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 */
29struct 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. */
60typedef 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 */
82static const uint8_t*
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 */
95static void
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 */
115static FBUpdateNotify*
116fbupdatenotify_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 */
138static void
139fbupdatenotify_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 */
152static void
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
191static 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 */
199static void
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 */
245static void
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
255ProxyFramebuffer*
256proxyFb_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
282void
283proxyFb_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
304static void
305proxyFb_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
339int
340proxyFb_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