1/* Copyright (C) 2007-2008 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#include "android/framebuffer.h" 13#include <memory.h> 14#include <stdlib.h> 15 16typedef struct { 17 /* client fields, these correspond to code that waits for updates before displaying them */ 18 /* at the moment, only one client is supported */ 19 void* fb_opaque; 20 QFrameBufferUpdateFunc fb_update; 21 QFrameBufferRotateFunc fb_rotate; 22 QFrameBufferPollFunc fb_poll; 23 QFrameBufferDoneFunc fb_done; 24 25 void* pr_opaque; 26 QFrameBufferCheckUpdateFunc pr_check; 27 QFrameBufferInvalidateFunc pr_invalidate; 28 QFrameBufferDetachFunc pr_detach; 29 30} QFrameBufferExtra; 31 32 33static int 34_get_pitch( int width, QFrameBufferFormat format ) 35{ 36 37 switch (format) { 38 case QFRAME_BUFFER_RGB565: 39 return width*2; 40 case QFRAME_BUFFER_RGBX_8888: 41 return width*4; 42 default: 43 return -1; 44 } 45} 46 47static int 48_get_bits_per_pixel(QFrameBufferFormat format) 49{ 50 51 switch (format) { 52 case QFRAME_BUFFER_RGB565: 53 return 16; 54 case QFRAME_BUFFER_RGBX_8888: 55 return 32; 56 default: 57 return -1; 58 } 59} 60 61static int 62_get_bytes_per_pixel(QFrameBufferFormat format) 63{ 64 65 switch (format) { 66 case QFRAME_BUFFER_RGB565: 67 return 2; 68 case QFRAME_BUFFER_RGBX_8888: 69 return 4; 70 default: 71 return -1; 72 } 73} 74 75int 76qframebuffer_init( QFrameBuffer* qfbuff, 77 int width, 78 int height, 79 int rotation, 80 QFrameBufferFormat format ) 81{ 82 int pitch, bytes_per_pixel, bits_per_pixel; 83 84 rotation &= 3; 85 86 if (!qfbuff || width < 0 || height < 0) 87 return -1; 88 89 pitch = _get_pitch( width, format ); 90 if (pitch < 0) 91 return -1; 92 93 bits_per_pixel = _get_bits_per_pixel(format); 94 if (bits_per_pixel < 0) 95 return -1; 96 97 bytes_per_pixel = _get_bytes_per_pixel(format); 98 if (bytes_per_pixel < 0) 99 return -1; 100 101 memset( qfbuff, 0, sizeof(*qfbuff) ); 102 103 qfbuff->extra = calloc( 1, sizeof(QFrameBufferExtra) ); 104 if (qfbuff->extra == NULL) 105 return -1; 106 107 qfbuff->pixels = calloc( pitch, height ); 108 if (qfbuff->pixels == NULL && (height > 0 && pitch > 0)) { 109 free( qfbuff->extra ); 110 return -1; 111 } 112 113 qfbuff->width = width; 114 qfbuff->height = height; 115 qfbuff->pitch = pitch; 116 qfbuff->format = format; 117 qfbuff->bits_per_pixel = bits_per_pixel; 118 qfbuff->bytes_per_pixel = bytes_per_pixel; 119 120 qframebuffer_set_dpi( qfbuff, DEFAULT_FRAMEBUFFER_DPI, DEFAULT_FRAMEBUFFER_DPI ); 121 return 0; 122} 123 124 125void 126qframebuffer_set_dpi( QFrameBuffer* qfbuff, 127 int x_dpi, 128 int y_dpi ) 129{ 130 /* dpi = dots / inch 131 ** inch = dots / dpi 132 ** mm / 25.4 = dots / dpi 133 ** mm = (dots * 25.4)/dpi 134 */ 135 qfbuff->phys_width_mm = (int)(0.5 + 25.4 * qfbuff->width / x_dpi); 136 qfbuff->phys_height_mm = (int)(0.5 + 25.4 * qfbuff->height / y_dpi); 137} 138 139/* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */ 140/* in millimeters. for the record 1 inch = 25.4 mm */ 141void 142qframebuffer_set_mm( QFrameBuffer* qfbuff, 143 int width_mm, 144 int height_mm ) 145{ 146 qfbuff->phys_width_mm = width_mm; 147 qfbuff->phys_height_mm = height_mm; 148} 149 150void 151qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h ) 152{ 153 QFrameBufferExtra* extra = qfbuff->extra; 154 155 if (extra->fb_update) 156 extra->fb_update( extra->fb_opaque, x, y, w, h ); 157} 158 159 160void 161qframebuffer_add_client( QFrameBuffer* qfbuff, 162 void* fb_opaque, 163 QFrameBufferUpdateFunc fb_update, 164 QFrameBufferRotateFunc fb_rotate, 165 QFrameBufferPollFunc fb_poll, 166 QFrameBufferDoneFunc fb_done ) 167{ 168 QFrameBufferExtra* extra = qfbuff->extra; 169 170 extra->fb_opaque = fb_opaque; 171 extra->fb_update = fb_update; 172 extra->fb_rotate = fb_rotate; 173 extra->fb_poll = fb_poll; 174 extra->fb_done = fb_done; 175} 176 177void 178qframebuffer_set_producer( QFrameBuffer* qfbuff, 179 void* opaque, 180 QFrameBufferCheckUpdateFunc pr_check, 181 QFrameBufferInvalidateFunc pr_invalidate, 182 QFrameBufferDetachFunc pr_detach ) 183{ 184 QFrameBufferExtra* extra = qfbuff->extra; 185 186 extra->pr_opaque = opaque; 187 extra->pr_check = pr_check; 188 extra->pr_invalidate = pr_invalidate; 189 extra->pr_detach = pr_detach; 190} 191 192 193void 194qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation ) 195{ 196 QFrameBufferExtra* extra = qfbuff->extra; 197 198 if ((rotation ^ qfbuff->rotation) & 1) { 199 /* swap width and height if new rotation requires it */ 200 int temp = qfbuff->width; 201 qfbuff->width = qfbuff->height; 202 qfbuff->height = temp; 203 qfbuff->pitch = _get_pitch( qfbuff->width, qfbuff->format ); 204 205 temp = qfbuff->phys_width_mm; 206 qfbuff->phys_width_mm = qfbuff->phys_height_mm; 207 qfbuff->phys_height_mm = temp; 208 } 209 qfbuff->rotation = rotation; 210 211 if (extra->fb_rotate) 212 extra->fb_rotate( extra->fb_opaque, rotation ); 213} 214 215void 216qframebuffer_poll( QFrameBuffer* qfbuff ) 217{ 218 QFrameBufferExtra* extra = qfbuff->extra; 219 220 if (extra && extra->fb_poll) 221 extra->fb_poll( extra->fb_opaque ); 222} 223 224 225extern void 226qframebuffer_done( QFrameBuffer* qfbuff ) 227{ 228 QFrameBufferExtra* extra = qfbuff->extra; 229 230 if (extra) { 231 if (extra->pr_detach) 232 extra->pr_detach( extra->pr_opaque ); 233 234 if (extra->fb_done) 235 extra->fb_done( extra->fb_opaque ); 236 } 237 238 free( qfbuff->pixels ); 239 free( qfbuff->extra ); 240 memset( qfbuff, 0, sizeof(*qfbuff) ); 241} 242 243 244#define MAX_FRAME_BUFFERS 8 245 246static QFrameBuffer* framebuffer_fifo[ MAX_FRAME_BUFFERS ]; 247static int framebuffer_fifo_rpos; 248static int framebuffer_fifo_count; 249 250void 251qframebuffer_fifo_add( QFrameBuffer* qfbuff ) 252{ 253 if (framebuffer_fifo_count >= MAX_FRAME_BUFFERS) 254 return; 255 256 framebuffer_fifo[ framebuffer_fifo_count++ ] = qfbuff; 257} 258 259 260QFrameBuffer* 261qframebuffer_fifo_get( void ) 262{ 263 if (framebuffer_fifo_rpos >= framebuffer_fifo_count) 264 return NULL; 265 266 return framebuffer_fifo[ framebuffer_fifo_rpos++ ]; 267} 268 269 270void 271qframebuffer_check_updates( void ) 272{ 273 int nn; 274 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 275 QFrameBuffer* q = framebuffer_fifo[nn]; 276 QFrameBufferExtra* extra = q->extra; 277 278 if (extra->pr_check) 279 extra->pr_check( extra->pr_opaque ); 280 } 281} 282 283void 284qframebuffer_pulse( void ) 285{ 286 int nn; 287 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 288 qframebuffer_poll(framebuffer_fifo[nn]); 289 } 290} 291 292void 293qframebuffer_invalidate_all( void ) 294{ 295 int nn; 296 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 297 QFrameBuffer* q = framebuffer_fifo[nn]; 298 QFrameBufferExtra* extra = q->extra; 299 300 if (extra->pr_invalidate) 301 extra->pr_invalidate( extra->pr_opaque ); 302 } 303} 304