Home | History | Annotate | Download | only in android
      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