commit 182f6d3
Michael Forney
·
2014-01-15 22:27:38 +0000 UTC
parent a0520fc
Implement buffered surfaces
4 files changed,
+242,
-1
M
Makefile
+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