commit 182f6d3

Michael Forney  ·  2014-01-15 22:27:38 +0000 UTC
parent a0520fc
Implement buffered surfaces
4 files changed,  +242, -1
+1, -0
1@@ -20,6 +20,7 @@ WLD_REQUIRES = fontconfig pixman-1
2 WLD_REQUIRES_PRIVATE = freetype2
3 WLD_SOURCES =           \
4     buffer.c            \
5+    buffered_surface.c  \
6     color.c             \
7     context.c           \
8     font.c              \
+222, -0
  1@@ -0,0 +1,222 @@
  2+/* wld: buffered_surface.c
  3+ *
  4+ * Copyright (c) 2013, 2014 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25+#include "wld-private.h"
 26+
 27+#include "interface/surface.h"
 28+IMPL(buffered, surface)
 29+
 30+struct buffer_entry
 31+{
 32+    struct wld_buffer * buffer;
 33+    bool busy;
 34+};
 35+
 36+struct buffered_surface
 37+{
 38+    struct wld_surface base;
 39+
 40+    struct wld_context * context;
 41+    struct buffer_entry * entries, * back;
 42+    unsigned entries_size, entries_capacity;
 43+
 44+    struct wld_buffer_socket * buffer_socket;
 45+
 46+    uint32_t width, height;
 47+    enum wld_format format;
 48+};
 49+
 50+struct wld_surface * buffered_surface_create
 51+    (struct wld_context * context, uint32_t width, uint32_t height,
 52+     uint32_t format, struct wld_buffer_socket * buffer_socket)
 53+{
 54+    struct buffered_surface * surface;
 55+
 56+    if (!(surface = malloc(sizeof *surface)))
 57+        return NULL;
 58+
 59+    surface_initialize(&surface->base, &surface_impl);
 60+    surface->context = context;
 61+    surface->entries = NULL;
 62+    surface->back = NULL;
 63+    surface->entries_size = 0;
 64+    surface->entries_capacity = 0;
 65+    surface->buffer_socket = buffer_socket;
 66+    surface->width = width;
 67+    surface->height = height;
 68+    surface->format = format;
 69+
 70+    return &surface->base;
 71+}
 72+
 73+pixman_region32_t * surface_damage(struct wld_surface * base,
 74+                                   pixman_region32_t * new_damage)
 75+{
 76+    struct buffered_surface * surface = buffered_surface(base);
 77+    struct wld_buffer * back_buffer;
 78+    unsigned index;
 79+
 80+    if (pixman_region32_not_empty(new_damage))
 81+    {
 82+        for (index = 0; index < surface->entries_size; ++index)
 83+        {
 84+            pixman_region32_union(&surface->entries[index].buffer->damage,
 85+                                  &surface->entries[index].buffer->damage,
 86+                                  new_damage);
 87+        }
 88+    }
 89+
 90+    if (!(back_buffer = surface_back(base)))
 91+        return NULL;
 92+
 93+    return &back_buffer->damage;
 94+}
 95+
 96+struct wld_buffer * surface_back(struct wld_surface * base)
 97+{
 98+    struct buffered_surface * surface = buffered_surface(base);
 99+    unsigned index;
100+
101+    if (surface->back)
102+        return surface->back->buffer;
103+
104+    /* The buffer socket may need to process any incoming buffer releases. */
105+    if (surface->buffer_socket)
106+        surface->buffer_socket->impl->process(surface->buffer_socket);
107+
108+    for (index = 0; index < surface->entries_size; ++index)
109+    {
110+        if (!surface->entries[index].busy)
111+        {
112+            surface->back = &surface->entries[index];
113+            return surface->back->buffer;
114+        }
115+    }
116+
117+    /* If there are no free buffers, we need to allocate another one. */
118+    struct wld_buffer * buffer;
119+
120+    buffer = wld_create_buffer(surface->context,
121+                               surface->width, surface->height,
122+                               surface->format);
123+
124+    if (!buffer)
125+        goto error0;
126+
127+    if (surface->entries_size == surface->entries_capacity)
128+    {
129+        struct buffer_entry * new_entries;
130+        size_t new_capacity = surface->entries_capacity * 2 + 1;
131+
132+        new_entries = realloc(surface->entries,
133+                              new_capacity * sizeof surface->entries[0]);
134+
135+        if (!new_entries)
136+            goto error1;
137+
138+        surface->entries = new_entries;
139+        surface->entries_capacity = new_capacity;
140+    }
141+
142+    surface->back = &surface->entries[surface->entries_size++];
143+    *surface->back = (struct buffer_entry) {
144+        .buffer = buffer,
145+        .busy = false
146+    };
147+
148+    return buffer;
149+
150+  error1:
151+    wld_destroy_buffer(buffer);
152+  error0:
153+    return NULL;
154+}
155+
156+struct wld_buffer * surface_take(struct wld_surface * base)
157+{
158+    struct buffered_surface * surface = buffered_surface(base);
159+    struct wld_buffer * buffer;
160+
161+    if (!(buffer = surface_back(base)))
162+        return NULL;
163+
164+    surface->back->busy = true;
165+    surface->back = NULL;
166+    pixman_region32_clear(&buffer->damage);
167+
168+    return buffer;
169+}
170+
171+bool surface_release(struct wld_surface * base, struct wld_buffer * buffer)
172+{
173+    struct buffered_surface * surface = buffered_surface(base);
174+    unsigned index;
175+
176+    for (index = 0; index < surface->entries_size; ++index)
177+    {
178+        if (surface->entries[index].buffer == buffer)
179+        {
180+            surface->entries[index].busy = false;
181+            return true;
182+        }
183+    }
184+
185+    return false;
186+}
187+
188+bool surface_swap(struct wld_surface * base)
189+{
190+    struct buffered_surface * surface = buffered_surface(base);
191+    struct wld_buffer * buffer;
192+
193+    if (!surface->buffer_socket)
194+        return false;
195+
196+    if (!(buffer = surface_back(base)))
197+        return false;
198+
199+    if (!surface->buffer_socket->impl->attach(surface->buffer_socket, buffer))
200+        return false;
201+
202+    surface->back->busy = true;
203+    surface->back = NULL;
204+    pixman_region32_clear(&buffer->damage);
205+
206+    return true;
207+}
208+
209+void surface_destroy(struct wld_surface * base)
210+{
211+    struct buffered_surface * surface = buffered_surface(base);
212+    unsigned index;
213+
214+    if (surface->buffer_socket)
215+        surface->buffer_socket->impl->destroy(surface->buffer_socket);
216+
217+    for (index = 0; index < surface->entries_size; ++index)
218+        wld_destroy_buffer(surface->entries[index].buffer);
219+
220+    free(surface->entries);
221+    free(surface);
222+}
223+
+1, -1
1@@ -27,7 +27,7 @@ struct wld_surface * default_create_surface(struct wld_context * context,
2                                             uint32_t width, uint32_t height,
3                                             uint32_t format)
4 {
5-    return NULL;
6+    return buffered_surface_create(context, width, height, format, NULL);
7 }
8 
9 void surface_initialize(struct wld_surface * surface,
+18, -0
 1@@ -159,6 +159,19 @@ struct wld_exporter_impl
 2     void (* destroy)(struct wld_exporter * exporter);
 3 };
 4 
 5+struct wld_buffer_socket
 6+{
 7+    const struct wld_buffer_socket_impl * impl;
 8+};
 9+
10+struct wld_buffer_socket_impl
11+{
12+    bool (* attach)(struct wld_buffer_socket * socket,
13+                    struct wld_buffer * buffer);
14+    void (* process)(struct wld_buffer_socket * socket);
15+    void (* destroy)(struct wld_buffer_socket * socket);
16+};
17+
18 bool font_ensure_glyph(struct font * font, FT_UInt glyph_index);
19 
20 /**
21@@ -220,6 +233,11 @@ struct wld_surface * default_create_surface(struct wld_context * context,
22                                             uint32_t width, uint32_t height,
23                                             uint32_t format);
24 
25+struct wld_surface * buffered_surface_create(struct wld_context * context,
26+                                             uint32_t width, uint32_t height,
27+                                             uint32_t format,
28+                                             struct wld_buffer_socket * socket);
29+
30 void context_initialize(struct wld_context * context,
31                         const struct wld_context_impl * impl);
32