commit 926560d

Michael Forney  ·  2013-09-11 22:56:39 +0000 UTC
parent d6e3d50
renderer: Use planes and wld for rendering
15 files changed,  +362, -384
+0, -4
 1@@ -24,10 +24,6 @@ PKG_CHECK_MODULES([wayland_server], [wayland-server])
 2 PKG_CHECK_MODULES([udev], [libudev])
 3 PKG_CHECK_MODULES([xkbcommon], [xkbcommon])
 4 PKG_CHECK_MODULES([drm], [libdrm])
 5-PKG_CHECK_MODULES([drm_intel], [libdrm_intel])
 6-PKG_CHECK_MODULES([intelbatch], [intelbatch])
 7-PKG_CHECK_MODULES([gbm], [gbm])
 8-PKG_CHECK_MODULES([egl], [egl])
 9 PKG_CHECK_MODULES([pixman], [pixman-1])
10 PKG_CHECK_MODULES([wld], [wld])
11 
+2, -4
 1@@ -1,7 +1,7 @@
 2 # swc: libswc/Makefile.am
 3 
 4 AM_CPPFLAGS = -I$(top_srcdir) -I$(PROTOCOL_DIR)
 5-AM_CFLAGS = $(pixman_CFLAGS) $(drm_CFLAGS) $(intelbatch_CFLAGS)
 6+AM_CFLAGS = $(drm_CFLAGS) $(pixman_CFLAGS) $(wld_CFLAGS)
 7 
 8 lib_LTLIBRARIES = libswc.la
 9 
10@@ -9,7 +9,6 @@ libswc_la_SOURCES = \
11     compositor.c compositor.h \
12     util.c util.h \
13     output.c output.h \
14-    buffer.c buffer.h \
15     plane.c plane.h \
16     surface.c surface.h \
17     compositor_surface.c compositor_surface.h \
18@@ -31,7 +30,6 @@ libswc_la_SOURCES = \
19     $(PROTOCOL_DIR)/wayland-drm-protocol.c
20 
21 libswc_la_LIBADD = $(wayland_server_LIBS) $(udev_LIBS) $(xkbcommon_LIBS) \
22-                   $(drm_LIBS) $(drm_intel_LIBS) $(gbm_LIBS) $(egl_LIBS) \
23-                   $(pixman_LIBS) $(intelbatch_LIBS) $(wld_LIBS) \
24+                   $(drm_LIBS) $(pixman_LIBS) $(wld_LIBS) \
25                    ../launch/liblaunch-protocol.la
26 
+0, -44
 1@@ -1,44 +0,0 @@
 2-#include "buffer.h"
 3-
 4-#include <stdio.h>
 5-#include <sys/mman.h>
 6-#include <libdrm/i915_drm.h>
 7-#include <xf86drm.h>
 8-#include <xf86drmMode.h>
 9-
10-bool swc_buffer_initialize(struct swc_buffer * buffer, struct swc_drm * drm,
11-                           uint32_t width, uint32_t height)
12-{
13-    uint32_t size;
14-    uint32_t tiling_mode = I915_TILING_X;
15-    unsigned long pitch;
16-
17-    buffer->width = width;
18-    buffer->height = height;
19-
20-    buffer->bo = drm_intel_bo_alloc_tiled(drm->bufmgr, "fb", width, height, 4,
21-                                          &tiling_mode, &pitch, 0);
22-
23-    buffer->pitch = pitch;
24-
25-    if (drmModeAddFB(drm->fd, width, height, 24, 32, buffer->pitch,
26-                     buffer->bo->handle, &buffer->id) != 0)
27-    {
28-        printf("could not create FB from buffer handle\n");
29-        goto error_buffer;
30-    }
31-
32-    return true;
33-
34-  error_buffer:
35-    drm_intel_bo_unreference(buffer->bo);
36-  error_base:
37-    return false;
38-}
39-
40-void swc_buffer_finish(struct swc_buffer * buffer, struct swc_drm * drm)
41-{
42-    drmModeRmFB(drm->fd, buffer->id);
43-    drm_intel_bo_unreference(buffer->bo);
44-}
45-
+0, -28
 1@@ -1,28 +0,0 @@
 2-#ifndef SWC_BUFFER_H
 3-#define SWC_BUFFER_H 1
 4-
 5-#include "drm.h"
 6-
 7-#include <stdbool.h>
 8-#include <pixman.h>
 9-
10-struct swc_buffer
11-{
12-    uint32_t id;
13-
14-    drm_intel_bo * bo;
15-
16-    uint32_t width, height, pitch;
17-};
18-
19-bool swc_buffer_initialize(struct swc_buffer * buffer, struct swc_drm * drm,
20-                           uint32_t width, uint32_t height);
21-
22-void swc_buffer_finish(struct swc_buffer * buffer, struct swc_drm * drm);
23-
24-void swc_buffer_ref_image(struct swc_buffer * buffer);
25-
26-void swc_buffer_unref_image(struct swc_buffer * buffer);
27-
28-#endif
29-
+151, -46
  1@@ -4,6 +4,7 @@
  2 #include <gbm.h>
  3 
  4 #include "compositor.h"
  5+#include "compositor_surface.h"
  6 #include "tty.h"
  7 #include "output.h"
  8 #include "surface.h"
  9@@ -14,41 +15,133 @@
 10 
 11 static const char default_seat[] = "seat0";
 12 
 13-struct repaint_operation
 14+static void calculate_damage(struct swc_compositor * compositor)
 15 {
 16-    struct swc_compositor * compositor;
 17-    struct swc_output * output;
 18-};
 19+    struct swc_surface * surface;
 20+    struct swc_compositor_surface_state * state;
 21+    pixman_region32_t opaque, surface_opaque;
 22+
 23+    pixman_region32_clear(&compositor->opaque);
 24+    pixman_region32_init(&surface_opaque);
 25+
 26+    /* Go through surfaces top-down to calculate clipping regions. */
 27+    wl_list_for_each(surface, &compositor->surfaces, link)
 28+    {
 29+        state = surface->class_state;
 30+
 31+        /* Clip the surface by the opaque region covering it. */
 32+        pixman_region32_copy(&state->clip, &compositor->opaque);
 33+
 34+        /* Translate the opaque region to global coordinates. */
 35+        pixman_region32_copy(&surface_opaque, &surface->state.opaque);
 36+        pixman_region32_translate(&surface_opaque, surface->geometry.x,
 37+                                  surface->geometry.y);
 38+
 39+        /* Add the surface's opaque region to the accumulated opaque
 40+         * region. */
 41+        pixman_region32_union(&compositor->opaque, &compositor->opaque,
 42+                              &surface_opaque);
 43+
 44+        if (pixman_region32_not_empty(&surface->state.damage))
 45+        {
 46+            swc_renderer_flush(&compositor->renderer, surface);
 47+
 48+            /* Translate surface damage to global coordinates. */
 49+            pixman_region32_translate(&surface->state.damage,
 50+                                      surface->geometry.x,
 51+                                      surface->geometry.y);
 52+
 53+            /* Add the surface damage to the compositor damage. */
 54+            pixman_region32_union(&compositor->damage, &compositor->damage,
 55+                                  &surface->state.damage);
 56+            pixman_region32_clear(&surface->state.damage);
 57+        }
 58 
 59-static void repaint_output(void * data)
 60+        if (state->border.damaged)
 61+        {
 62+            pixman_region32_t border_region, surface_region;
 63+
 64+            pixman_region32_init_with_extents(&border_region, &state->extents);
 65+            pixman_region32_init_rect
 66+                (&surface_region, surface->geometry.x, surface->geometry.y,
 67+                 surface->geometry.width, surface->geometry.height);
 68+
 69+            pixman_region32_subtract(&border_region, &border_region,
 70+                                     &surface_region);
 71+
 72+            pixman_region32_union(&compositor->damage, &compositor->damage,
 73+                                  &border_region);
 74+
 75+            pixman_region32_fini(&border_region);
 76+            pixman_region32_fini(&surface_region);
 77+
 78+            state->border.damaged = false;
 79+        }
 80+    }
 81+
 82+    pixman_region32_fini(&surface_opaque);
 83+}
 84+
 85+static void repaint_output(struct swc_compositor * compositor,
 86+                           struct swc_output * output)
 87 {
 88-    struct repaint_operation * operation = data;
 89-    struct swc_compositor * compositor = operation->compositor;
 90+    pixman_region32_t damage, previous_damage, base_damage;
 91+
 92+    pixman_region32_init(&damage);
 93+    pixman_region32_init(&previous_damage);
 94+    pixman_region32_init(&base_damage);
 95+
 96+    pixman_region32_intersect_rect
 97+        (&damage, &compositor->damage, output->geometry.x, output->geometry.y,
 98+         output->geometry.width, output->geometry.height);
 99+
100+    /* We must save the damage from the previous frame because the back buffer
101+     * is also damaged in this region. */
102+    pixman_region32_copy(&previous_damage, &output->previous_damage);
103+    pixman_region32_copy(&output->previous_damage, &damage);
104+
105+    /* The total damage is composed of the damage from the new frame, and the
106+     * damage from the last frame. */
107+    pixman_region32_union(&damage, &damage, &previous_damage);
108 
109-    swc_renderer_repaint_output(&compositor->renderer, operation->output,
110-                                &compositor->surfaces);
111+    pixman_region32_subtract(&base_damage, &damage, &compositor->opaque);
112 
113-    swc_output_switch_buffer(operation->output);
114+    swc_renderer_set_target(&compositor->renderer, &output->framebuffer_plane);
115+    swc_renderer_repaint(&compositor->renderer, &damage, &base_damage,
116+                         &compositor->surfaces);
117 
118-    free(operation);
119+    pixman_region32_subtract(&compositor->damage, &compositor->damage, &damage);
120+
121+    pixman_region32_fini(&damage);
122+    pixman_region32_fini(&previous_damage);
123+    pixman_region32_fini(&base_damage);
124+
125+    if (!swc_plane_flip(&output->framebuffer_plane))
126+        fprintf(stderr, "Plane flip failed\n");
127 }
128 
129-static void schedule_repaint_for_output(struct swc_compositor * compositor,
130-                                        struct swc_output * output)
131+static void perform_update(void * data)
132 {
133-    struct wl_event_loop * event_loop;
134-    struct repaint_operation * operation;
135+    struct swc_compositor * compositor = data;
136+    struct swc_output * output;
137+    uint32_t updates = compositor->scheduled_updates
138+                       & ~compositor->pending_flips;
139 
140-    if (output->repaint_scheduled)
141-        return;
142+    if (updates)
143+    {
144+        printf("performing update\n");
145+        calculate_damage(compositor);
146+
147+        wl_list_for_each(output, &compositor->outputs, link)
148+        {
149+            if (updates & SWC_OUTPUT_MASK(output))
150+                repaint_output(compositor, output);
151+        }
152 
153-    operation = malloc(sizeof *operation);
154-    operation->compositor = compositor;
155-    operation->output = output;
156+        compositor->pending_flips |= updates;
157+        compositor->scheduled_updates &= ~updates;
158+    }
159 
160-    event_loop = wl_display_get_event_loop(compositor->display);
161-    wl_event_loop_add_idle(event_loop, &repaint_output, operation);
162-    output->repaint_scheduled = true;
163 }
164 
165 static bool handle_key(struct swc_keyboard * keyboard, uint32_t time,
166@@ -186,21 +279,22 @@ static void handle_drm_event(struct wl_listener * listener, void * data)
167             struct timeval timeval;
168             uint32_t time;
169 
170-            output->repaint_scheduled = false;
171-            output->front_buffer ^= 1;
172-
173             gettimeofday(&timeval, NULL);
174             time = timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
175 
176-            /* Handle all frame callbacks for surfaces on this output. */
177-            wl_list_for_each(surface, &compositor->surfaces, link)
178-            {
179-                swc_surface_send_frame_callbacks(surface, time);
180+            compositor->pending_flips &= ~SWC_OUTPUT_MASK(output);
181 
182-                if (surface->state.buffer)
183-                    wl_buffer_send_release(&surface->state.buffer->resource);
184+            if (compositor->pending_flips == 0)
185+            {
186+                wl_list_for_each(surface, &compositor->surfaces, link)
187+                    swc_surface_send_frame_callbacks(surface, time);
188             }
189 
190+            /* If we had scheduled updates that couldn't run because we were
191+             * waiting on a page flip, run them now. */
192+            if (compositor->scheduled_updates)
193+                perform_update(compositor);
194+
195             break;
196         }
197     }
198@@ -295,6 +389,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
199     compositor->display = display;
200     compositor->tty_listener.notify = &handle_tty_event;
201     compositor->drm_listener.notify = &handle_drm_event;
202+    compositor->scheduled_updates = 0;
203+    compositor->pending_flips = 0;
204     compositor->compositor_class.interface
205         = &swc_compositor_class_implementation;
206 
207@@ -338,19 +434,10 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
208     wl_signal_add(&compositor->drm.event_signal, &compositor->drm_listener);
209     swc_drm_add_event_sources(&compositor->drm, event_loop);
210 
211-    compositor->gbm = gbm_create_device(compositor->drm.fd);
212-
213-    if (!compositor->gbm)
214-    {
215-        printf("could not create gbm device\n");
216-        goto error_drm;
217-    }
218-
219-    if (!swc_renderer_initialize(&compositor->renderer, &compositor->drm,
220-                                 compositor->gbm))
221+    if (!swc_renderer_initialize(&compositor->renderer, &compositor->drm))
222     {
223         printf("could not initialize renderer\n");
224-        goto error_gbm;
225+        goto error_drm;
226     }
227 
228     outputs = swc_drm_create_outputs(&compositor->drm);
229@@ -367,6 +454,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
230         goto error_renderer;
231     }
232 
233+    pixman_region32_init(&compositor->damage);
234+    pixman_region32_init(&compositor->opaque);
235     wl_list_init(&compositor->surfaces);
236     wl_array_init(&compositor->key_bindings);
237     wl_signal_init(&compositor->destroy_signal);
238@@ -387,8 +476,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
239 
240   error_renderer:
241     swc_renderer_finalize(&compositor->renderer);
242-  error_gbm:
243-    gbm_device_destroy(compositor->gbm);
244   error_drm:
245     swc_drm_finish(&compositor->drm);
246   error_seat:
247@@ -415,7 +502,6 @@ void swc_compositor_finish(struct swc_compositor * compositor)
248         free(output);
249     }
250 
251-    gbm_device_destroy(compositor->gbm);
252     swc_drm_finish(&compositor->drm);
253     swc_seat_finish(&compositor->seat);
254     swc_tty_finish(&compositor->tty);
255@@ -453,3 +539,22 @@ void swc_compositor_add_key_binding(struct swc_compositor * compositor,
256     binding->data = data;
257 }
258 
259+void swc_compositor_schedule_update(struct swc_compositor * compositor,
260+                                    struct swc_output * output)
261+{
262+    bool update_scheduled = compositor->scheduled_updates != 0;
263+
264+    if (compositor->scheduled_updates & SWC_OUTPUT_MASK(output))
265+        return;
266+
267+    compositor->scheduled_updates |= SWC_OUTPUT_MASK(output);
268+
269+    if (!update_scheduled)
270+    {
271+        struct wl_event_loop * event_loop;
272+
273+        event_loop = wl_display_get_event_loop(compositor->display);
274+        wl_event_loop_add_idle(event_loop, &perform_update, compositor);
275+    }
276+}
277+
+0, -1
1@@ -14,7 +14,6 @@ struct swc_compositor
2     struct wl_display * display;
3 
4     struct udev * udev;
5-    struct gbm_device * gbm;
6 
7     struct swc_tty tty;
8     struct swc_seat seat;
+1, -2
 1@@ -187,8 +187,7 @@ void attach(struct swc_surface * surface, struct wl_resource * resource)
 2     struct swc_compositor * compositor = swc_container_of
 3         (surface->class, typeof(*compositor), compositor_class);
 4 
 5-    swc_renderer_attach(&compositor->renderer, surface,
 6-                        wl_resource_get_user_data(resource));
 7+    swc_renderer_attach(&compositor->renderer, surface, resource);
 8 }
 9 
10 void update(struct swc_surface * surface)
+0, -1
1@@ -257,7 +257,6 @@ static void handle_page_flip(int fd, unsigned int sequence, unsigned int sec,
2     struct swc_output * output = data;
3 
4     printf("page flip\n");
5-    output->front_buffer ^= 1;
6 
7     /* XXX: It doesn't make sense for multiple things to be listening for page
8      *      flips (or does it?). Maybe this should be a callback instead? */
+0, -3
 1@@ -4,9 +4,7 @@
 2 #include <stdbool.h>
 3 #include <stdint.h>
 4 #include <libudev.h>
 5-#include <gbm.h>
 6 #include <wayland-server.h>
 7-#include <libdrm/intel_bufmgr.h>
 8 
 9 struct wld_drm_context * context;
10 
11@@ -21,7 +19,6 @@ struct swc_drm
12     uint32_t id;
13     char * path;
14 
15-    drm_intel_bufmgr * bufmgr;
16     struct wld_drm_context * context;
17 
18     uint32_t taken_output_ids;
+6, -42
 1@@ -57,14 +57,12 @@ bool swc_output_initialize(struct swc_output * output, struct swc_drm * drm,
 2     printf("initializing output with id: %u\n", id);
 3 
 4     output->id = id;
 5-    output->repaint_scheduled = false;
 6-    output->front_buffer = 0;
 7-
 8     output->physical_width = connector->mmWidth;
 9     output->physical_height = connector->mmHeight;
10 
11     wl_list_init(&output->resources);
12     wl_array_init(&output->modes);
13+    pixman_region32_init(&output->previous_damage);
14 
15     output->crtc_id = crtc_id;
16     output->connector_id = connector->connector_id;
17@@ -93,36 +91,18 @@ bool swc_output_initialize(struct swc_output * output, struct swc_drm * drm,
18     output->geometry.width = output->current_mode->width;
19     output->geometry.height = output->current_mode->height;
20 
21-    /* Create output buffers */
22-    if (!swc_buffer_initialize(&output->buffers[0], drm, output->geometry.width,
23-                               output->geometry.height))
24-    {
25-        printf("could not initialize buffer 0 for output\n");
26-        goto error_base;
27-    }
28-
29-    if (!swc_buffer_initialize(&output->buffers[1], drm, output->geometry.width,
30-                               output->geometry.height))
31-    {
32-        printf("could not initialize buffer 1 for output\n");
33-        goto error_buffer0;
34-    }
35-
36     output->original_state.crtc = current_crtc;
37 
38-    if (drmModeSetCrtc(drm->fd, output->crtc_id, output->buffers[0].id, 0, 0,
39-                       &output->connector_id, 1, &output->current_mode->info) != 0)
40+    /* Create output planes */
41+    if (!swc_plane_initialize(&output->framebuffer_plane,
42+                              &swc_framebuffer_plane, output))
43     {
44-        printf("could not set crtc for output\n");
45-        goto error_buffer1;
46+        printf("failed to initialize framebuffer plane\n");
47+        goto error_base;
48     }
49 
50     return true;
51 
52-  error_buffer1:
53-    swc_buffer_finish(&output->buffers[1], drm);
54-  error_buffer0:
55-    swc_buffer_finish(&output->buffers[0], drm);
56   error_base:
57     return false;
58 }
59@@ -139,9 +119,6 @@ void swc_output_finish(struct swc_output * output)
60     drmModeSetCrtc(output->drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
61                    crtc->y, &output->connector_id, 1, &crtc->mode);
62     drmModeFreeCrtc(crtc);
63-
64-    swc_buffer_finish(&output->buffers[0], output->drm);
65-    swc_buffer_finish(&output->buffers[1], output->drm);
66 }
67 
68 void swc_output_add_globals(struct swc_output * output,
69@@ -150,16 +127,3 @@ void swc_output_add_globals(struct swc_output * output,
70     wl_global_create(display, &wl_output_interface, 1, output, &bind_output);
71 }
72 
73-void swc_output_switch_buffer(struct swc_output * output)
74-{
75-    printf("queueing pageflip\n");
76-
77-    /* Queue a page flip */
78-    if (drmModePageFlip(output->drm->fd, output->crtc_id,
79-                        swc_output_get_back_buffer(output)->id,
80-                        DRM_MODE_PAGE_FLIP_EVENT, output) != 0)
81-    {
82-        printf("could not queue pageflip\n");
83-    }
84-}
85-
+6, -20
 1@@ -1,7 +1,7 @@
 2 #ifndef SWC_OUTPUT_H
 3 #define SWC_OUTPUT_H 1
 4 
 5-#include "buffer.h"
 6+#include "plane.h"
 7 
 8 #include <stdint.h>
 9 #include <pixman.h>
10@@ -26,9 +26,11 @@ struct swc_output
11     struct wl_array modes;
12     struct swc_mode * current_mode, * preferred_mode;
13 
14-    /* Use double buffering */
15-    struct swc_buffer buffers[2];
16-    uint8_t front_buffer;
17+    /* Output planes. */
18+    struct swc_plane framebuffer_plane;
19+    struct swc_plane cursor_plane;
20+
21+    pixman_region32_t previous_damage;
22 
23     /* The CRTC and connector we are using to drive this output */
24     uint32_t crtc_id;
25@@ -39,8 +41,6 @@ struct swc_output
26         drmModeCrtc * crtc;
27     } original_state;
28 
29-    bool repaint_scheduled;
30-
31     struct wl_list resources;
32     struct wl_list link;
33 };
34@@ -54,19 +54,5 @@ void swc_output_finish(struct swc_output * output);
35 void swc_output_add_globals(struct swc_output * output,
36                             struct wl_display * display);
37 
38-void swc_output_switch_buffer(struct swc_output * output);
39-
40-static inline struct swc_buffer * swc_output_get_front_buffer
41-    (struct swc_output * output)
42-{
43-    return &output->buffers[output->front_buffer];
44-}
45-
46-static inline struct swc_buffer * swc_output_get_back_buffer
47-    (struct swc_output * output)
48-{
49-    return &output->buffers[!output->front_buffer];
50-}
51-
52 #endif
53 
+145, -159
  1@@ -1,29 +1,18 @@
  2 #include "renderer.h"
  3 #include "compositor_surface.h"
  4-#include "util.h"
  5+#include "drm_buffer.h"
  6 
  7+#include <assert.h>
  8 #include <stdio.h>
  9-#include <GLES2/gl2.h>
 10-#include <libdrm/intel_bufmgr.h>
 11-#include <libdrm/drm.h>
 12-#include <intelbatch/blt.h>
 13-#include <intelbatch/mi.h>
 14-#include <xf86drm.h>
 15+#include <stdlib.h>
 16+#include <wld/wld.h>
 17+#include <wld/drm.h>
 18 
 19 struct buffer_state
 20 {
 21-    union
 22-    {
 23-        struct
 24-        {
 25-            pixman_image_t * image;
 26-        } shm;
 27-        struct
 28-        {
 29-            drm_intel_bo * bo;
 30-            uint32_t width, height, pitch;
 31-        } drm;
 32-    };
 33+    struct wld_drawable * drawable;
 34+    /* Only used for SHM buffers */
 35+    pixman_image_t * dst, * src;
 36     struct wl_listener destroy_listener;
 37 };
 38 
 39@@ -40,38 +29,17 @@ static inline uint32_t pixman_format(uint32_t format)
 40     return 0;
 41 }
 42 
 43-static inline void switch_context(struct swc_renderer * renderer,
 44-                                  uint32_t context, struct swc_buffer * buffer)
 45+static inline uint32_t wld_format(uint32_t format)
 46 {
 47-    if (renderer->context != context)
 48+    switch (format)
 49     {
 50-        /* Leave old context */
 51-        switch (renderer->context)
 52-        {
 53-            case SWC_RENDERER_CONTEXT_NONE:
 54-                break;
 55-            case SWC_RENDERER_CONTEXT_BATCH:
 56-                intel_batch_flush(&renderer->batch);
 57-                break;
 58-            case SWC_RENDERER_CONTEXT_SHM:
 59-                drm_intel_gem_bo_unmap_gtt(buffer->bo);
 60-                break;
 61-        }
 62-
 63-        /* Enter new context */
 64-        switch (context)
 65-        {
 66-            case SWC_RENDERER_CONTEXT_NONE:
 67-                break;
 68-            case SWC_RENDERER_CONTEXT_BATCH:
 69-                break;
 70-            case SWC_RENDERER_CONTEXT_SHM:
 71-                drm_intel_gem_bo_map_gtt(buffer->bo);
 72-                break;
 73-        }
 74-
 75-        renderer->context = context;
 76+        case WL_SHM_FORMAT_XRGB8888:
 77+            return WLD_FORMAT_XRGB8888;
 78+        case WL_SHM_FORMAT_ARGB8888:
 79+            return WLD_FORMAT_ARGB8888;
 80     }
 81+
 82+    return 0;
 83 }
 84 
 85 static void handle_buffer_destroy(struct wl_listener * listener, void * data)
 86@@ -79,6 +47,11 @@ static void handle_buffer_destroy(struct wl_listener * listener, void * data)
 87     struct buffer_state * state
 88         = swc_container_of(listener, typeof(*state), destroy_listener);
 89 
 90+    wld_destroy_drawable(state->drawable);
 91+    if (state->dst)
 92+        pixman_image_unref(state->dst);
 93+    if (state->src)
 94+        pixman_image_unref(state->src);
 95     free(state);
 96 }
 97 
 98@@ -92,176 +65,189 @@ static inline struct buffer_state * buffer_state(struct wl_resource * resource)
 99                     : NULL;
100 }
101 
102-static void repaint_surface_for_output(struct swc_renderer * renderer,
103-                                       struct swc_surface * surface,
104-                                       struct swc_output * output)
105+static void repaint_surface(struct swc_renderer * renderer,
106+                            struct swc_surface * surface,
107+                            pixman_region32_t * damage)
108 {
109-    struct swc_buffer * back_buffer = swc_output_get_back_buffer(output);
110+    struct swc_render_target * target = &renderer->target;
111+    pixman_region32_t surface_damage;
112+    pixman_region32_t border_damage;
113+    pixman_region32_t surface_region;
114     struct buffer_state * state;
115     struct swc_compositor_surface_state * surface_state = surface->class_state;
116 
117     if (!surface->state.buffer)
118         return;
119 
120-    state = buffer_state(&surface->state.buffer->resource);
121-
122-    if (wl_buffer_is_shm(surface->state.buffer))
123-    {
124-        pixman_image_t * buffer_image;
125+    state = buffer_state(surface->state.buffer);
126+    assert(state);
127 
128-        switch_context(renderer, SWC_RENDERER_CONTEXT_SHM, back_buffer);
129+    pixman_region32_init_with_extents(&surface_damage, &surface_state->extents);
130+    pixman_region32_init(&border_damage);
131+    pixman_region32_init_rect
132+        (&surface_region, surface->geometry.x, surface->geometry.y,
133+         surface->geometry.width, surface->geometry.height);
134 
135-        printf("repainting shm surface\n");
136+    pixman_region32_intersect(&surface_damage, damage, &surface_damage);
137+    pixman_region32_subtract(&surface_damage, &surface_damage,
138+                             &surface_state->clip);
139+    pixman_region32_subtract(&border_damage, &surface_damage, &surface_region);
140+    pixman_region32_intersect(&surface_damage, &surface_damage,
141+                              &surface_region);
142 
143-        buffer_image = pixman_image_create_bits_no_clear
144-            (PIXMAN_x8r8g8b8, back_buffer->width, back_buffer->height,
145-             back_buffer->bo->virtual, back_buffer->pitch);
146+    pixman_region32_fini(&surface_region);
147 
148-        pixman_image_composite32(PIXMAN_OP_SRC,
149-                                 state->shm.image, NULL,
150-                                 buffer_image, 0, 0, 0, 0, 0, 0,
151-                                 surface->geometry.width,
152-                                 surface->geometry.height);
153-    }
154-    else
155+    if (pixman_region32_not_empty(&surface_damage))
156     {
157-        switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
158-
159-        printf("repainting drm surface\n");
160-
161-        drm_intel_bo * src = state->drm.bo;
162-        uint32_t src_pitch = state->drm.pitch;
163-
164-        xy_src_copy_blt(&renderer->batch, src, src_pitch, 0, 0,
165-                        back_buffer->bo, back_buffer->pitch,
166-                        surface->geometry.x + surface_state->border.width,
167-                        surface->geometry.y + surface_state->border.width,
168-                        surface->geometry.width, surface->geometry.height);
169+        printf("\tdrm surface %u { x: %d, y: %d, w: %u, h: %u }\n",
170+               wl_resource_get_id(surface->resource),
171+               surface->geometry.x, surface->geometry.y,
172+               surface->geometry.width, surface->geometry.height);
173+
174+        pixman_region32_translate(&surface_damage,
175+                                  -surface->geometry.x, -surface->geometry.y);
176+        wld_copy_region(state->drawable, target->drawable, &surface_damage,
177+                        surface->geometry.x - target->geometry.x,
178+                        surface->geometry.y - target->geometry.y);
179     }
180 
181+    pixman_region32_fini(&surface_damage);
182+
183     /* Draw border */
184+    if (pixman_region32_not_empty(&border_damage))
185     {
186-        switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
187-
188-        /* Top */
189-        xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
190-                     surface->geometry.x, surface->geometry.y,
191-                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
192-                     surface->geometry.y + surface_state->border.width,
193-                     surface_state->border.color);
194-        /* Bottom */
195-        xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
196-                     surface->geometry.x,
197-                     surface->geometry.y + surface_state->border.width + surface->geometry.height,
198-                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
199-                     surface->geometry.y + surface->geometry.height + 2 * surface_state->border.width,
200-                     surface_state->border.color);
201-        /* Left */
202-        xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
203-                     surface->geometry.x, surface->geometry.y + surface_state->border.width,
204-                     surface->geometry.x + surface_state->border.width,
205-                     surface->geometry.y + + surface_state->border.width + surface->geometry.height,
206-                     surface_state->border.color);
207-        /* Right */
208-        xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
209-                     surface->geometry.x + surface_state->border.width + surface->geometry.width,
210-                     surface->geometry.y + surface_state->border.width,
211-                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
212-                     surface->geometry.y + surface_state->border.width + surface->geometry.height,
213-                     surface_state->border.color);
214+        printf("\tborder\n");
215 
216+        pixman_region32_translate(&border_damage,
217+                                  -target->geometry.x, -target->geometry.y);
218+        wld_fill_region(target->drawable, surface_state->border.color,
219+                        &border_damage);
220     }
221+
222+    pixman_region32_fini(&border_damage);
223 }
224 
225 bool swc_renderer_initialize(struct swc_renderer * renderer,
226-                             struct swc_drm * drm,
227-                             struct gbm_device * gbm)
228+                             struct swc_drm * drm)
229 {
230     renderer->drm = drm;
231-    renderer->gbm = gbm;
232-
233-    intel_batch_initialize(&renderer->batch, drm->bufmgr);
234 
235     return true;
236 }
237 
238 void swc_renderer_finalize(struct swc_renderer * renderer)
239 {
240-    intel_batch_finalize(&renderer->batch);
241 }
242 
243-void swc_renderer_repaint_output(struct swc_renderer * renderer,
244-                                 struct swc_output * output,
245-                                 struct wl_list * surfaces)
246+void swc_renderer_set_target(struct swc_renderer * renderer,
247+                             struct swc_plane * plane)
248 {
249+    struct wld_drawable * drawable = swc_plane_get_buffer(plane);
250+
251+    renderer->target.drawable = drawable;
252+    renderer->target.geometry.x = plane->output->geometry.x + plane->x;
253+    renderer->target.geometry.y = plane->output->geometry.y + plane->y;
254+    renderer->target.geometry.width = drawable->width;
255+    renderer->target.geometry.height = drawable->height;
256+}
257+
258+void swc_renderer_repaint(struct swc_renderer * renderer,
259+                          pixman_region32_t * damage,
260+                          pixman_region32_t * base_damage,
261+                          struct wl_list * surfaces)
262+{
263+    struct swc_render_target * target = &renderer->target;
264     struct swc_surface * surface;
265-    struct swc_buffer * back_buffer;
266 
267-    back_buffer = swc_output_get_back_buffer(output);
268+    printf("rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
269+           target->geometry.x, target->geometry.y,
270+           target->geometry.width, target->geometry.height);
271 
272-    switch_context(renderer, SWC_RENDERER_CONTEXT_BATCH, back_buffer);
273+    /* Paint base damage black. */
274+    if (pixman_region32_not_empty(base_damage))
275+    {
276+        pixman_region32_translate(base_damage,
277+                                  -target->geometry.x, -target->geometry.y);
278+        wld_fill_region(target->drawable, 0xff000000, base_damage);
279+    }
280 
281-    wl_list_for_each(surface, surfaces, link)
282+    wl_list_for_each_reverse(surface, surfaces, link)
283     {
284-        if (surface->outputs & (1 << output->id))
285-            repaint_surface_for_output(renderer, surface, output);
286+        if (swc_rectangle_overlap(&target->geometry, &surface->geometry))
287+            repaint_surface(renderer, surface, damage);
288     }
289 
290-    switch_context(renderer, SWC_RENDERER_CONTEXT_NONE, back_buffer);
291+    wld_flush(target->drawable);
292 }
293 
294 void swc_renderer_attach(struct swc_renderer * renderer,
295                          struct swc_surface * surface,
296-                         struct wl_buffer * buffer)
297+                         struct wl_resource * resource)
298 {
299     struct buffer_state * state;
300-    struct gbm_bo * bo;
301+    struct wl_shm_buffer * shm_buffer;
302+    struct swc_drm_buffer * drm_buffer;
303 
304-    if (!buffer)
305+    if (!resource)
306         return;
307 
308     /* Check if we have already seen this buffer. */
309-    if ((state = buffer_state(&buffer->resource)))
310+    if ((state = buffer_state(resource)))
311         return;
312 
313     if (!(state = malloc(sizeof *state)))
314         return;
315 
316-    /* SHM buffer */
317-    if (wl_buffer_is_shm(buffer))
318+    if ((shm_buffer = wl_shm_buffer_get(resource)))
319     {
320-        struct swc_output * output;
321-        uint32_t wayland_format = wl_shm_buffer_get_format(buffer);
322-
323-        state->shm.image
324-            = pixman_image_create_bits(pixman_format(wayland_format),
325-                                       wl_shm_buffer_get_width(buffer),
326-                                       wl_shm_buffer_get_height(buffer),
327-                                       wl_shm_buffer_get_data(buffer),
328-                                       wl_shm_buffer_get_stride(buffer));
329+        uint32_t width = wl_shm_buffer_get_width(shm_buffer),
330+                 height = wl_shm_buffer_get_height(shm_buffer),
331+                 format = wl_shm_buffer_get_format(shm_buffer),
332+                 pitch = wl_shm_buffer_get_stride(shm_buffer);
333+        void * data = wl_shm_buffer_get_data(shm_buffer);
334+
335+        state->drawable = wld_drm_create_drawable(renderer->drm->context,
336+                                                  width, height,
337+                                                  wld_format(format));
338+        state->src = pixman_image_create_bits_no_clear(pixman_format(format),
339+                                                       width, height,
340+                                                       data, pitch);
341+        state->dst = wld_map(state->drawable);
342     }
343-    /* DRM buffer */
344-    else if ((bo = gbm_bo_import(renderer->gbm, GBM_BO_IMPORT_WL_BUFFER, buffer,
345-                                 GBM_BO_USE_RENDERING)))
346+    else if ((drm_buffer = swc_drm_buffer_get(resource)))
347     {
348-        int handle = gbm_bo_get_handle(bo).s32;
349-        struct drm_gem_flink flink = { .handle = handle };
350-
351-        if (drmIoctl(renderer->drm->fd, DRM_IOCTL_GEM_FLINK, &flink) != 0)
352-        {
353-            printf("could not flink handle\n");
354+        if (!(state = malloc(sizeof *state)))
355             return;
356-        }
357-
358-        state->drm.bo
359-            = drm_intel_bo_gem_create_from_name(renderer->drm->bufmgr,
360-                                                "surface", flink.name);
361-        state->drm.pitch = gbm_bo_get_stride(bo);
362-        state->drm.width = gbm_bo_get_width(bo);
363-        state->drm.height = gbm_bo_get_height(bo);
364 
365-        printf("pitch: %u, width: %u, height: %u\n", state->drm.pitch,
366-            state->drm.width, state->drm.height);
367+        state->drawable = drm_buffer->drawable;
368+        state->src = NULL;
369+        state->dst = NULL;
370+    }
371+    else
372+    {
373+        fprintf(stderr, "Unsupported buffer type\n");
374+        return;
375     }
376+
377+    state->destroy_listener.notify = &handle_buffer_destroy;
378+    wl_resource_add_destroy_listener(resource, &state->destroy_listener);
379+}
380+
381+void swc_renderer_flush(struct swc_renderer * renderer,
382+                        struct swc_surface * surface)
383+{
384+    struct wl_shm_buffer * buffer;
385+    struct buffer_state * state;
386+
387+    if (!(buffer = wl_shm_buffer_get(surface->state.buffer)))
388+        return;
389+
390+    state = buffer_state(surface->state.buffer);
391+    assert(state);
392+
393+    pixman_image_set_clip_region32(state->src, &surface->state.damage);
394+    pixman_image_composite32(PIXMAN_OP_SRC, state->src, NULL, state->dst,
395+                             0, 0, 0, 0, 0, 0,
396+                             state->drawable->width, state->drawable->height);
397 }
398 
+16, -14
 1@@ -5,35 +5,37 @@
 2 #include "surface.h"
 3 #include "drm.h"
 4 
 5-#include <intelbatch/batch.h>
 6-
 7-enum swc_renderer_context
 8+struct swc_render_target
 9 {
10-    SWC_RENDERER_CONTEXT_NONE,
11-    SWC_RENDERER_CONTEXT_SHM,
12-    SWC_RENDERER_CONTEXT_BATCH
13+    struct wld_drawable * drawable;
14+    pixman_rectangle32_t geometry;
15 };
16 
17 struct swc_renderer
18 {
19     struct swc_drm * drm;
20-    struct gbm_device * gbm;
21-    enum swc_renderer_context context;
22-    struct intel_batch batch;
23+    struct swc_render_target target;
24 };
25 
26 bool swc_renderer_initialize(struct swc_renderer * renderer,
27-                             struct swc_drm * drm, struct gbm_device * gbm);
28+                             struct swc_drm * drm);
29 
30 void swc_renderer_finalize(struct swc_renderer * renderer);
31 
32-void swc_renderer_repaint_output(struct swc_renderer * renderer,
33-                                 struct swc_output * output,
34-                                 struct wl_list * surfaces);
35+void swc_renderer_set_target(struct swc_renderer * renderer,
36+                             struct swc_plane * plane);
37+
38+void swc_renderer_repaint(struct swc_renderer * renderer,
39+                          pixman_region32_t * damage,
40+                          pixman_region32_t * base_damage,
41+                          struct wl_list * surfaces);
42 
43 void swc_renderer_attach(struct swc_renderer * renderer,
44                          struct swc_surface * surface,
45-                         struct wl_buffer * buffer);
46+                         struct wl_resource * resource);
47+
48+void swc_renderer_flush(struct swc_renderer * renderer,
49+                        struct swc_surface * surface);
50 
51 #endif
52 
+34, -15
  1@@ -25,9 +25,11 @@
  2 #include "event.h"
  3 #include "region.h"
  4 #include "util.h"
  5+#include "drm_buffer.h"
  6 
  7 #include <stdlib.h>
  8 #include <stdio.h>
  9+#include <wld/wld.h>
 10 
 11 static pixman_box32_t infinite_extents = {
 12     .x1 = INT32_MIN, .y1 = INT32_MIN,
 13@@ -83,7 +85,7 @@ static void state_finish(struct swc_surface_state * state)
 14  * @return: Whether or not the buffer was changed.
 15  */
 16 static bool state_set_buffer(struct swc_surface_state * state,
 17-                             struct wl_buffer * buffer)
 18+                             struct wl_resource * buffer)
 19 {
 20     if (buffer == state->buffer)
 21         return false;
 22@@ -98,7 +100,7 @@ static bool state_set_buffer(struct swc_surface_state * state,
 23     {
 24         /* Need to watch the new buffer for destruction so we can remove it
 25          * from state. */
 26-        wl_resource_add_destroy_listener(&buffer->resource,
 27+        wl_resource_add_destroy_listener(buffer,
 28                                          &state->buffer_destroy_listener);
 29     }
 30 
 31@@ -107,6 +109,17 @@ static bool state_set_buffer(struct swc_surface_state * state,
 32     return true;
 33 }
 34 
 35+static void set_size(struct swc_surface * surface,
 36+                     uint32_t width, uint32_t height)
 37+{
 38+    /* Check if the surface was resized. */
 39+    if (width != surface->geometry.width || height != surface->geometry.height)
 40+    {
 41+        surface->geometry.width = width;
 42+        surface->geometry.height = height;
 43+    }
 44+}
 45+
 46 static void destroy(struct wl_client * client, struct wl_resource * resource)
 47 {
 48     wl_resource_destroy(resource);
 49@@ -116,14 +129,8 @@ static void attach(struct wl_client * client, struct wl_resource * resource,
 50                    struct wl_resource * buffer_resource, int32_t x, int32_t y)
 51 {
 52     struct swc_surface * surface = wl_resource_get_user_data(resource);
 53-    struct wl_buffer * buffer
 54-        = buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL;
 55-
 56-    state_set_buffer(&surface->pending.state, buffer);
 57 
 58-    /* Adjust geometry of the surface to match the buffer. */
 59-    surface->geometry.width = buffer ? buffer->width : 0;
 60-    surface->geometry.height = buffer ? buffer->height : 0;
 61+    state_set_buffer(&surface->pending.state, buffer_resource);
 62 
 63     surface->pending.x = x;
 64     surface->pending.y = y;
 65@@ -199,16 +206,28 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
 66     /* Attach */
 67     if (surface->state.buffer != surface->pending.state.buffer)
 68     {
 69-        if (surface->state.buffer)
 70+        struct wl_shm_buffer * shm_buffer;
 71+        struct swc_drm_buffer * drm_buffer;
 72+
 73+        if (surface->state.buffer
 74+            && surface->state.buffer != surface->pending.state.buffer)
 75         {
 76-            /* Release the old buffer, it's no longer needed. */
 77-            wl_buffer_send_release(&surface->state.buffer->resource);
 78+            wl_buffer_send_release(surface->state.buffer);
 79         }
 80 
 81         state_set_buffer(&surface->state, surface->pending.state.buffer);
 82 
 83-        surface->class->interface->attach(surface,
 84-                                          &surface->state.buffer->resource);
 85+        /* Determine size of buffer. */
 86+        if ((shm_buffer = wl_shm_buffer_get(surface->state.buffer)))
 87+        {
 88+            set_size(surface, wl_shm_buffer_get_width(shm_buffer),
 89+                     wl_shm_buffer_get_height(shm_buffer));
 90+        }
 91+        else if ((drm_buffer = swc_drm_buffer_get(surface->state.buffer)))
 92+        {
 93+            set_size(surface, drm_buffer->drawable->width,
 94+                     drm_buffer->drawable->height);
 95+        }
 96     }
 97 
 98     /* Damage */
 99@@ -369,7 +388,7 @@ void swc_surface_set_class(struct swc_surface * surface,
100         }
101 
102 
103-        surface->class->interface->attach(surface, &surface->state.buffer->resource);
104+        surface->class->interface->attach(surface, surface->state.buffer);
105         surface->class->interface->update(surface);
106     }
107 }
+1, -1
1@@ -32,7 +32,7 @@ struct swc_surface;
2 
3 struct swc_surface_state
4 {
5-    struct wl_buffer * buffer;
6+    struct wl_resource * buffer;
7 
8     /* The region that needs to be repainted */
9     pixman_region32_t damage;