1e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/* Copyright (C) 2010 The Android Open Source Project
2e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine**
3e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** This software is licensed under the terms of the GNU General Public
4e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** License version 2, as published by the Free Software Foundation, and
5e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** may be copied, distributed, and modified under those terms.
6e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine**
7e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** This program is distributed in the hope that it will be useful,
8e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** but WITHOUT ANY WARRANTY; without even the implied warranty of
9e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine** GNU General Public License for more details.
11e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine*/
12e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
13e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
14e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Contains core-side framebuffer service that sends framebuffer updates
15e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * to the UI connected to the core.
16e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
17e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
18e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "console.h"
19e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "android/looper.h"
20e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "android/display-core.h"
21e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "android/async-utils.h"
2294a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine#include "android/protocol/fb-updates.h"
2394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine#include "android/protocol/fb-updates-proxy.h"
24e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "android/utils/system.h"
25e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine#include "android/utils/debug.h"
26e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
2794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine/* Descriptor for the Core-side implementation of the "framebufer" service.
2894a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine */
2994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkinestruct ProxyFramebuffer {
30e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Writer used to send FB update notification messages. */
318acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine    AsyncWriter             fb_update_writer;
32e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
33ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    /* Reader used to read FB requests from the client. */
34ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    AsyncReader             fb_req_reader;
35ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine
36e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* I/O associated with this descriptor. */
378acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine    LoopIo                  io;
388acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine
397a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    /* Display state used for this service */
407a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    DisplayState*           ds;
417a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    DisplayUpdateListener*  ds_listener;
42e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
43e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Looper used to communicate framebuffer updates. */
44e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    Looper* looper;
45e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
46e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Head of the list of pending FB update notifications. */
47e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    struct FBUpdateNotify*  fb_update_head;
48e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
49e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Tail of the list of pending FB update notifications. */
50e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    struct FBUpdateNotify*  fb_update_tail;
51e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
52e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Socket used to communicate framebuffer updates. */
53e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    int     sock;
54ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine
55ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    /* Framebuffer request header. */
56ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    FBRequestHeader         fb_req_header;
57e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine};
58e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
5994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine/* Framebuffer update notification descriptor. */
60e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinetypedef struct FBUpdateNotify {
61e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Links all pending FB update notifications. */
62e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    struct FBUpdateNotify*  next_fb_update;
63e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
64e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Core framebuffer instance that owns the message. */
6594a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    ProxyFramebuffer*       proxy_fb;
66e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
67e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Size of the message to transfer. */
68e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    size_t                  message_size;
69e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
70e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    /* Update message. */
71e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    FBUpdateMessage         message;
72e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine} FBUpdateNotify;
73e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
74e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
75e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Gets pointer in framebuffer's pixels for the given pixel.
76e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Param:
77e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  fb Framebuffer containing pixels.
78e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  x, and y identify the pixel to get pointer for.
79e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Return:
80e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  Pointer in framebuffer's pixels for the given pixel.
81e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
82e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinestatic const uint8_t*
837a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner_pixel_offset(const DisplaySurface* dsu, int x, int y)
84e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
857a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    return (const uint8_t*)dsu->data + y * dsu->linesize + x * dsu->pf.bytes_per_pixel;
86e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
87e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
88e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
89e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Copies pixels from a framebuffer rectangle.
90e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Param:
91e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  rect - Buffer where to copy pixel.
92e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  fb - Framebuffer containing the rectangle to copy.
93e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  x, y, w, and h - dimensions of the rectangle to copy.
94e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
95e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinestatic void
967a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner_copy_fb_rect(uint8_t* rect, const DisplaySurface* dsu, int x, int y, int w, int h)
97e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
987a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    const uint8_t* start = _pixel_offset(dsu, x, y);
99e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    for (; h > 0; h--) {
1007a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        memcpy(rect, start, w * dsu->pf.bytes_per_pixel);
1017a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        start += dsu->linesize;
1027a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        rect += w * dsu->pf.bytes_per_pixel;
103e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
104e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
105e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
106e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
107e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Allocates and initializes framebuffer update notification descriptor.
108e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Param:
109e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  ds - Display state for the framebuffer.
110e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  fb Framebuffer containing pixels.
111e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  x, y, w, and h identify the rectangle that is being updated.
112e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Return:
113e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  Initialized framebuffer update notification descriptor.
114e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
115e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinestatic FBUpdateNotify*
1167a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turnerfbupdatenotify_create(ProxyFramebuffer* proxy_fb,
117e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                      int x, int y, int w, int h)
118e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
1197a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    const size_t rect_size = w * h * proxy_fb->ds->surface->pf.bytes_per_pixel;
120e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size);
121e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
122e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->next_fb_update = NULL;
12394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    ret->proxy_fb = proxy_fb;
124e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->message_size = sizeof(FBUpdateMessage) + rect_size;
125e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->message.x = x;
126e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->message.y = y;
127e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->message.w = w;
128e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->message.h = h;
1297a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    _copy_fb_rect(ret->message.rect, proxy_fb->ds->surface, x, y, w, h);
130e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    return ret;
131e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
132e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
133e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
134e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create.
135e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Param:
136e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine *  desc - Descreptor to delete.
137e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
138e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinestatic void
139e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinefbupdatenotify_delete(FBUpdateNotify* desc)
140e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
141e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    if (desc != NULL) {
142e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        free(desc);
143e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
144e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
145e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
146e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine/*
147ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * Asynchronous write I/O callback launched when writing framebuffer
148ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * notifications to the socket.
149e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine * Param:
15094a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine *  proxy_fb - ProxyFramebuffer instance.
151e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine */
152e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinestatic void
15394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine_proxyFb_io_write(ProxyFramebuffer* proxy_fb)
154e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
15594a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    while (proxy_fb->fb_update_head != NULL) {
15694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        FBUpdateNotify* current_update = proxy_fb->fb_update_head;
157e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        // Lets continue writing of the current notification.
158e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        const AsyncStatus status =
159f9e333ade2529f257ced6bcff8e5824cb07eacf9David 'Digit' Turner            asyncWriter_write(&proxy_fb->fb_update_writer);
160e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        switch (status) {
161e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            case ASYNC_COMPLETE:
162e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                // Done with the current update. Move on to the next one.
163e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                break;
164e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            case ASYNC_ERROR:
165e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                // Done with the current update. Move on to the next one.
16694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                loopIo_dontWantWrite(&proxy_fb->io);
167e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                break;
168e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
169e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            case ASYNC_NEED_MORE:
170e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                // Transfer will eventually come back into this routine.
171e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                return;
172e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        }
173e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
174e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        // Advance the list of updates
17594a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        proxy_fb->fb_update_head = current_update->next_fb_update;
17694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        if (proxy_fb->fb_update_head == NULL) {
17794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->fb_update_tail = NULL;
178e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        }
179e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        fbupdatenotify_delete(current_update);
180e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
18194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        if (proxy_fb->fb_update_head != NULL) {
182e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            // Schedule the next one.
18394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            asyncWriter_init(&proxy_fb->fb_update_writer,
18494a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                             &proxy_fb->fb_update_head->message,
18594a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                             proxy_fb->fb_update_head->message_size,
18694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                             &proxy_fb->io);
187e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        }
188e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
189e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
190e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
1917a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turnerstatic void proxyFb_update(void* opaque, int x, int y, int w, int h);
1927a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner
193ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine/*
194ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * Asynchronous read I/O callback launched when reading framebuffer requests
195ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * from the socket.
196ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * Param:
19794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine *  proxy_fb - ProxyFramebuffer instance.
198ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine */
199ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkinestatic void
20094a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine_proxyFb_io_read(ProxyFramebuffer* proxy_fb)
201ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine{
202ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    // Read the request header.
2037a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    DisplaySurface* dsu;
204ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    const AsyncStatus status =
205f9e333ade2529f257ced6bcff8e5824cb07eacf9David 'Digit' Turner        asyncReader_read(&proxy_fb->fb_req_reader);
206ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    switch (status) {
207ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine        case ASYNC_COMPLETE:
208ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            // Request header is received
20994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            switch (proxy_fb->fb_req_header.request_type) {
210ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                case AFB_REQUEST_REFRESH:
211ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                    // Force full screen update to be sent
2127a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner                    dsu = proxy_fb->ds->surface;
2137a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner                    proxyFb_update(proxy_fb,
2147a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner                                  0, 0, dsu->width, dsu->height);
215ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                    break;
216ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                default:
217ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                    derror("Unknown framebuffer request %d\n",
21894a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                           proxy_fb->fb_req_header.request_type);
219ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                    break;
220ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            }
22194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->fb_req_header.request_type = -1;
22294a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            asyncReader_init(&proxy_fb->fb_req_reader, &proxy_fb->fb_req_header,
22394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                             sizeof(proxy_fb->fb_req_header), &proxy_fb->io);
224ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            break;
225ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine        case ASYNC_ERROR:
22694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            loopIo_dontWantRead(&proxy_fb->io);
227ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            if (errno == ECONNRESET) {
228ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                // UI has exited. We need to destroy framebuffer service.
2297a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner                proxyFb_destroy(proxy_fb);
230ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            }
231ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            break;
232ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine
233ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine        case ASYNC_NEED_MORE:
234ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            // Transfer will eventually come back into this routine.
235ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine            return;
236ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    }
237ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine}
238ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine
239ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine/*
240ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * Asynchronous I/O callback launched when writing framebuffer notifications
241ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * to the socket.
242ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine * Param:
24394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine *  opaque - ProxyFramebuffer instance.
244ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine */
245ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkinestatic void
24694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine_proxyFb_io_fun(void* opaque, int fd, unsigned events)
247ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine{
248ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    if (events & LOOP_IO_READ) {
24994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        _proxyFb_io_read((ProxyFramebuffer*)opaque);
250ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    } else if (events & LOOP_IO_WRITE) {
25194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        _proxyFb_io_write((ProxyFramebuffer*)opaque);
252ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    }
253ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine}
254ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine
25594a2fba98924c6684650d66409934358cb0c9d09Vladimir ChtchetkineProxyFramebuffer*
2567a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' TurnerproxyFb_create(int sock, const char* protocol)
257e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
258e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    // At this point we're implementing the -raw protocol only.
25994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    ProxyFramebuffer* ret;
2607a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    DisplayState* ds = get_displaystate();
2617a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    DisplayUpdateListener* dul;
2627a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner
263e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ANEW0(ret);
264e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->sock = sock;
265e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->looper = looper_newCore();
2667a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    ret->ds = ds;
2677a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner
2687a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    ANEW0(dul);
2697a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    dul->opaque = ret;
2707a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    dul->dpy_update = proxyFb_update;
2717a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    register_displayupdatelistener(ds, dul);
2727a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    ret->ds_listener = dul;
2737a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner
274e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->fb_update_head = NULL;
275e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    ret->fb_update_tail = NULL;
27694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret);
277ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine    asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header,
278ac389ae4513263597dc02e4099867d5123faaa04Vladimir Chtchetkine                     sizeof(ret->fb_req_header), &ret->io);
279e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    return ret;
280e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
281e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
282e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkinevoid
28394a2fba98924c6684650d66409934358cb0c9d09Vladimir ChtchetkineproxyFb_destroy(ProxyFramebuffer* proxy_fb)
284e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
28594a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    if (proxy_fb != NULL) {
2867a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        unregister_displayupdatelistener(proxy_fb->ds, proxy_fb->ds_listener);
28794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        if (proxy_fb->looper != NULL) {
288e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            // Stop all I/O that may still be going on.
28994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            loopIo_done(&proxy_fb->io);
290e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            // Delete all pending frame updates.
29194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            while (proxy_fb->fb_update_head != NULL) {
29294a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                FBUpdateNotify* pending_update = proxy_fb->fb_update_head;
29394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                proxy_fb->fb_update_head = pending_update->next_fb_update;
294e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine                fbupdatenotify_delete(pending_update);
295e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            }
29694a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->fb_update_tail = NULL;
29794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            looper_free(proxy_fb->looper);
29894a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->looper = NULL;
299e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        }
3007a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        AFREE(proxy_fb);
301e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
302e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
303e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
3047a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turnerstatic void
3057a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' TurnerproxyFb_update(void* opaque, int x, int y, int w, int h)
306e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine{
3077a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    ProxyFramebuffer* proxy_fb = opaque;
308e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    AsyncStatus status;
3097a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, x, y, w, h);
310e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
311e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    // Lets see if we should list it behind other pending updates.
31294a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    if (proxy_fb->fb_update_tail != NULL) {
31394a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        proxy_fb->fb_update_tail->next_fb_update = descr;
31494a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine        proxy_fb->fb_update_tail = descr;
315e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        return;
316e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
317e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine
318e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    // We're first in the list. Just send it now.
31994a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    proxy_fb->fb_update_head = proxy_fb->fb_update_tail = descr;
32094a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine    asyncWriter_init(&proxy_fb->fb_update_writer,
32194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                     &proxy_fb->fb_update_head->message,
32294a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine                     proxy_fb->fb_update_head->message_size, &proxy_fb->io);
323f9e333ade2529f257ced6bcff8e5824cb07eacf9David 'Digit' Turner    status = asyncWriter_write(&proxy_fb->fb_update_writer);
324e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    switch (status) {
325e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        case ASYNC_COMPLETE:
326e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            fbupdatenotify_delete(descr);
32794a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
328e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            return;
329e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        case ASYNC_ERROR:
330e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            fbupdatenotify_delete(descr);
33194a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
332e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            return;
333e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine        case ASYNC_NEED_MORE:
33494a2fba98924c6684650d66409934358cb0c9d09Vladimir Chtchetkine            // Update transfer will eventually complete in _proxyFb_io_fun
335e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine            return;
336e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine    }
337e95660aadc669784406d5f5a867988b8ecc2ed0dVladimir Chtchetkine}
3388acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine
3398acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkineint
34094a2fba98924c6684650d66409934358cb0c9d09Vladimir ChtchetkineproxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb)
3418acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine{
3427a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    if (proxy_fb == NULL || proxy_fb->ds == NULL)
3437a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner        return -1;
3447a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner
3457a5ee57895822a769f48ab40e590711a2459e2d1David 'Digit' Turner    return proxy_fb->ds->surface->pf.bits_per_pixel;
3468acf4e2237c2969647f47008344e44918bb30acbVladimir Chtchetkine}
347