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 16 typedef 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 33 static 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 47 static 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 61 static 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 75 int 76 qframebuffer_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 125 void 126 qframebuffer_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 */ 141 void 142 qframebuffer_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 150 void 151 qframebuffer_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 160 void 161 qframebuffer_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 177 void 178 qframebuffer_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 193 void 194 qframebuffer_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 215 void 216 qframebuffer_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 225 extern void 226 qframebuffer_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 246 static QFrameBuffer* framebuffer_fifo[ MAX_FRAME_BUFFERS ]; 247 static int framebuffer_fifo_rpos; 248 static int framebuffer_fifo_count; 249 250 void 251 qframebuffer_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 260 QFrameBuffer* 261 qframebuffer_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 270 void 271 qframebuffer_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 283 void 284 qframebuffer_pulse( void ) 285 { 286 int nn; 287 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 288 qframebuffer_poll(framebuffer_fifo[nn]); 289 } 290 } 291 292 void 293 qframebuffer_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