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