blob: 0ae109f789b171128c4e83a29f3d80bc4dbf1196 [file] [log] [blame]
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -08001/* 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 UI-side framebuffer client that receives framebuffer updates
15 * from the core.
16 */
17
18#include "android/framebuffer-common.h"
19#include "android/framebuffer-ui.h"
20#include "android/utils/system.h"
21#include "android/utils/debug.h"
Vladimir Chtchetkineac389ae2011-01-20 14:35:55 -080022#include "android/sync-utils.h"
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080023
24#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \
25 exit(1); \
26 } while (0)
27
28/*
29 * Enumerates states for the client framebuffer update reader.
30 */
31typedef enum ClientFBState {
32 /* The reader is waiting on update header. */
33 WAIT_HEADER,
34
35 /* The reader is waiting on pixels. */
36 WAIT_PIXELS,
37} ClientFBState;
38
39/*
40 * Descriptor for the framebuffer client.
41 */
42struct ClientFramebuffer {
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080043 /* Framebuffer for this client. */
44 QFrameBuffer* fb;
45
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080046 /* Core connection instance for the framebuffer client. */
47 CoreConnection* core_connection;
48
49 /* Current update header. */
50 FBUpdateMessage update_header;
51
52 /* Reader's buffer. */
53 uint8_t* reader_buffer;
54
55 /* Offset in the reader's buffer where to read next chunk of data. */
56 size_t reader_offset;
57
58 /* Total number of bytes the reader expects to read. */
59 size_t reader_bytes;
60
61 /* Current state of the update reader. */
62 ClientFBState fb_state;
63
64 /* Socket descriptor for the framebuffer client. */
65 int sock;
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -080066
67 /* Number of bits used to encode single pixel. */
68 int bits_per_pixel;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080069};
70
71/* The only instance of framebuffer client. */
72static ClientFramebuffer _client_fb;
73
74/*
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080075 * Updates a display rectangle.
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080076 * Param
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080077 * fb - Framebuffer where to update the rectangle.
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080078 * x, y, w, and h define rectangle to update.
79 * bits_per_pixel define number of bits used to encode a single pixel.
80 * pixels contains pixels for the rectangle. Buffer addressed by this parameter
81 * must be eventually freed with free()
82 */
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080083static void
84update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080085 uint8_t bits_per_pixel, uint8_t* pixels)
86{
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080087 if (fb != NULL) {
88 uint16_t n;
89 const uint8_t* src = pixels;
90 const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8);
91 uint8_t* dst = (uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel;
92 for (n = 0; n < h; n++) {
93 memcpy(dst, src, src_line_size);
94 src += src_line_size;
95 dst += fb->pitch;
96 }
97 qframebuffer_update(fb, x, y, w, h);
98 }
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080099 free(pixels);
100}
101
102/*
103 * Asynchronous I/O callback launched when framebuffer notifications are ready
104 * to be read.
105 * Param:
106 * opaque - ClientFramebuffer instance.
107 */
108static void
109_clientfb_read_cb(void* opaque)
110{
111 ClientFramebuffer* fb_client = opaque;
112 int ret;
113
114 // Read updates while they are immediately available.
115 for (;;) {
116 // Read next chunk of data.
117 ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset,
118 fb_client->reader_bytes - fb_client->reader_offset);
119 if (ret == 0) {
120 /* disconnection ! */
121 clientfb_destroy(fb_client);
122 return;
123 }
124 if (ret < 0) {
125 if (errno == EINTR) {
126 /* loop on EINTR */
127 continue;
128 } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
129 // Chunk is not avalable at this point. Come back later.
130 return;
131 }
132 }
133
134 fb_client->reader_offset += ret;
135 if (fb_client->reader_offset != fb_client->reader_bytes) {
136 // There are still some data left in the pipe.
137 continue;
138 }
139
140 // All expected data has been read. Time to change the state.
141 if (fb_client->fb_state == WAIT_HEADER) {
142 // Update header has been read. Prepare for the pixels.
143 fb_client->fb_state = WAIT_PIXELS;
144 fb_client->reader_offset = 0;
145 fb_client->reader_bytes = fb_client->update_header.w *
146 fb_client->update_header.h *
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800147 (fb_client->bits_per_pixel / 8);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800148 fb_client->reader_buffer = malloc(fb_client->reader_bytes);
149 if (fb_client->reader_buffer == NULL) {
150 PANIC("Unable to allocate memory for framebuffer update\n");
151 }
152 } else {
153 // Pixels have been read. Prepare for the header.
154 uint8_t* pixels = fb_client->reader_buffer;
155
156 fb_client->fb_state = WAIT_HEADER;
157 fb_client->reader_offset = 0;
158 fb_client->reader_bytes = sizeof(FBUpdateMessage);
159 fb_client->reader_buffer = (uint8_t*)&fb_client->update_header;
160
161 // Perform the update. Note that pixels buffer must be freed there.
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800162 update_rect(fb_client->fb, fb_client->update_header.x,
163 fb_client->update_header.y, fb_client->update_header.w,
164 fb_client->update_header.h, fb_client->bits_per_pixel,
165 pixels);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800166 }
167 }
168}
169
170ClientFramebuffer*
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800171clientfb_create(SockAddress* console_socket,
172 const char* protocol,
173 QFrameBuffer* fb)
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800174{
175 char* connect_message = NULL;
176 char switch_cmd[256];
177
178 // Connect to the framebuffer service.
179 _client_fb.core_connection = core_connection_create(console_socket);
180 if (_client_fb.core_connection == NULL) {
181 derror("Framebuffer client is unable to connect to the console: %s\n",
182 errno_str);
183 return NULL;
184 }
185 if (core_connection_open(_client_fb.core_connection)) {
186 core_connection_free(_client_fb.core_connection);
187 _client_fb.core_connection = NULL;
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800188 derror("Framebuffer client is unable to open the console: %s\n",
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800189 errno_str);
190 return NULL;
191 }
192 snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
193 if (core_connection_switch_stream(_client_fb.core_connection, switch_cmd,
194 &connect_message)) {
195 derror("Unable to attach to the framebuffer %s: %s\n",
196 switch_cmd, connect_message ? connect_message : "");
197 if (connect_message != NULL) {
198 free(connect_message);
199 }
200 core_connection_close(_client_fb.core_connection);
201 core_connection_free(_client_fb.core_connection);
202 _client_fb.core_connection = NULL;
203 return NULL;
204 }
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800205
206 // We expect core framebuffer to return us bits per pixel property in
207 // the handshake message.
208 _client_fb.bits_per_pixel = 0;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800209 if (connect_message != NULL) {
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800210 char* bpp = strstr(connect_message, "bitsperpixel=");
211 if (bpp != NULL) {
212 char* end;
213 bpp += strlen("bitsperpixel=");
214 end = strchr(bpp, ' ');
215 if (end == NULL) {
216 end = bpp + strlen(bpp);
217 }
218 _client_fb.bits_per_pixel = strtol(bpp, &end, 0);
219 }
220 }
221
222 if (!_client_fb.bits_per_pixel) {
223 derror("Unexpected core framebuffer reply: %s\n"
224 "Bits per pixel property is not there, or is invalid\n", connect_message);
225 core_connection_close(_client_fb.core_connection);
226 core_connection_free(_client_fb.core_connection);
227 _client_fb.core_connection = NULL;
228 return NULL;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800229 }
230
231 // Now that we're connected lets initialize the descriptor.
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800232 _client_fb.fb = fb;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800233 _client_fb.sock = core_connection_get_socket(_client_fb.core_connection);
234 _client_fb.fb_state = WAIT_HEADER;
235 _client_fb.reader_buffer = (uint8_t*)&_client_fb.update_header;
236 _client_fb.reader_offset = 0;
237 _client_fb.reader_bytes = sizeof(FBUpdateMessage);
238
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800239 if (connect_message != NULL) {
240 free(connect_message);
241 }
242
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800243 // At last setup read callback, and start receiving the updates.
244 if (qemu_set_fd_handler(_client_fb.sock, _clientfb_read_cb, NULL, &_client_fb)) {
245 derror("Unable to set up framebuffer read callback\n");
246 core_connection_close(_client_fb.core_connection);
247 core_connection_free(_client_fb.core_connection);
248 _client_fb.core_connection = NULL;
249 return NULL;
250 }
Vladimir Chtchetkineac389ae2011-01-20 14:35:55 -0800251 {
252 // Force the core to send us entire framebuffer now, when we're prepared
253 // to receive it.
254 FBRequestHeader hd;
255 SyncSocket* sk = syncsocket_init(_client_fb.sock);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800256
Vladimir Chtchetkineac389ae2011-01-20 14:35:55 -0800257 hd.request_type = AFB_REQUEST_REFRESH;
258 syncsocket_start_write(sk);
259 syncsocket_write(sk, &hd, sizeof(hd), 500);
260 syncsocket_stop_write(sk);
261 syncsocket_free(sk);
262 }
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800263 fprintf(stdout, "Framebuffer %s is now attached to the core %s\n",
264 protocol, sock_address_to_string(console_socket));
265
266 return &_client_fb;
267}
268
269void
270clientfb_destroy(ClientFramebuffer* client_fb)
271{
272 if (client_fb != NULL && client_fb->core_connection != NULL) {
273 // Disable the reader callback.
274 qemu_set_fd_handler(client_fb->sock, NULL, NULL, NULL);
275
276 // Close framebuffer connection.
277 core_connection_close(client_fb->core_connection);
278 core_connection_free(client_fb->core_connection);
279 client_fb->core_connection = NULL;
280 }
281}