blob: b9b968eb9be3db9dacf61160182fba394046381b [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* 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*/
David 'Digit' Turnere3fdd072011-02-02 14:43:23 +010012#include "android/framebuffer.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080013#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;
David 'Digit' Turner055ae422010-07-27 11:34:16 -070022 QFrameBufferPollFunc fb_poll;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080023 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;
David 'Digit' Turner97d795c2011-01-16 01:42:37 +010040 case QFRAME_BUFFER_RGBX_8888:
41 return width*4;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080042 default:
43 return -1;
44 }
45}
46
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080047static int
48_get_bits_per_pixel(QFrameBufferFormat format)
49{
50
51 switch (format) {
52 case QFRAME_BUFFER_RGB565:
53 return 16;
David 'Digit' Turner97d795c2011-01-16 01:42:37 +010054 case QFRAME_BUFFER_RGBX_8888:
55 return 32;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080056 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;
David 'Digit' Turner97d795c2011-01-16 01:42:37 +010068 case QFRAME_BUFFER_RGBX_8888:
69 return 4;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080070 default:
71 return -1;
72 }
73}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080074
75int
76qframebuffer_init( QFrameBuffer* qfbuff,
77 int width,
78 int height,
79 int rotation,
80 QFrameBufferFormat format )
81{
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080082 int pitch, bytes_per_pixel, bits_per_pixel;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080083
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
David 'Digit' Turner97d795c2011-01-16 01:42:37 +010093 bits_per_pixel = _get_bits_per_pixel(format);
94 if (bits_per_pixel < 0)
95 return -1;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080096
David 'Digit' Turner97d795c2011-01-16 01:42:37 +010097 bytes_per_pixel = _get_bytes_per_pixel(format);
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -080098 if (bytes_per_pixel < 0)
99 return -1;
100
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800101 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;
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800117 qfbuff->bits_per_pixel = bits_per_pixel;
118 qfbuff->bytes_per_pixel = bytes_per_pixel;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800119
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,
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700165 QFrameBufferPollFunc fb_poll,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800166 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;
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700173 extra->fb_poll = fb_poll;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800174 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
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700215void
216qframebuffer_poll( QFrameBuffer* qfbuff )
217{
218 QFrameBufferExtra* extra = qfbuff->extra;
219
David 'Digit' Turner73f31662010-10-13 16:52:14 +0200220 if (extra && extra->fb_poll)
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700221 extra->fb_poll( extra->fb_opaque );
222}
223
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800224
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
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100284qframebuffer_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
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800293qframebuffer_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}