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* 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 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* 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 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 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 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 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* 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 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 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 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