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