1 /* Copyright (C) 2010 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 /*
14 * Contains core-side framebuffer service that sends framebuffer updates
15 * to the UI connected to the core.
16 */
17
18 #include "console.h"
19 #include "android/looper.h"
20 #include "android/display-core.h"
21 #include "android/async-utils.h"
22 #include "android/protocol/fb-updates.h"
23 #include "android/protocol/fb-updates-proxy.h"
24 #include "android/utils/system.h"
25 #include "android/utils/debug.h"
26
27 /* Descriptor for the Core-side implementation of the "framebufer" service.
28 */
29 struct ProxyFramebuffer {
30 /* Writer used to send FB update notification messages. */
31 AsyncWriter fb_update_writer;
32
33 /* Reader used to read FB requests from the client. */
34 AsyncReader fb_req_reader;
35
36 /* I/O associated with this descriptor. */
37 LoopIo io;
38
39 /* Display state used for this service */
40 DisplayState* ds;
41 DisplayUpdateListener* ds_listener;
42
43 /* Looper used to communicate framebuffer updates. */
44 Looper* looper;
45
46 /* Head of the list of pending FB update notifications. */
47 struct FBUpdateNotify* fb_update_head;
48
49 /* Tail of the list of pending FB update notifications. */
50 struct FBUpdateNotify* fb_update_tail;
51
52 /* Socket used to communicate framebuffer updates. */
53 int sock;
54
55 /* Framebuffer request header. */
56 FBRequestHeader fb_req_header;
57 };
58
59 /* Framebuffer update notification descriptor. */
60 typedef struct FBUpdateNotify {
61 /* Links all pending FB update notifications. */
62 struct FBUpdateNotify* next_fb_update;
63
64 /* Core framebuffer instance that owns the message. */
65 ProxyFramebuffer* proxy_fb;
66
67 /* Size of the message to transfer. */
68 size_t message_size;
69
70 /* Update message. */
71 FBUpdateMessage message;
72 } FBUpdateNotify;
73
74 /*
75 * Gets pointer in framebuffer's pixels for the given pixel.
76 * Param:
77 * fb Framebuffer containing pixels.
78 * x, and y identify the pixel to get pointer for.
79 * Return:
80 * Pointer in framebuffer's pixels for the given pixel.
81 */
82 static const uint8_t*
_pixel_offset(const DisplaySurface * dsu,int x,int y)83 _pixel_offset(const DisplaySurface* dsu, int x, int y)
84 {
85 return (const uint8_t*)dsu->data + y * dsu->linesize + x * dsu->pf.bytes_per_pixel;
86 }
87
88 /*
89 * Copies pixels from a framebuffer rectangle.
90 * Param:
91 * rect - Buffer where to copy pixel.
92 * fb - Framebuffer containing the rectangle to copy.
93 * x, y, w, and h - dimensions of the rectangle to copy.
94 */
95 static void
_copy_fb_rect(uint8_t * rect,const DisplaySurface * dsu,int x,int y,int w,int h)96 _copy_fb_rect(uint8_t* rect, const DisplaySurface* dsu, int x, int y, int w, int h)
97 {
98 const uint8_t* start = _pixel_offset(dsu, x, y);
99 for (; h > 0; h--) {
100 memcpy(rect, start, w * dsu->pf.bytes_per_pixel);
101 start += dsu->linesize;
102 rect += w * dsu->pf.bytes_per_pixel;
103 }
104 }
105
106 /*
107 * Allocates and initializes framebuffer update notification descriptor.
108 * Param:
109 * ds - Display state for the framebuffer.
110 * fb Framebuffer containing pixels.
111 * x, y, w, and h identify the rectangle that is being updated.
112 * Return:
113 * Initialized framebuffer update notification descriptor.
114 */
115 static FBUpdateNotify*
fbupdatenotify_create(ProxyFramebuffer * proxy_fb,int x,int y,int w,int h)116 fbupdatenotify_create(ProxyFramebuffer* proxy_fb,
117 int x, int y, int w, int h)
118 {
119 const size_t rect_size = w * h * proxy_fb->ds->surface->pf.bytes_per_pixel;
120 FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size);
121
122 ret->next_fb_update = NULL;
123 ret->proxy_fb = proxy_fb;
124 ret->message_size = sizeof(FBUpdateMessage) + rect_size;
125 ret->message.x = x;
126 ret->message.y = y;
127 ret->message.w = w;
128 ret->message.h = h;
129 _copy_fb_rect(ret->message.rect, proxy_fb->ds->surface, x, y, w, h);
130 return ret;
131 }
132
133 /*
134 * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create.
135 * Param:
136 * desc - Descreptor to delete.
137 */
138 static void
fbupdatenotify_delete(FBUpdateNotify * desc)139 fbupdatenotify_delete(FBUpdateNotify* desc)
140 {
141 if (desc != NULL) {
142 free(desc);
143 }
144 }
145
146 /*
147 * Asynchronous write I/O callback launched when writing framebuffer
148 * notifications to the socket.
149 * Param:
150 * proxy_fb - ProxyFramebuffer instance.
151 */
152 static void
_proxyFb_io_write(ProxyFramebuffer * proxy_fb)153 _proxyFb_io_write(ProxyFramebuffer* proxy_fb)
154 {
155 while (proxy_fb->fb_update_head != NULL) {
156 FBUpdateNotify* current_update = proxy_fb->fb_update_head;
157 // Lets continue writing of the current notification.
158 const AsyncStatus status =
159 asyncWriter_write(&proxy_fb->fb_update_writer);
160 switch (status) {
161 case ASYNC_COMPLETE:
162 // Done with the current update. Move on to the next one.
163 break;
164 case ASYNC_ERROR:
165 // Done with the current update. Move on to the next one.
166 loopIo_dontWantWrite(&proxy_fb->io);
167 break;
168
169 case ASYNC_NEED_MORE:
170 // Transfer will eventually come back into this routine.
171 return;
172 }
173
174 // Advance the list of updates
175 proxy_fb->fb_update_head = current_update->next_fb_update;
176 if (proxy_fb->fb_update_head == NULL) {
177 proxy_fb->fb_update_tail = NULL;
178 }
179 fbupdatenotify_delete(current_update);
180
181 if (proxy_fb->fb_update_head != NULL) {
182 // Schedule the next one.
183 asyncWriter_init(&proxy_fb->fb_update_writer,
184 &proxy_fb->fb_update_head->message,
185 proxy_fb->fb_update_head->message_size,
186 &proxy_fb->io);
187 }
188 }
189 }
190
191 static void proxyFb_update(void* opaque, int x, int y, int w, int h);
192
193 /*
194 * Asynchronous read I/O callback launched when reading framebuffer requests
195 * from the socket.
196 * Param:
197 * proxy_fb - ProxyFramebuffer instance.
198 */
199 static void
_proxyFb_io_read(ProxyFramebuffer * proxy_fb)200 _proxyFb_io_read(ProxyFramebuffer* proxy_fb)
201 {
202 // Read the request header.
203 DisplaySurface* dsu;
204 const AsyncStatus status =
205 asyncReader_read(&proxy_fb->fb_req_reader);
206 switch (status) {
207 case ASYNC_COMPLETE:
208 // Request header is received
209 switch (proxy_fb->fb_req_header.request_type) {
210 case AFB_REQUEST_REFRESH:
211 // Force full screen update to be sent
212 dsu = proxy_fb->ds->surface;
213 proxyFb_update(proxy_fb,
214 0, 0, dsu->width, dsu->height);
215 break;
216 default:
217 derror("Unknown framebuffer request %d\n",
218 proxy_fb->fb_req_header.request_type);
219 break;
220 }
221 proxy_fb->fb_req_header.request_type = -1;
222 asyncReader_init(&proxy_fb->fb_req_reader, &proxy_fb->fb_req_header,
223 sizeof(proxy_fb->fb_req_header), &proxy_fb->io);
224 break;
225 case ASYNC_ERROR:
226 loopIo_dontWantRead(&proxy_fb->io);
227 if (errno == ECONNRESET) {
228 // UI has exited. We need to destroy framebuffer service.
229 proxyFb_destroy(proxy_fb);
230 }
231 break;
232
233 case ASYNC_NEED_MORE:
234 // Transfer will eventually come back into this routine.
235 return;
236 }
237 }
238
239 /*
240 * Asynchronous I/O callback launched when writing framebuffer notifications
241 * to the socket.
242 * Param:
243 * opaque - ProxyFramebuffer instance.
244 */
245 static void
_proxyFb_io_fun(void * opaque,int fd,unsigned events)246 _proxyFb_io_fun(void* opaque, int fd, unsigned events)
247 {
248 if (events & LOOP_IO_READ) {
249 _proxyFb_io_read((ProxyFramebuffer*)opaque);
250 } else if (events & LOOP_IO_WRITE) {
251 _proxyFb_io_write((ProxyFramebuffer*)opaque);
252 }
253 }
254
255 ProxyFramebuffer*
proxyFb_create(int sock,const char * protocol)256 proxyFb_create(int sock, const char* protocol)
257 {
258 // At this point we're implementing the -raw protocol only.
259 ProxyFramebuffer* ret;
260 DisplayState* ds = get_displaystate();
261 DisplayUpdateListener* dul;
262
263 ANEW0(ret);
264 ret->sock = sock;
265 ret->looper = looper_newCore();
266 ret->ds = ds;
267
268 ANEW0(dul);
269 dul->opaque = ret;
270 dul->dpy_update = proxyFb_update;
271 register_displayupdatelistener(ds, dul);
272 ret->ds_listener = dul;
273
274 ret->fb_update_head = NULL;
275 ret->fb_update_tail = NULL;
276 loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret);
277 asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header,
278 sizeof(ret->fb_req_header), &ret->io);
279 return ret;
280 }
281
282 void
proxyFb_destroy(ProxyFramebuffer * proxy_fb)283 proxyFb_destroy(ProxyFramebuffer* proxy_fb)
284 {
285 if (proxy_fb != NULL) {
286 unregister_displayupdatelistener(proxy_fb->ds, proxy_fb->ds_listener);
287 if (proxy_fb->looper != NULL) {
288 // Stop all I/O that may still be going on.
289 loopIo_done(&proxy_fb->io);
290 // Delete all pending frame updates.
291 while (proxy_fb->fb_update_head != NULL) {
292 FBUpdateNotify* pending_update = proxy_fb->fb_update_head;
293 proxy_fb->fb_update_head = pending_update->next_fb_update;
294 fbupdatenotify_delete(pending_update);
295 }
296 proxy_fb->fb_update_tail = NULL;
297 looper_free(proxy_fb->looper);
298 proxy_fb->looper = NULL;
299 }
300 AFREE(proxy_fb);
301 }
302 }
303
304 static void
proxyFb_update(void * opaque,int x,int y,int w,int h)305 proxyFb_update(void* opaque, int x, int y, int w, int h)
306 {
307 ProxyFramebuffer* proxy_fb = opaque;
308 AsyncStatus status;
309 FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, x, y, w, h);
310
311 // Lets see if we should list it behind other pending updates.
312 if (proxy_fb->fb_update_tail != NULL) {
313 proxy_fb->fb_update_tail->next_fb_update = descr;
314 proxy_fb->fb_update_tail = descr;
315 return;
316 }
317
318 // We're first in the list. Just send it now.
319 proxy_fb->fb_update_head = proxy_fb->fb_update_tail = descr;
320 asyncWriter_init(&proxy_fb->fb_update_writer,
321 &proxy_fb->fb_update_head->message,
322 proxy_fb->fb_update_head->message_size, &proxy_fb->io);
323 status = asyncWriter_write(&proxy_fb->fb_update_writer);
324 switch (status) {
325 case ASYNC_COMPLETE:
326 fbupdatenotify_delete(descr);
327 proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
328 return;
329 case ASYNC_ERROR:
330 fbupdatenotify_delete(descr);
331 proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
332 return;
333 case ASYNC_NEED_MORE:
334 // Update transfer will eventually complete in _proxyFb_io_fun
335 return;
336 }
337 }
338
339 int
proxyFb_get_bits_per_pixel(ProxyFramebuffer * proxy_fb)340 proxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb)
341 {
342 if (proxy_fb == NULL || proxy_fb->ds == NULL)
343 return -1;
344
345 return proxy_fb->ds->surface->pf.bits_per_pixel;
346 }
347