aboutsummaryrefslogtreecommitdiffstats
path: root/framebuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'framebuffer.c')
-rw-r--r--framebuffer.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/framebuffer.c b/framebuffer.c
new file mode 100644
index 0000000..e7c955f
--- /dev/null
+++ b/framebuffer.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "framebuffer.h"
+#include <memory.h>
+#include <stdlib.h>
+
+typedef struct {
+ /* client fields, these correspond to code that waits for updates before displaying them */
+ /* at the moment, only one client is supported */
+ void* fb_opaque;
+ QFrameBufferUpdateFunc fb_update;
+ QFrameBufferRotateFunc fb_rotate;
+ QFrameBufferDoneFunc fb_done;
+
+ void* pr_opaque;
+ QFrameBufferCheckUpdateFunc pr_check;
+ QFrameBufferInvalidateFunc pr_invalidate;
+ QFrameBufferDetachFunc pr_detach;
+
+} QFrameBufferExtra;
+
+
+static int
+_get_pitch( int width, QFrameBufferFormat format )
+{
+
+ switch (format) {
+ case QFRAME_BUFFER_RGB565:
+ return width*2;
+ default:
+ return -1;
+ }
+}
+
+
+int
+qframebuffer_init( QFrameBuffer* qfbuff,
+ int width,
+ int height,
+ int rotation,
+ QFrameBufferFormat format )
+{
+ int pitch;
+
+ rotation &= 3;
+
+ if (!qfbuff || width < 0 || height < 0)
+ return -1;
+
+ pitch = _get_pitch( width, format );
+ if (pitch < 0)
+ return -1;
+
+ memset( qfbuff, 0, sizeof(*qfbuff) );
+
+ qfbuff->extra = calloc( 1, sizeof(QFrameBufferExtra) );
+ if (qfbuff->extra == NULL)
+ return -1;
+
+ qfbuff->pixels = calloc( pitch, height );
+ if (qfbuff->pixels == NULL && (height > 0 && pitch > 0)) {
+ free( qfbuff->extra );
+ return -1;
+ }
+
+ qfbuff->width = width;
+ qfbuff->height = height;
+ qfbuff->pitch = pitch;
+ qfbuff->format = format;
+
+ qframebuffer_set_dpi( qfbuff, DEFAULT_FRAMEBUFFER_DPI, DEFAULT_FRAMEBUFFER_DPI );
+ return 0;
+}
+
+
+void
+qframebuffer_set_dpi( QFrameBuffer* qfbuff,
+ int x_dpi,
+ int y_dpi )
+{
+ /* dpi = dots / inch
+ ** inch = dots / dpi
+ ** mm / 25.4 = dots / dpi
+ ** mm = (dots * 25.4)/dpi
+ */
+ qfbuff->phys_width_mm = 25.4 * qfbuff->width / x_dpi;
+ qfbuff->phys_height_mm = 25.4 * qfbuff->height / y_dpi;
+}
+
+/* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */
+/* in millimeters. for the record 1 inch = 25.4 mm */
+void
+qframebuffer_set_mm( QFrameBuffer* qfbuff,
+ int width_mm,
+ int height_mm )
+{
+ qfbuff->phys_width_mm = width_mm;
+ qfbuff->phys_height_mm = height_mm;
+}
+
+void
+qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if (extra->fb_update)
+ extra->fb_update( extra->fb_opaque, x, y, w, h );
+}
+
+
+void
+qframebuffer_add_client( QFrameBuffer* qfbuff,
+ void* fb_opaque,
+ QFrameBufferUpdateFunc fb_update,
+ QFrameBufferRotateFunc fb_rotate,
+ QFrameBufferDoneFunc fb_done )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ extra->fb_opaque = fb_opaque;
+ extra->fb_update = fb_update;
+ extra->fb_rotate = fb_rotate;
+ extra->fb_done = fb_done;
+}
+
+void
+qframebuffer_add_producer( QFrameBuffer* qfbuff,
+ void* opaque,
+ QFrameBufferCheckUpdateFunc pr_check,
+ QFrameBufferInvalidateFunc pr_invalidate,
+ QFrameBufferDetachFunc pr_detach )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ extra->pr_opaque = opaque;
+ extra->pr_check = pr_check;
+ extra->pr_invalidate = pr_invalidate;
+ extra->pr_detach = pr_detach;
+}
+
+
+void
+qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if ((rotation ^ qfbuff->rotation) & 1) {
+ /* swap width and height if new rotation requires it */
+ int temp = qfbuff->width;
+ qfbuff->width = qfbuff->height;
+ qfbuff->height = temp;
+ qfbuff->pitch = _get_pitch( qfbuff->width, qfbuff->format );
+
+ temp = qfbuff->phys_width_mm;
+ qfbuff->phys_width_mm = qfbuff->phys_height_mm;
+ qfbuff->phys_height_mm = temp;
+ }
+ qfbuff->rotation = rotation;
+
+ if (extra->fb_rotate)
+ extra->fb_rotate( extra->fb_opaque, rotation );
+}
+
+
+extern void
+qframebuffer_done( QFrameBuffer* qfbuff )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if (extra) {
+ if (extra->pr_detach)
+ extra->pr_detach( extra->pr_opaque );
+
+ if (extra->fb_done)
+ extra->fb_done( extra->fb_opaque );
+ }
+
+ free( qfbuff->pixels );
+ free( qfbuff->extra );
+ memset( qfbuff, 0, sizeof(*qfbuff) );
+}
+
+
+#define MAX_FRAME_BUFFERS 8
+
+static QFrameBuffer* framebuffer_fifo[ MAX_FRAME_BUFFERS ];
+static int framebuffer_fifo_rpos;
+static int framebuffer_fifo_count;
+
+void
+qframebuffer_fifo_add( QFrameBuffer* qfbuff )
+{
+ if (framebuffer_fifo_count >= MAX_FRAME_BUFFERS)
+ return;
+
+ framebuffer_fifo[ framebuffer_fifo_count++ ] = qfbuff;
+}
+
+
+QFrameBuffer*
+qframebuffer_fifo_get( void )
+{
+ if (framebuffer_fifo_rpos >= framebuffer_fifo_count)
+ return NULL;
+
+ return framebuffer_fifo[ framebuffer_fifo_rpos++ ];
+}
+
+
+void
+qframebuffer_check_updates( void )
+{
+ int nn;
+ for (nn = 0; nn < framebuffer_fifo_count; nn++) {
+ QFrameBuffer* q = framebuffer_fifo[nn];
+ QFrameBufferExtra* extra = q->extra;
+
+ if (extra->pr_check)
+ extra->pr_check( extra->pr_opaque );
+ }
+}
+
+void
+qframebuffer_invalidate_all( void )
+{
+ int nn;
+ for (nn = 0; nn < framebuffer_fifo_count; nn++) {
+ QFrameBuffer* q = framebuffer_fifo[nn];
+ QFrameBufferExtra* extra = q->extra;
+
+ if (extra->pr_invalidate)
+ extra->pr_invalidate( extra->pr_opaque );
+ }
+}