From e3fdd075ed97085b4201cb0c79609633b19bddcc Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 2 Feb 2011 14:43:23 +0100 Subject: Move framebuffer.h to android/ The QFrameBuffer is no used by QEMU-specific code anymore so it's more logical to move it here. Change-Id: Id49ff53dd49648000e7543652d66f7c03881a8cb --- android/display-core.h | 2 +- android/display.h | 2 +- android/framebuffer.c | 294 ++++++++++++++++++++++++++++++++++++ android/framebuffer.h | 218 ++++++++++++++++++++++++++ android/main-ui.c | 2 +- android/main.c | 2 +- android/protocol/fb-updates-impl.h | 2 +- android/protocol/fb-updates-proxy.c | 2 +- android/skin/file.h | 2 +- android/skin/window.c | 2 +- 10 files changed, 520 insertions(+), 8 deletions(-) create mode 100644 android/framebuffer.c create mode 100644 android/framebuffer.h (limited to 'android') diff --git a/android/display-core.h b/android/display-core.h index 6204e56..edeccac 100644 --- a/android/display-core.h +++ b/android/display-core.h @@ -18,7 +18,7 @@ #ifndef _ANDROID_DISPLAY_CORE_H #define _ANDROID_DISPLAY_CORE_H -#include "framebuffer.h" +#include "android/framebuffer.h" #include "android/display.h" #include "android/protocol/fb-updates-proxy.h" diff --git a/android/display.h b/android/display.h index 111979c..4b9e908 100644 --- a/android/display.h +++ b/android/display.h @@ -13,7 +13,7 @@ #define _ANDROID_DISPLAY_H #include "console.h" -#include "framebuffer.h" +#include "android/framebuffer.h" extern void android_display_init(DisplayState* ds, QFrameBuffer* qfbuff); diff --git a/android/framebuffer.c b/android/framebuffer.c new file mode 100644 index 0000000..53c6a48 --- /dev/null +++ b/android/framebuffer.c @@ -0,0 +1,294 @@ +/* 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 "android/framebuffer.h" +#include +#include + +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; + QFrameBufferPollFunc fb_poll; + 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; + case QFRAME_BUFFER_RGBX_8888: + return width*4; + default: + return -1; + } +} + +static int +_get_bits_per_pixel(QFrameBufferFormat format) +{ + + switch (format) { + case QFRAME_BUFFER_RGB565: + return 16; + case QFRAME_BUFFER_RGBX_8888: + return 32; + default: + return -1; + } +} + +static int +_get_bytes_per_pixel(QFrameBufferFormat format) +{ + + switch (format) { + case QFRAME_BUFFER_RGB565: + return 2; + case QFRAME_BUFFER_RGBX_8888: + return 4; + default: + return -1; + } +} + +int +qframebuffer_init( QFrameBuffer* qfbuff, + int width, + int height, + int rotation, + QFrameBufferFormat format ) +{ + int pitch, bytes_per_pixel, bits_per_pixel; + + rotation &= 3; + + if (!qfbuff || width < 0 || height < 0) + return -1; + + pitch = _get_pitch( width, format ); + if (pitch < 0) + return -1; + + bits_per_pixel = _get_bits_per_pixel(format); + if (bits_per_pixel < 0) + return -1; + + bytes_per_pixel = _get_bytes_per_pixel(format); + if (bytes_per_pixel < 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; + qfbuff->bits_per_pixel = bits_per_pixel; + qfbuff->bytes_per_pixel = bytes_per_pixel; + + 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 = (int)(0.5 + 25.4 * qfbuff->width / x_dpi); + qfbuff->phys_height_mm = (int)(0.5 + 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, + QFrameBufferPollFunc fb_poll, + QFrameBufferDoneFunc fb_done ) +{ + QFrameBufferExtra* extra = qfbuff->extra; + + extra->fb_opaque = fb_opaque; + extra->fb_update = fb_update; + extra->fb_rotate = fb_rotate; + extra->fb_poll = fb_poll; + extra->fb_done = fb_done; +} + +void +qframebuffer_set_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 ); +} + +void +qframebuffer_poll( QFrameBuffer* qfbuff ) +{ + QFrameBufferExtra* extra = qfbuff->extra; + + if (extra && extra->fb_poll) + extra->fb_poll( extra->fb_opaque ); +} + + +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 ); + } +} diff --git a/android/framebuffer.h b/android/framebuffer.h new file mode 100644 index 0000000..9d1f626 --- /dev/null +++ b/android/framebuffer.h @@ -0,0 +1,218 @@ +/* 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. +*/ +#ifndef _ANDROID_FRAMEBUFFER_H_ +#define _ANDROID_FRAMEBUFFER_H_ + +/* A simple abstract interface to framebuffer displays. this is used to + * de-couple hardware emulation from final display. + * + * Each QFrameBuffer object holds a pixel buffer that is shared between + * one 'Producer' and one or more 'Clients' + * + * The Producer is in charge of updating the pixel buffer from the state + * of the emulated VRAM. A Client listens to updates to the pixel buffer, + * sent from the producer through qframebuffer_update()/_rotate() and + * displays them. + * + * note the 'rotation' field: it can take values 0, 1, 2 or 3 and corresponds + * to a rotation that must be performed to the pixels stored in the framebuffer + * *before* displaying them a value of 1 corresponds to a rotation of + * 90 clockwise-degrees, when the framebuffer is rotated 90 or 270 degrees, + * its width/height are swapped automatically + * + * phys_width_mm and phys_height_mm are physical dimensions expressed + * in millimeters + * + * More about the client/producer relationships below. + */ +typedef struct QFrameBuffer QFrameBuffer; + + +typedef enum { + QFRAME_BUFFER_NONE = 0, + QFRAME_BUFFER_RGB565 = 1, + QFRAME_BUFFER_RGBX_8888 = 2, + QFRAME_BUFFER_MAX /* do not remove */ +} QFrameBufferFormat; + +struct QFrameBuffer { + int width; /* width in pixels */ + int height; /* height in pixels */ + int pitch; /* bytes per line */ + int bits_per_pixel; /* bits per pixel */ + int bytes_per_pixel; /* bytes per pixel */ + int rotation; /* rotation to be applied when displaying */ + QFrameBufferFormat format; + void* pixels; /* pixel buffer */ + + int phys_width_mm; + int phys_height_mm; + + /* extra data that is handled by the framebuffer implementation */ + void* extra; + +}; + +/* the default dpi resolution of a typical framebuffer. this is an average + * between various prototypes being used during the development of the + * Android system... + */ +#define DEFAULT_FRAMEBUFFER_DPI 165 + + +/* initialize a framebuffer object and allocate its pixel buffer */ +/* this computes phys_width_mm and phys_height_mm assuming a 165 dpi screen */ +/* returns -1 in case of error, 0 otherwise */ +extern int +qframebuffer_init( QFrameBuffer* qfbuff, + int width, + int height, + int rotation, + QFrameBufferFormat format ); + +/* recompute phys_width_mm and phys_height_mm according to the emulated + * screen DPI settings */ +extern void +qframebuffer_set_dpi( QFrameBuffer* qfbuff, + int x_dpi, + int 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 */ +extern void +qframebuffer_set_mm( QFrameBuffer* qfbuff, + int width_mm, + int height_mm ); + +/* the Client::Update method is called to instruct a client that a given + * rectangle of the framebuffer pixels was updated and needs to be + * redrawn. + */ +typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y, + int w, int h ); + +/* the Client::Rotate method is called to instruct the client that a + * framebuffer's internal rotation has changed. This is the rotation + * that must be applied before displaying the pixels. + * + * Note that it is assumed that all framebuffer pixels have changed too + * so the client should call its Update method as well. + */ +typedef void (*QFrameBufferRotateFunc)( void* opaque, int rotation ); + +/* the Client::Poll method is called periodically to poll for input + * events and act on them. Putting this here is not 100% pure but + * make things simpler due to QEMU's weird architecture where the + * GUI timer drivers event polling. + */ +typedef void (*QFrameBufferPollFunc)( void* opaque ); + +/* the Client::Done func tells a client that a framebuffer object was freed. + * no more reference to its pixels should be done. + */ +typedef void (*QFrameBufferDoneFunc) ( void* opaque ); + +/* add one client to a given framebuffer. + * the current implementation only allows one client per frame-buffer, + * but we could allow more for various reasons (e.g. displaying the + * framebuffer + dispatching it through VNC at the same time) + */ +extern void +qframebuffer_add_client( QFrameBuffer* qfbuff, + void* fb_opaque, + QFrameBufferUpdateFunc fb_update, + QFrameBufferRotateFunc fb_rotate, + QFrameBufferPollFunc fb_poll, + QFrameBufferDoneFunc fb_done ); + +/* Producer::CheckUpdate is called to let the producer check the + * VRAM state (e.g. VRAM dirty pages) to see if anything changed since the + * last call to the method. When true, the method should call either + * qframebuffer_update() or qframebuffer_rotate() with the appropriate values. + */ +typedef void (*QFrameBufferCheckUpdateFunc)( void* opaque ); + +/* Producer::Invalidate tells the producer that the next call to + * CheckUpdate should act as if the whole content of VRAM had changed. + * this is normally done to force client initialization/refreshes. + */ +typedef void (*QFrameBufferInvalidateFunc) ( void* opaque ); + +/* the Producer::Detach method is used to tell the producer that the + * underlying QFrameBuffer object is about to be de-allocated. + */ +typedef void (*QFrameBufferDetachFunc) ( void* opaque ); + +/* set the producer of a given framebuffer */ +extern void +qframebuffer_set_producer( QFrameBuffer* qfbuff, + void* opaque, + QFrameBufferCheckUpdateFunc fb_check, + QFrameBufferInvalidateFunc fb_invalidate, + QFrameBufferDetachFunc fb_detach ); + +/* tell a client that a rectangle region has been updated in the framebuffer + * pixel buffer this is typically called from a Producer::CheckUpdate method + */ +extern void +qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h ); + +/* rotate the framebuffer (may swap width/height), and tell all clients. + * Should be called from a Producer::CheckUpdate method + */ +extern void +qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation ); + +extern void +qframebuffer_poll( QFrameBuffer* qfbuff ); + +/* finalize a framebuffer, release its pixel buffer. Should be called + * from the framebuffer object's owner + */ +extern void +qframebuffer_done( QFrameBuffer* qfbuff ); + + +/* this is called repeatedly by the emulator. for each registered framebuffer, + * call its producer's CheckUpdate method, if any. + */ +extern void +qframebuffer_check_updates( void ); + +/* this is called by the emulator. for each registered framebuffer, call + * its producer's Invalidate method, if any + */ +extern void +qframebuffer_invalidate_all( void ); + +/* + * to completely separate the implementation of clients, producers, and skins, + * we use a simple global FIFO list of QFrameBuffer objects. + * + * qframebuffer_fifo_add() is typically called by the emulator initialization + * depending on the emulated device's configuration + * + * qframebuffer_fifo_get() is typically called by a hardware framebuffer + * emulation. + */ + +/* add a new constructed frame buffer object to our global list */ +extern void +qframebuffer_fifo_add( QFrameBuffer* qfbuff ); + +/* retrieve a frame buffer object from the global FIFO list */ +extern QFrameBuffer* +qframebuffer_fifo_get( void ); + +/* */ + +#endif /* _ANDROID_FRAMEBUFFER_H_ */ diff --git a/android/main-ui.c b/android/main-ui.c index 051f3e8..9981b76 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -59,7 +59,7 @@ #include "android/protocol/ui-commands-impl.h" #include "android/protocol/attach-ui-impl.h" -#include "framebuffer.h" +#include "android/framebuffer.h" #include "iolooper.h" AndroidRotation android_framebuffer_rotation; diff --git a/android/main.c b/android/main.c index 64fe617..e38c0e3 100644 --- a/android/main.c +++ b/android/main.c @@ -53,7 +53,7 @@ #include "android/snapshot.h" -#include "framebuffer.h" +#include "android/framebuffer.h" #include "iolooper.h" AndroidRotation android_framebuffer_rotation; diff --git a/android/protocol/fb-updates-impl.h b/android/protocol/fb-updates-impl.h index 2572b5e..c4dd2e0 100644 --- a/android/protocol/fb-updates-impl.h +++ b/android/protocol/fb-updates-impl.h @@ -19,7 +19,7 @@ #define _ANDROID_FRAMEBUFFER_UI_H #include "console.h" -#include "framebuffer.h" +#include "android/framebuffer.h" #include "android/looper.h" #include "android/async-utils.h" diff --git a/android/protocol/fb-updates-proxy.c b/android/protocol/fb-updates-proxy.c index fee1195..359c942 100644 --- a/android/protocol/fb-updates-proxy.c +++ b/android/protocol/fb-updates-proxy.c @@ -16,7 +16,7 @@ */ #include "console.h" -#include "framebuffer.h" +#include "android/framebuffer.h" #include "android/looper.h" #include "android/display-core.h" #include "android/async-utils.h" diff --git a/android/skin/file.h b/android/skin/file.h index 6f88063..4e3a8fc 100644 --- a/android/skin/file.h +++ b/android/skin/file.h @@ -14,7 +14,7 @@ #include "android/skin/image.h" #include "android/config.h" -#include "framebuffer.h" +#include "android/framebuffer.h" /** Layout **/ diff --git a/android/skin/window.c b/android/skin/window.c index c2d0bf4..2755763 100644 --- a/android/skin/window.c +++ b/android/skin/window.c @@ -21,7 +21,7 @@ #include "user-events.h" #include -#include "framebuffer.h" +#include "android/framebuffer.h" /* when shrinking, we reduce the pixel ratio by this fixed amount */ #define SHRINK_SCALE 0.6 -- cgit v1.1