blob: 520238129517c4bc873ce0d96f767d57659bd0a1 [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"
22
23#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \
24 exit(1); \
25 } while (0)
26
27/*
28 * Enumerates states for the client framebuffer update reader.
29 */
30typedef enum ClientFBState {
31 /* The reader is waiting on update header. */
32 WAIT_HEADER,
33
34 /* The reader is waiting on pixels. */
35 WAIT_PIXELS,
36} ClientFBState;
37
38/*
39 * Descriptor for the framebuffer client.
40 */
41struct ClientFramebuffer {
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080042 /* Framebuffer for this client. */
43 QFrameBuffer* fb;
44
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080045 /* Core connection instance for the framebuffer client. */
46 CoreConnection* core_connection;
47
48 /* Current update header. */
49 FBUpdateMessage update_header;
50
51 /* Reader's buffer. */
52 uint8_t* reader_buffer;
53
54 /* Offset in the reader's buffer where to read next chunk of data. */
55 size_t reader_offset;
56
57 /* Total number of bytes the reader expects to read. */
58 size_t reader_bytes;
59
60 /* Current state of the update reader. */
61 ClientFBState fb_state;
62
63 /* Socket descriptor for the framebuffer client. */
64 int sock;
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -080065
66 /* Number of bits used to encode single pixel. */
67 int bits_per_pixel;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080068};
69
70/* The only instance of framebuffer client. */
71static ClientFramebuffer _client_fb;
72
73/*
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080074 * Updates a display rectangle.
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080075 * Param
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080076 * fb - Framebuffer where to update the rectangle.
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080077 * x, y, w, and h define rectangle to update.
78 * bits_per_pixel define number of bits used to encode a single pixel.
79 * pixels contains pixels for the rectangle. Buffer addressed by this parameter
80 * must be eventually freed with free()
81 */
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080082static void
83update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080084 uint8_t bits_per_pixel, uint8_t* pixels)
85{
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -080086 if (fb != NULL) {
87 uint16_t n;
88 const uint8_t* src = pixels;
89 const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8);
90 uint8_t* dst = (uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel;
91 for (n = 0; n < h; n++) {
92 memcpy(dst, src, src_line_size);
93 src += src_line_size;
94 dst += fb->pitch;
95 }
96 qframebuffer_update(fb, x, y, w, h);
97 }
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080098 free(pixels);
99}
100
101/*
102 * Asynchronous I/O callback launched when framebuffer notifications are ready
103 * to be read.
104 * Param:
105 * opaque - ClientFramebuffer instance.
106 */
107static void
108_clientfb_read_cb(void* opaque)
109{
110 ClientFramebuffer* fb_client = opaque;
111 int ret;
112
113 // Read updates while they are immediately available.
114 for (;;) {
115 // Read next chunk of data.
116 ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset,
117 fb_client->reader_bytes - fb_client->reader_offset);
118 if (ret == 0) {
119 /* disconnection ! */
120 clientfb_destroy(fb_client);
121 return;
122 }
123 if (ret < 0) {
124 if (errno == EINTR) {
125 /* loop on EINTR */
126 continue;
127 } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
128 // Chunk is not avalable at this point. Come back later.
129 return;
130 }
131 }
132
133 fb_client->reader_offset += ret;
134 if (fb_client->reader_offset != fb_client->reader_bytes) {
135 // There are still some data left in the pipe.
136 continue;
137 }
138
139 // All expected data has been read. Time to change the state.
140 if (fb_client->fb_state == WAIT_HEADER) {
141 // Update header has been read. Prepare for the pixels.
142 fb_client->fb_state = WAIT_PIXELS;
143 fb_client->reader_offset = 0;
144 fb_client->reader_bytes = fb_client->update_header.w *
145 fb_client->update_header.h *
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800146 (fb_client->bits_per_pixel / 8);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800147 fb_client->reader_buffer = malloc(fb_client->reader_bytes);
148 if (fb_client->reader_buffer == NULL) {
149 PANIC("Unable to allocate memory for framebuffer update\n");
150 }
151 } else {
152 // Pixels have been read. Prepare for the header.
153 uint8_t* pixels = fb_client->reader_buffer;
154
155 fb_client->fb_state = WAIT_HEADER;
156 fb_client->reader_offset = 0;
157 fb_client->reader_bytes = sizeof(FBUpdateMessage);
158 fb_client->reader_buffer = (uint8_t*)&fb_client->update_header;
159
160 // Perform the update. Note that pixels buffer must be freed there.
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800161 update_rect(fb_client->fb, fb_client->update_header.x,
162 fb_client->update_header.y, fb_client->update_header.w,
163 fb_client->update_header.h, fb_client->bits_per_pixel,
164 pixels);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800165 }
166 }
167}
168
169ClientFramebuffer*
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800170clientfb_create(SockAddress* console_socket,
171 const char* protocol,
172 QFrameBuffer* fb)
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800173{
174 char* connect_message = NULL;
175 char switch_cmd[256];
176
177 // Connect to the framebuffer service.
178 _client_fb.core_connection = core_connection_create(console_socket);
179 if (_client_fb.core_connection == NULL) {
180 derror("Framebuffer client is unable to connect to the console: %s\n",
181 errno_str);
182 return NULL;
183 }
184 if (core_connection_open(_client_fb.core_connection)) {
185 core_connection_free(_client_fb.core_connection);
186 _client_fb.core_connection = NULL;
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800187 derror("Framebuffer client is unable to open the console: %s\n",
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800188 errno_str);
189 return NULL;
190 }
191 snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
192 if (core_connection_switch_stream(_client_fb.core_connection, switch_cmd,
193 &connect_message)) {
194 derror("Unable to attach to the framebuffer %s: %s\n",
195 switch_cmd, connect_message ? connect_message : "");
196 if (connect_message != NULL) {
197 free(connect_message);
198 }
199 core_connection_close(_client_fb.core_connection);
200 core_connection_free(_client_fb.core_connection);
201 _client_fb.core_connection = NULL;
202 return NULL;
203 }
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800204
205 // We expect core framebuffer to return us bits per pixel property in
206 // the handshake message.
207 _client_fb.bits_per_pixel = 0;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800208 if (connect_message != NULL) {
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800209 char* bpp = strstr(connect_message, "bitsperpixel=");
210 if (bpp != NULL) {
211 char* end;
212 bpp += strlen("bitsperpixel=");
213 end = strchr(bpp, ' ');
214 if (end == NULL) {
215 end = bpp + strlen(bpp);
216 }
217 _client_fb.bits_per_pixel = strtol(bpp, &end, 0);
218 }
219 }
220
221 if (!_client_fb.bits_per_pixel) {
222 derror("Unexpected core framebuffer reply: %s\n"
223 "Bits per pixel property is not there, or is invalid\n", connect_message);
224 core_connection_close(_client_fb.core_connection);
225 core_connection_free(_client_fb.core_connection);
226 _client_fb.core_connection = NULL;
227 return NULL;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800228 }
229
230 // Now that we're connected lets initialize the descriptor.
Vladimir Chtchetkinecf755ea2011-01-12 14:38:19 -0800231 _client_fb.fb = fb;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800232 _client_fb.sock = core_connection_get_socket(_client_fb.core_connection);
233 _client_fb.fb_state = WAIT_HEADER;
234 _client_fb.reader_buffer = (uint8_t*)&_client_fb.update_header;
235 _client_fb.reader_offset = 0;
236 _client_fb.reader_bytes = sizeof(FBUpdateMessage);
237
Vladimir Chtchetkine8acf4e22010-12-21 07:14:17 -0800238 if (connect_message != NULL) {
239 free(connect_message);
240 }
241
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800242 // At last setup read callback, and start receiving the updates.
243 if (qemu_set_fd_handler(_client_fb.sock, _clientfb_read_cb, NULL, &_client_fb)) {
244 derror("Unable to set up framebuffer read callback\n");
245 core_connection_close(_client_fb.core_connection);
246 core_connection_free(_client_fb.core_connection);
247 _client_fb.core_connection = NULL;
248 return NULL;
249 }
250
251 fprintf(stdout, "Framebuffer %s is now attached to the core %s\n",
252 protocol, sock_address_to_string(console_socket));
253
254 return &_client_fb;
255}
256
257void
258clientfb_destroy(ClientFramebuffer* client_fb)
259{
260 if (client_fb != NULL && client_fb->core_connection != NULL) {
261 // Disable the reader callback.
262 qemu_set_fd_handler(client_fb->sock, NULL, NULL, NULL);
263
264 // Close framebuffer connection.
265 core_connection_close(client_fb->core_connection);
266 core_connection_free(client_fb->core_connection);
267 client_fb->core_connection = NULL;
268 }
269}