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 "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 QFrameBufferDoneFunc fb_done; 23 24 void* pr_opaque; 25 QFrameBufferCheckUpdateFunc pr_check; 26 QFrameBufferInvalidateFunc pr_invalidate; 27 QFrameBufferDetachFunc pr_detach; 28 29 } QFrameBufferExtra; 30 31 32 static int 33 _get_pitch( int width, QFrameBufferFormat format ) 34 { 35 36 switch (format) { 37 case QFRAME_BUFFER_RGB565: 38 return width*2; 39 default: 40 return -1; 41 } 42 } 43 44 45 int 46 qframebuffer_init( QFrameBuffer* qfbuff, 47 int width, 48 int height, 49 int rotation, 50 QFrameBufferFormat format ) 51 { 52 int pitch; 53 54 rotation &= 3; 55 56 if (!qfbuff || width < 0 || height < 0) 57 return -1; 58 59 pitch = _get_pitch( width, format ); 60 if (pitch < 0) 61 return -1; 62 63 memset( qfbuff, 0, sizeof(*qfbuff) ); 64 65 qfbuff->extra = calloc( 1, sizeof(QFrameBufferExtra) ); 66 if (qfbuff->extra == NULL) 67 return -1; 68 69 qfbuff->pixels = calloc( pitch, height ); 70 if (qfbuff->pixels == NULL && (height > 0 && pitch > 0)) { 71 free( qfbuff->extra ); 72 return -1; 73 } 74 75 qfbuff->width = width; 76 qfbuff->height = height; 77 qfbuff->pitch = pitch; 78 qfbuff->format = format; 79 80 qframebuffer_set_dpi( qfbuff, DEFAULT_FRAMEBUFFER_DPI, DEFAULT_FRAMEBUFFER_DPI ); 81 return 0; 82 } 83 84 85 void 86 qframebuffer_set_dpi( QFrameBuffer* qfbuff, 87 int x_dpi, 88 int y_dpi ) 89 { 90 /* dpi = dots / inch 91 ** inch = dots / dpi 92 ** mm / 25.4 = dots / dpi 93 ** mm = (dots * 25.4)/dpi 94 */ 95 qfbuff->phys_width_mm = (int)(0.5 + 25.4 * qfbuff->width / x_dpi); 96 qfbuff->phys_height_mm = (int)(0.5 + 25.4 * qfbuff->height / y_dpi); 97 } 98 99 /* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */ 100 /* in millimeters. for the record 1 inch = 25.4 mm */ 101 void 102 qframebuffer_set_mm( QFrameBuffer* qfbuff, 103 int width_mm, 104 int height_mm ) 105 { 106 qfbuff->phys_width_mm = width_mm; 107 qfbuff->phys_height_mm = height_mm; 108 } 109 110 void 111 qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h ) 112 { 113 QFrameBufferExtra* extra = qfbuff->extra; 114 115 if (extra->fb_update) 116 extra->fb_update( extra->fb_opaque, x, y, w, h ); 117 } 118 119 120 void 121 qframebuffer_add_client( QFrameBuffer* qfbuff, 122 void* fb_opaque, 123 QFrameBufferUpdateFunc fb_update, 124 QFrameBufferRotateFunc fb_rotate, 125 QFrameBufferDoneFunc fb_done ) 126 { 127 QFrameBufferExtra* extra = qfbuff->extra; 128 129 extra->fb_opaque = fb_opaque; 130 extra->fb_update = fb_update; 131 extra->fb_rotate = fb_rotate; 132 extra->fb_done = fb_done; 133 } 134 135 void 136 qframebuffer_set_producer( QFrameBuffer* qfbuff, 137 void* opaque, 138 QFrameBufferCheckUpdateFunc pr_check, 139 QFrameBufferInvalidateFunc pr_invalidate, 140 QFrameBufferDetachFunc pr_detach ) 141 { 142 QFrameBufferExtra* extra = qfbuff->extra; 143 144 extra->pr_opaque = opaque; 145 extra->pr_check = pr_check; 146 extra->pr_invalidate = pr_invalidate; 147 extra->pr_detach = pr_detach; 148 } 149 150 151 void 152 qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation ) 153 { 154 QFrameBufferExtra* extra = qfbuff->extra; 155 156 if ((rotation ^ qfbuff->rotation) & 1) { 157 /* swap width and height if new rotation requires it */ 158 int temp = qfbuff->width; 159 qfbuff->width = qfbuff->height; 160 qfbuff->height = temp; 161 qfbuff->pitch = _get_pitch( qfbuff->width, qfbuff->format ); 162 163 temp = qfbuff->phys_width_mm; 164 qfbuff->phys_width_mm = qfbuff->phys_height_mm; 165 qfbuff->phys_height_mm = temp; 166 } 167 qfbuff->rotation = rotation; 168 169 if (extra->fb_rotate) 170 extra->fb_rotate( extra->fb_opaque, rotation ); 171 } 172 173 174 extern void 175 qframebuffer_done( QFrameBuffer* qfbuff ) 176 { 177 QFrameBufferExtra* extra = qfbuff->extra; 178 179 if (extra) { 180 if (extra->pr_detach) 181 extra->pr_detach( extra->pr_opaque ); 182 183 if (extra->fb_done) 184 extra->fb_done( extra->fb_opaque ); 185 } 186 187 free( qfbuff->pixels ); 188 free( qfbuff->extra ); 189 memset( qfbuff, 0, sizeof(*qfbuff) ); 190 } 191 192 193 #define MAX_FRAME_BUFFERS 8 194 195 static QFrameBuffer* framebuffer_fifo[ MAX_FRAME_BUFFERS ]; 196 static int framebuffer_fifo_rpos; 197 static int framebuffer_fifo_count; 198 199 void 200 qframebuffer_fifo_add( QFrameBuffer* qfbuff ) 201 { 202 if (framebuffer_fifo_count >= MAX_FRAME_BUFFERS) 203 return; 204 205 framebuffer_fifo[ framebuffer_fifo_count++ ] = qfbuff; 206 } 207 208 209 QFrameBuffer* 210 qframebuffer_fifo_get( void ) 211 { 212 if (framebuffer_fifo_rpos >= framebuffer_fifo_count) 213 return NULL; 214 215 return framebuffer_fifo[ framebuffer_fifo_rpos++ ]; 216 } 217 218 219 void 220 qframebuffer_check_updates( void ) 221 { 222 int nn; 223 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 224 QFrameBuffer* q = framebuffer_fifo[nn]; 225 QFrameBufferExtra* extra = q->extra; 226 227 if (extra->pr_check) 228 extra->pr_check( extra->pr_opaque ); 229 } 230 } 231 232 void 233 qframebuffer_invalidate_all( void ) 234 { 235 int nn; 236 for (nn = 0; nn < framebuffer_fifo_count; nn++) { 237 QFrameBuffer* q = framebuffer_fifo[nn]; 238 QFrameBufferExtra* extra = q->extra; 239 240 if (extra->pr_invalidate) 241 extra->pr_invalidate( extra->pr_opaque ); 242 } 243 } 244