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