diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c
index 0bac0fde..91b86616 100644
--- a/drivers/multiple/Win32/gdisp_lld.c
+++ b/drivers/multiple/Win32/gdisp_lld.c
@@ -17,6 +17,13 @@
 
 #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/
 
+#include "gdisp/lld/gdisp_lld.h"
+
+// Declare our driver object
+GDISPDriver	GDISP_Win32;
+
+#define GC	(&GDISP_Win32)
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -45,9 +52,6 @@
 	#include "ginput/lld/mouse.h"
 #endif
 
-/* Include the emulation code for things we don't support */
-#include "gdisp/lld/emulation.c"
-
 /*===========================================================================*/
 /* Driver local routines    .                                                */
 /*===========================================================================*/
@@ -329,86 +333,59 @@ bool_t gdisp_lld_init(void) {
 		Sleep(1);
 
 	/* Initialise the GDISP structure to match */
-	GDISP.Orientation = GDISP_ROTATE_0;
-	GDISP.Powermode = powerOn;
-	GDISP.Backlight = 100;
-	GDISP.Contrast = 50;
-	GDISP.Width = wWidth;
-	GDISP.Height = wHeight;
-	#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
-		GDISP.clipx0 = 0;
-		GDISP.clipy0 = 0;
-		GDISP.clipx1 = GDISP.Width;
-		GDISP.clipy1 = GDISP.Height;
-	#endif
+	GC->g.Orientation = GDISP_ROTATE_0;
+	GC->g.Powermode = powerOn;
+	GC->g.Backlight = 100;
+	GC->g.Contrast = 50;
+	GC->g.Width = wWidth;
+	GC->g.Height = wHeight;
 	return TRUE;
 }
 
-/**
- * @brief   Draws a pixel on the display.
- *
- * @param[in] x        X location of the pixel
- * @param[in] y        Y location of the pixel
- * @param[in] color    The color of the pixel
- *
- * @notapi
- */
-void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
-	HDC dc;
-	#if WIN32_USE_MSG_REDRAW
-		RECT	rect;
-	#endif
-	#if GDISP_NEED_CONTROL
-		coord_t	t;
-	#endif
-
-	#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
-		// Clip pre orientation change
-		if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
-	#endif
-
-	#if GDISP_NEED_CONTROL
-		switch(GDISP.Orientation) {
-		case GDISP_ROTATE_0:
-			break;
-		case GDISP_ROTATE_90:
-			t = GDISP.Height - 1 - y;
-			y = x;
-			x = t;
-			break;
-		case GDISP_ROTATE_180:
-			x = GDISP.Width - 1 - x;
-			y = GDISP.Height - 1 - y;
-			break;
-		case GDISP_ROTATE_270:
-			t = GDISP.Width - 1 - x;
-			x = y;
-			y = t;
-			break;
-		}
-	#endif
+#if GDISP_HARDWARE_DRAWPIXEL
+	void gdisp_lld_draw_pixel(void) {
+		HDC			dcScreen;
+		int			x, y;
+		COLORREF	color;
 	
-	// Draw the pixel in the buffer
-	color = COLOR2BGR(color);
-	SetPixel(dcBuffer, x, y, color);
+		color = COLOR2BGR(GC->p.color);
 	
-	#if WIN32_USE_MSG_REDRAW
-		rect.left = x; rect.right = x+1;
-		rect.top = y; rect.bottom = y+1;
-		InvalidateRect(winRootWindow, &rect, FALSE);
-		UpdateWindow(winRootWindow);
-	#else
-		// Draw the pixel again directly on the screen.
-		// This is cheaper than invalidating a single pixel in the window
-		dc = GetDC(winRootWindow);
-		SetPixel(dc, x, y, color);
-		ReleaseDC(winRootWindow, dc);
-	#endif
-}
+		#if GDISP_NEED_CONTROL
+			switch(GC->g.Orientation) {
+			case GDISP_ROTATE_0:
+				x = GC->p.x;
+				y = GC->p.y;
+				break;
+			case GDISP_ROTATE_90:
+				x = GC->g.Height - 1 - GC->p.y;
+				y = GC->p.x;
+				break;
+			case GDISP_ROTATE_180:
+				x = GC->g.Width - 1 - GC->p.x;
+				y = GC->g.Height - 1 - GC->p.y;
+				break;
+			case GDISP_ROTATE_270:
+				x = GC->p.y;
+				y = GC->g.Width - 1 - GC->p.x;
+				break;
+			}
+		#else
+			x = GC->p.x;
+			y = GC->p.y;
+		#endif
+
+		// Draw the pixel on the screen and in the buffer.
+		dcScreen = GetDC(winRootWindow);
+		SetPixel(dcScreen, x, y, color);
+		SetPixel(dcBuffer, x, y, color);
+		ReleaseDC(winRootWindow, dcScreen);
+	}
+#endif
 
 /* ---- Optional Routines ---- */
 
-#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__)
+#if 0
+#if GDISP_HARDWARE_LINES
 	/**
 	 * @brief   Draw a line.
 	 * @note    Optional - The high level driver can emulate using software.
@@ -439,57 +416,57 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 		#endif
 
 		#if GDISP_NEED_CONTROL
-			switch(GDISP.Orientation) {
+			switch(GC->g.Orientation) {
 			case GDISP_ROTATE_0:
 				#if GDISP_NEED_CLIP
 					// Clip post orientation change
-					if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height)
-						clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1);
+					if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height)
+						clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1);
 				#endif
 				break;
 			case GDISP_ROTATE_90:
-				t = GDISP.Height - 1 - y0;
+				t = GC->g.Height - 1 - y0;
 				y0 = x0;
 				x0 = t;
-				t = GDISP.Height - 1 - y1;
+				t = GC->g.Height - 1 - y1;
 				y1 = x1;
 				x1 = t;
 				#if GDISP_NEED_CLIP
 					// Clip post orientation change
-					if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height)
-						clip = CreateRectRgn(GDISP.Height-1-GDISP.clipy1, GDISP.clipx0, GDISP.Height-1-GDISP.clipy0, GDISP.clipx1);
+					if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height)
+						clip = CreateRectRgn(GC->g.Height-1-GC->g.clipy1, GC->g.clipx0, GC->g.Height-1-GC->g.clipy0, GC->g.clipx1);
 				#endif
 				break;
 			case GDISP_ROTATE_180:
-				x0 = GDISP.Width - 1 - x0;
-				y0 = GDISP.Height - 1 - y0;
-				x1 = GDISP.Width - 1 - x1;
-				y1 = GDISP.Height - 1 - y1;
+				x0 = GC->g.Width - 1 - x0;
+				y0 = GC->g.Height - 1 - y0;
+				x1 = GC->g.Width - 1 - x1;
+				y1 = GC->g.Height - 1 - y1;
 				#if GDISP_NEED_CLIP
 					// Clip post orientation change
-					if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height)
-						clip = CreateRectRgn(GDISP.Width-1-GDISP.clipx1, GDISP.Height-1-GDISP.clipy1, GDISP.Width-1-GDISP.clipx0, GDISP.Height-1-GDISP.clipy0);
+					if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height)
+						clip = CreateRectRgn(GC->g.Width-1-GC->g.clipx1, GC->g.Height-1-GC->g.clipy1, GC->g.Width-1-GC->g.clipx0, GC->g.Height-1-GC->g.clipy0);
 				#endif
 				break;
 			case GDISP_ROTATE_270:
-				t = GDISP.Width - 1 - x0;
+				t = GC->g.Width - 1 - x0;
 				x0 = y0;
 				y0 = t;
-				t = GDISP.Width - 1 - x1;
+				t = GC->g.Width - 1 - x1;
 				x1 = y1;
 				y1 = t;
 				#if GDISP_NEED_CLIP
 					// Clip post orientation change
-					if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height)
-						clip = CreateRectRgn(GDISP.clipy0, GDISP.Width-1-GDISP.clipx1, GDISP.clipy1, GDISP.Width-1-GDISP.clipx0);
+					if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height)
+						clip = CreateRectRgn(GC->g.clipy0, GC->g.Width-1-GC->g.clipx1, GC->g.clipy1, GC->g.Width-1-GC->g.clipx0);
 				#endif
 				break;
 			}
 		#else
 			#if GDISP_NEED_CLIP
 				clip = NULL;
-				if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height)
-					clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1);
+				if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height)
+					clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1);
 			#endif
 		#endif
 	
@@ -535,85 +512,58 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 		}
 	}
 #endif
+#endif
 
-#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
-	/**
-	 * @brief   Fill an area with a color.
-	 * @note    Optional - The high level driver can emulate using software.
-	 *
-	 * @param[in] x, y     The start filled area
-	 * @param[in] cx, cy   The width and height to be filled
-	 * @param[in] color    The color of the fill
-	 *
-	 * @notapi
-	 */
-	void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-		HDC dc;
-		RECT rect;
-		HBRUSH hbr;
-
-		#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
-			// Clip pre orientation change
-			if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; }
-			if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; }
-			if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
-			if (x+cx > GDISP.clipx1)	cx = GDISP.clipx1 - x;
-			if (y+cy > GDISP.clipy1)	cy = GDISP.clipy1 - y;
-		#endif
+#if GDISP_HARDWARE_FILLS
+	void gdisp_lld_fill_area(void) {
+		HDC			dcScreen;
+		RECT		rect;
+		HBRUSH		hbr;
+		COLORREF	color;
 
+		color = COLOR2BGR(GC->p.color);
 		#if GDISP_NEED_CONTROL
-			switch(GDISP.Orientation) {
+			switch(GC->g.Orientation) {
 			case GDISP_ROTATE_0:
-				rect.top = y;
-				rect.bottom = rect.top+cy;
-				rect.left = x;
-				rect.right = rect.left+cx;
+				rect.top = GC->p.y;
+				rect.bottom = rect.top + GC->p.cy;
+				rect.left = GC->p.x;
+				rect.right = rect.left + GC->p.cx;
 				break;
 			case GDISP_ROTATE_90:
-				rect.top = x;
-				rect.bottom = rect.top+cx;
-				rect.right = GDISP.Height - y;
-				rect.left = rect.right-cy;
+				rect.top = GC->p.x;
+				rect.bottom = rect.top + GC->p.cx;
+				rect.right = GC->g.Height - GC->p.y;
+				rect.left = rect.right - GC->p.cy;
 				break;
 			case GDISP_ROTATE_180:
-				rect.bottom = GDISP.Height - y;
-				rect.top = rect.bottom-cy;
-				rect.right = GDISP.Width - x;
-				rect.left = rect.right-cx;
+				rect.bottom = GC->g.Height - GC->p.y;
+				rect.top = rect.bottom - GC->p.cy;
+				rect.right = GC->g.Width - GC->p.x;
+				rect.left = rect.right - GC->p.cx;
 				break;
 			case GDISP_ROTATE_270:
-				rect.bottom = GDISP.Width - x;
-				rect.top = rect.bottom-cx;
-				rect.left = y;
-				rect.right = rect.left+cy;
+				rect.bottom = GC->g.Width - GC->p.x;
+				rect.top = rect.bottom - GC->p.cx;
+				rect.left = GC->p.y;
+				rect.right = rect.left + GC->p.cy;
 				break;
 			}
 		#else
-			rect.top = y;
-			rect.bottom = rect.top+cy;
-			rect.left = x;
-			rect.right = rect.left+cx;
+			rect.top = GC->p.y;
+			rect.bottom = rect.top + GC->p.cy;
+			rect.left = GC->p.x;
+			rect.right = rect.left + GC->p.cx;
 		#endif
 
-		color = COLOR2BGR(color);
 		hbr = CreateSolidBrush(color);
 
-		if (hbr) {
-			// Fill the area
-			FillRect(dcBuffer, &rect, hbr);
+		dcScreen = GetDC(winRootWindow);
+		FillRect(dcScreen, &rect, hbr);
+		FillRect(dcBuffer, &rect, hbr);
+		ReleaseDC(winRootWindow, dcScreen);
 
-			#if WIN32_USE_MSG_REDRAW
-				InvalidateRect(winRootWindow, &rect, FALSE);
-				UpdateWindow(winRootWindow);
-			#else
-				// Filling the area directly on the screen is likely to be cheaper than invalidating it
-				dc = GetDC(winRootWindow);
-				FillRect(dc, &rect, hbr);
-				ReleaseDC(winRootWindow, dc);
-			#endif
-
-			DeleteObject(hbr);
-		}
+		DeleteObject(hbr);
 	}
 #endif
 
@@ -626,7 +576,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 		coord_t	i, j;
 
 		// Shortcut.
-		if (GDISP.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx)
+		if (GC->g.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx)
 			return (pixel_t *)buffer;
 		
 		// Allocate the destination buffer
@@ -635,7 +585,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 			return 0;
 		
 		// Copy the bits we need
-		switch(GDISP.Orientation) {
+		switch(GC->g.Orientation) {
 		case GDISP_ROTATE_0:
 			for(dst = dstbuf, src = buffer+srcx, j = 0; j < cy; j++)
 				for(i = 0; i < cx; i++, src += srccx - cx)
@@ -665,7 +615,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 	}
 #endif
 	
-#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
+#if GDISP_HARDWARE_BITFILLS
 	/**
 	 * @brief   Fill an area with a bitmap.
 	 * @note    Optional - The high level driver can emulate using software.
@@ -687,12 +637,12 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 
 		#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
 			// Clip pre orientation change
-			if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; }
-			if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; }
+			if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; srcx += GC->g.clipx0 - x; x = GC->g.clipx0; }
+			if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; srcy += GC->g.clipy0 - y; y = GC->g.clipy0; }
 			if (srcx+cx > srccx)		cx = srccx - srcx;
-			if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
-			if (x+cx > GDISP.clipx1)	cx = GDISP.clipx1 - x;
-			if (y+cy > GDISP.clipy1)	cy = GDISP.clipy1 - y;
+			if (cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return;
+			if (x+cx > GC->g.clipx1)	cx = GC->g.clipx1 - x;
+			if (y+cy > GC->g.clipy1)	cy = GC->g.clipy1 - y;
 		#endif
 
 		// Make everything relative to the start of the line
@@ -719,7 +669,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 			srcimg = rotateimg(cx, cy, srcx, srccx, buffer);
 			if (!srcimg) return;
 			
-			switch(GDISP.Orientation) {
+			switch(GC->g.Orientation) {
 			case GDISP_ROTATE_0:
 				bmpInfo.bV4Width = cx;
 				bmpInfo.bV4Height = -cy; /* top-down image */
@@ -733,21 +683,21 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 				bmpInfo.bV4Height = -cx; /* top-down image */
 				rect.top = x;
 				rect.bottom = rect.top+cx;
-				rect.right = GDISP.Height - y;
+				rect.right = GC->g.Height - y;
 				rect.left = rect.right-cy;
 				break;
 			case GDISP_ROTATE_180:
 				bmpInfo.bV4Width = cx;
 				bmpInfo.bV4Height = -cy; /* top-down image */
-				rect.bottom = GDISP.Height - y;
+				rect.bottom = GC->g.Height - y;
 				rect.top = rect.bottom-cy;
-				rect.right = GDISP.Width - x;
+				rect.right = GC->g.Width - x;
 				rect.left = rect.right-cx;
 				break;
 			case GDISP_ROTATE_270:
 				bmpInfo.bV4Width = cy;
 				bmpInfo.bV4Height = -cx; /* top-down image */
-				rect.bottom = GDISP.Width - x;
+				rect.bottom = GC->g.Width - x;
 				rect.top = rect.bottom-cx;
 				rect.left = y;
 				rect.right = rect.left+cy;
@@ -793,24 +743,24 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 
 		#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
 			// Clip pre orientation change
-			if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0;
+			if (x < 0 || x >= GC->g.Width || y < 0 || y >= GC->g.Height) return 0;
 		#endif
 
 		#if GDISP_NEED_CONTROL
-			switch(GDISP.Orientation) {
+			switch(GC->g.Orientation) {
 			case GDISP_ROTATE_0:
 				break;
 			case GDISP_ROTATE_90:
-				t = GDISP.Height - 1 - y;
+				t = GC->g.Height - 1 - y;
 				y = x;
 				x = t;
 				break;
 			case GDISP_ROTATE_180:
-				x = GDISP.Width - 1 - x;
-				y = GDISP.Height - 1 - y;
+				x = GC->g.Width - 1 - x;
+				y = GC->g.Height - 1 - y;
 				break;
 			case GDISP_ROTATE_270:
-				t = GDISP.Width - 1 - x;
+				t = GC->g.Width - 1 - x;
 				x = y;
 				y = t;
 				break;
@@ -842,11 +792,11 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 		
 		#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
 			// Clip pre orientation change
-			if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; }
-			if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; }
-			if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return;
-			if (x+cx > GDISP.clipx1)	cx = GDISP.clipx1 - x;
-			if (y+cy > GDISP.clipy1)	cy = GDISP.clipy1 - y;
+			if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; x = GC->g.clipx0; }
+			if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; y = GC->g.clipy0; }
+			if (!lines || cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return;
+			if (x+cx > GC->g.clipx1)	cx = GC->g.clipx1 - x;
+			if (y+cy > GC->g.clipy1)	cy = GC->g.clipy1 - y;
 		#endif
 		
 		if (lines > cy) lines = cy;
@@ -856,7 +806,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 		hbr = CreateSolidBrush(bgcolor);
 
 		#if GDISP_NEED_CONTROL
-			switch(GDISP.Orientation) {
+			switch(GC->g.Orientation) {
 			case GDISP_ROTATE_0:
 				rect.top = y;
 				rect.bottom = rect.top+cy;
@@ -867,13 +817,13 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 			case GDISP_ROTATE_90:
 				rect.top = x;
 				rect.bottom = rect.top+cx;
-				rect.right = GDISP.Height - y;
+				rect.right = GC->g.Height - y;
 				rect.left = rect.right-cy;
 				goto horizontal_scroll;
 			case GDISP_ROTATE_180:
-				rect.bottom = GDISP.Height - y;
+				rect.bottom = GC->g.Height - y;
 				rect.top = rect.bottom-cy;
-				rect.right = GDISP.Width - x;
+				rect.right = GC->g.Width - x;
 				rect.left = rect.right-cx;
 			vertical_scroll:
 				srect.left = frect.left = rect.left;
@@ -891,7 +841,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 					ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0);
 				break;
 			case GDISP_ROTATE_270:
-				rect.bottom = GDISP.Width - x;
+				rect.bottom = GC->g.Width - x;
 				rect.top = rect.bottom-cx;
 				rect.left = y;
 				rect.right = rect.left+cy;
@@ -963,36 +913,36 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) {
 	void gdisp_lld_control(unsigned what, void *value) {
 		switch(what) {
 		case GDISP_CONTROL_ORIENTATION:
-			if (GDISP.Orientation == (gdisp_orientation_t)value)
+			if (GC->g.Orientation == (gdisp_orientation_t)value)
 				return;
 			switch((gdisp_orientation_t)value) {
 				case GDISP_ROTATE_0:
-					GDISP.Width = wWidth;
-					GDISP.Height = wHeight;
+					GC->g.Width = wWidth;
+					GC->g.Height = wHeight;
 					break;
 				case GDISP_ROTATE_90:
-					GDISP.Height = wWidth;
-					GDISP.Width = wHeight;
+					GC->g.Height = wWidth;
+					GC->g.Width = wHeight;
 					break;
 				case GDISP_ROTATE_180:
-					GDISP.Width = wWidth;
-					GDISP.Height = wHeight;
+					GC->g.Width = wWidth;
+					GC->g.Height = wHeight;
 					break;
 				case GDISP_ROTATE_270:
-					GDISP.Height = wWidth;
-					GDISP.Width = wHeight;
+					GC->g.Height = wWidth;
+					GC->g.Width = wHeight;
 					break;
 				default:
 					return;
 			}
 
 			#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
-				GDISP.clipx0 = 0;
-				GDISP.clipy0 = 0;
-				GDISP.clipx1 = GDISP.Width;
-				GDISP.clipy1 = GDISP.Height;
+				GC->g.clipx0 = 0;
+				GC->g.clipy0 = 0;
+				GC->g.clipx1 = GC->g.Width;
+				GC->g.clipy1 = GC->g.Height;
 			#endif
-			GDISP.Orientation = (gdisp_orientation_t)value;
+			GC->g.Orientation = (gdisp_orientation_t)value;
 			return;
 /*
 		case GDISP_CONTROL_POWER:
diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h
index b6fa874a..357febe4 100644
--- a/drivers/multiple/Win32/gdisp_lld_config.h
+++ b/drivers/multiple/Win32/gdisp_lld_config.h
@@ -22,14 +22,20 @@
 /* Driver hardware support.                                                  */
 /*===========================================================================*/
 
-#define GDISP_DRIVER_NAME				"Win32"
+#define GDISP_DRIVER_NAME				"Win32"
+#define GDISP_DRIVER_STRUCT				GDISP_Win32
 
-#define GDISP_HARDWARE_LINES			TRUE
-#define GDISP_HARDWARE_FILLS			TRUE
-#define GDISP_HARDWARE_BITFILLS			TRUE
-#define GDISP_HARDWARE_SCROLL			TRUE
-#define GDISP_HARDWARE_PIXELREAD		TRUE
-#define GDISP_HARDWARE_CONTROL			TRUE
+#define GDISP_HARDWARE_STREAM			FALSE
+#define GDISP_HARDWARE_STREAM_END		FALSE
+#define GDISP_HARDWARE_DRAWPIXEL		TRUE
+#define GDISP_HARDWARE_CLEARS			FALSE
+#define GDISP_HARDWARE_FILLS			TRUE
+//#define GDISP_HARDWARE_BITFILLS			TRUE
+//#define GDISP_HARDWARE_SCROLL			TRUE
+//#define GDISP_HARDWARE_PIXELREAD		TRUE
+//#define GDISP_HARDWARE_CONTROL			TRUE
+#define GDISP_HARDWARE_QUERY			FALSE
+#define GDISP_HARDWARE_CLIP				FALSE
 
 #define GDISP_PIXELFORMAT				GDISP_PIXELFORMAT_RGB888
 
diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h
index b82c9f3c..3a1968ed 100644
--- a/include/gdisp/gdisp.h
+++ b/include/gdisp/gdisp.h
@@ -76,20 +76,16 @@ typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_pow
  * Applications should always use the routines and macros defined
  * below to access it in case the implementation ever changed.
  */
-typedef struct GDISPDriver_t {
+typedef struct GDISPControl {
 		coord_t				Width;
 		coord_t				Height;
 		gdisp_orientation_t	Orientation;
 		gdisp_powermode_t	Powermode;
 		uint8_t				Backlight;
 		uint8_t				Contrast;
-		#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
-			coord_t				clipx0, clipy0;
-			coord_t				clipx1, clipy1;		/* not inclusive */
-		#endif
-		} GDISPDriver;
+	} GDISPControl;
 
-extern GDISPDriver	GDISP;
+extern GDISPControl	*GDISP;
 
 /*===========================================================================*/
 /* Constants.                                                                */
@@ -129,6 +125,7 @@ extern GDISPDriver	GDISP;
  */
 #define GDISP_PIXELFORMAT_MONO		1
 #define GDISP_PIXELFORMAT_RGB565	565
+#define GDISP_PIXELFORMAT_BGR565	9565
 #define GDISP_PIXELFORMAT_RGB888	888
 #define GDISP_PIXELFORMAT_RGB444	444
 #define GDISP_PIXELFORMAT_RGB332	332
@@ -219,10 +216,20 @@ extern GDISPDriver	GDISP;
 	#define MASKCOLOR			FALSE
 	#define RGB2COLOR(r,g,b)	((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3)))
 	#define HTML2COLOR(h)		((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3)))
-	#define RED_OF(c)			(((c) & 0xF800)>>8)
+	#define RED_OF(c)			(((c)&0xF800)>>8)
 	#define GREEN_OF(c)			(((c)&0x07E0)>>3)
 	#define BLUE_OF(c)			(((c)&0x001F)<<3)
 
+#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565
+	typedef uint16_t			color_t;
+	#define COLOR(c)			((color_t)(c))
+	#define MASKCOLOR			FALSE
+	#define RGB2COLOR(r,g,b)	((color_t)((((r) & 0xF8)>>3) | (((g) & 0xFC)<<3) | (((b) & 0xF8)<<8)))
+	#define HTML2COLOR(h)		((color_t)((((h) & 0x0000F8)>>3) | (((h) & 0x00FC00)>>5) | (((h) & 0xF80000)>>8)))
+	#define RED_OF(c)			(((c)&0x001F)<<3)
+	#define GREEN_OF(c)			(((c)&0x07E0)>>3)
+	#define BLUE_OF(c)			(((c)& 0xF800)>>8)
+
 #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
 	typedef uint32_t color_t;
 	#define COLOR(c)			((color_t)(((c) & 0xFFFFFF)))
@@ -296,278 +303,82 @@ typedef color_t		pixel_t;
 extern "C" {
 #endif
 
-#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC || defined(__DOXYGEN__)
-	/* These routines can be hardware accelerated
-	 *	- Do not add a routine here unless it has also been added to the hardware acceleration layer
-	 */
+/* Base Functions */
 
-	/* Base Functions */
-
-	/**
-	 * @brief   Test if the GDISP engine is currently drawing.
-	 * @note    This function will always return FALSE if
-	 * 			GDISP_NEED_ASYNC is not defined.
-	 *
-	 * @return	TRUE if gdisp is busy, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t gdispIsBusy(void);
-
-	/* Drawing Functions */
-
-	/**
-	 * @brief   Clear the display to the specified color.
-	 *
-	 * @param[in] color The color to use when clearing the screen
-	 *
-	 * @api
-	 */
-	void gdispClear(color_t color);
-
-	/**
-	 * @brief   Set a pixel in the specified color.
-	 *
-	 * @param[in] x,y   The position to set the pixel.
-	 * @param[in] color The color to use
-	 *
-	 * @api
-	 */
-	void gdispDrawPixel(coord_t x, coord_t y, color_t color);
-
-	/**
-	 * @brief   Draw a line.
-	 *
-	 * @param[in] x0,y0		The start position
-	 * @param[in] x1,y1 	The end position
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
-
-	/**
-	 * @brief   Fill an area with a color.
-	 *
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the box (outside dimensions)
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
-
-	/**
-	 * @brief   Fill an area using the supplied bitmap.
-	 * @details The bitmap is in the pixel format specified by the low level driver
-	 * @note	If a packed pixel format is used and the width doesn't
-	 *			match a whole number of bytes, the next line will start on a
-	 *			non-byte boundary (no end-of-line padding).
-	 * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
-	 * 			or at least retained until this call has finished the blit. You can
-	 * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
-	 *
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the filled area
-	 * @param[in] srcx,srcy The bitmap position to start the fill form
-	 * @param[in] srccx		The width of a line in the bitmap
-	 * @param[in] buffer	The bitmap in the driver's pixel format
-	 *
-	 * @api
-	 */
-	void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
-
-	/* Clipping Functions */
-
-	#if GDISP_NEED_CLIP || defined(__DOXYGEN__)
-		/**
-		 * @brief   Clip all drawing to the defined area.
-		 *
-		 * @param[in] x,y     The start position
-		 * @param[in] cx,cy   The size of the clip area
-		 *
-		 * @api
-		 */
-		void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy);
-	#endif
-
-	/* Circle Functions */
-
-	#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw a circle.
-		 *
-		 * @param[in] x,y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 * @param[in] color		The color to use
-		 *
-		 * @api
-		 */
-		void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color);
-
-		/**
-		 * @brief   Draw a filled circle.
-		 *
-		 * @param[in] x,y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 * @param[in] color		The color to use
-		 *
-		 * @api
-		 */
-		void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color);
-	#endif
-	
-	/* Ellipse Functions */
-
-	#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw an ellipse.
-		 *
-		 * @param[in] x,y   The center of the ellipse
-		 * @param[in] a,b     The dimensions of the ellipse
-		 * @param[in] color   The color to use
-		 *
-		 * @api
-		 */
-		void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
-
-		/**
-		 * @brief   Draw a filled ellipse.
-		 *
-		 * @param[in] x,y   The center of the ellipse
-		 * @param[in] a,b     The dimensions of the ellipse
-		 * @param[in] color   The color to use
-		 *
-		 * @api
-		 */
-		void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
-	#endif
-
-	/* Arc Functions */
-
-	#if GDISP_NEED_ARC || defined(__DOXYGEN__)
-		/*
-		 * @brief	Draw an arc.
-		 *
-		 * @param[in] x0,y0		The center point
-		 * @param[in] radius	The radius of the arc
-		 * @param[in] start		The start angle (0 to 360)
-		 * @param[in] end		The end angle (0 to 360)
-		 * @param[in] color		The color of the arc
-		 *
-		 * @api
-		 */
-		void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
-
-		/*
-		 * @brief	Draw a filled arc.
-		 * @note				Not very efficient currently - does lots of overdrawing
-		 *
-		 * @param[in] x0,y0		The center point
-		 * @param[in] radius	The radius of the arc
-		 * @param[in] start		The start angle (0 to 360)
-		 * @param[in] end		The end angle (0 to 360)
-		 * @param[in] color		The color of the arc
-		 *
-		 * @api
-		 */
-		void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
-	#endif
-
-	/* Read a pixel Function */
-
-	#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
-		/**
-		 * @brief   Get the color of a pixel.
-		 * @return  The color of the pixel.
-		 *
-		 * @param[in] x,y     The position of the pixel
-		 *
-		 * @api
-		 */
-		color_t gdispGetPixelColor(coord_t x, coord_t y);
-	#endif
-
-	/* Scrolling Function - clears the area scrolled out */
-
-	#if GDISP_NEED_SCROLL || defined(__DOXYGEN__)
-		/**
-		 * @brief   Scroll vertically a section of the screen.
-		 * @pre		GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h
-		 * @note    Optional.
-		 * @note    If lines is >= cy, it is equivelent to a area fill with bgcolor.
-		 *
-		 * @param[in] x, y     The start of the area to be scrolled
-		 * @param[in] cx, cy   The size of the area to be scrolled
-		 * @param[in] lines    The number of lines to scroll (Can be positive or negative)
-		 * @param[in] bgcolor  The color to fill the newly exposed area.
-		 *
-		 * @api
-		 */
-		void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
-	#endif
-
-	/* Set driver specific control */
-
-	#if GDISP_NEED_CONTROL || defined(__DOXYGEN__)
-		/**
-		 * @brief   Control hardware specific parts of the display. eg powermodes, backlight etc
-		 * @note    Depending on the hardware implementation this function may not
-		 *          support some codes. They will be ignored.
-		 *
-		 * @param[in] what		what you want to control
-		 * @param[in] value		The value to be assigned
-		 *
-		 * @api
-		 */
-		void gdispControl(unsigned what, void *value);
-	#endif
-
-	/* Query driver specific data */
-
-	#if GDISP_NEED_QUERY || defined(__DOXYGEN__)
-		/**
-		 * @brief   Query a property of the display.
-		 * @note    The result must be typecast to the correct type.
-		 * @note    An unsupported query will return (void *)-1.
-		 *
-		 * @param[in] what		What to query
-		 *
-		 * @api
-		 */
-		void *gdispQuery(unsigned what);
-	#endif
-
-#else
-	/* Include the low level driver information */
-	#include "gdisp/lld/gdisp_lld.h"
-
-	/* The same as above but use the low level driver directly if no multi-thread support is needed */
-	#define gdispIsBusy()										FALSE
-	#define gdispClear(color)									gdisp_lld_clear(color)
-	#define gdispDrawPixel(x, y, color)							gdisp_lld_draw_pixel(x, y, color)
-	#define gdispDrawLine(x0, y0, x1, y1, color)				gdisp_lld_draw_line(x0, y0, x1, y1, color)
-	#define gdispFillArea(x, y, cx, cy, color)					gdisp_lld_fill_area(x, y, cx, cy, color)
-	#define gdispBlitAreaEx(x, y, cx, cy, sx, sy, scx, buf)		gdisp_lld_blit_area_ex(x, y, cx, cy, sx, sy, scx, buf)
-	#define gdispSetClip(x, y, cx, cy)							gdisp_lld_set_clip(x, y, cx, cy)
-	#define gdispDrawCircle(x, y, radius, color)				gdisp_lld_draw_circle(x, y, radius, color)
-	#define gdispFillCircle(x, y, radius, color)				gdisp_lld_fill_circle(x, y, radius, color)
-	#define gdispDrawArc(x, y, radius, sangle, eangle, color)	gdisp_lld_draw_arc(x, y, radius, sangle, eangle, color)
-	#define gdispFillArc(x, y, radius, sangle, eangle, color)	gdisp_lld_fill_arc(x, y, radius, sangle, eangle, color)
-	#define gdispDrawEllipse(x, y, a, b, color)					gdisp_lld_draw_ellipse(x, y, a, b, color)
-	#define gdispFillEllipse(x, y, a, b, color)					gdisp_lld_fill_ellipse(x, y, a, b, color)
-	#define gdispGetPixelColor(x, y)							gdisp_lld_get_pixel_color(x, y)
-	#define gdispVerticalScroll(x, y, cx, cy, lines, bgcolor)	gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor)
-	#define gdispControl(what, value)							gdisp_lld_control(what, value)
-	#define gdispQuery(what)									gdisp_lld_query(what)
-
-#endif
-
-/* These routines are not hardware accelerated
- *	- Do not add a hardware accelerated routines here.
+/**
+ * @brief   Blend 2 colors according to the alpha
+ * @return	The combined color
+ *
+ * @param[in] fg		The foreground color
+ * @param[in] bg		The background color
+ * @param[in] alpha		The alpha value (0-255). 0 is all background, 255 is all foreground.
+ *
+ * @api
  */
+color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
 
-/* Extra drawing functions */
+/* Drawing Functions */
+
+/**
+ * @brief   Clear the display to the specified color.
+ *
+ * @param[in] color The color to use when clearing the screen
+ *
+ * @api
+ */
+void gdispClear(color_t color);
+
+/**
+ * @brief   Set a pixel in the specified color.
+ *
+ * @param[in] x,y   The position to set the pixel.
+ * @param[in] color The color to use
+ *
+ * @api
+ */
+void gdispDrawPixel(coord_t x, coord_t y, color_t color);
+
+/**
+ * @brief   Draw a line.
+ *
+ * @param[in] x0,y0		The start position
+ * @param[in] x1,y1 	The end position
+ * @param[in] color		The color to use
+ *
+ * @api
+ */
+void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
+
+/**
+ * @brief   Fill an area with a color.
+ *
+ * @param[in] x,y		The start position
+ * @param[in] cx,cy		The size of the box (outside dimensions)
+ * @param[in] color		The color to use
+ *
+ * @api
+ */
+void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
+
+/**
+ * @brief   Fill an area using the supplied bitmap.
+ * @details The bitmap is in the pixel format specified by the low level driver
+ * @note	If a packed pixel format is used and the width doesn't
+ *			match a whole number of bytes, the next line will start on a
+ *			non-byte boundary (no end-of-line padding).
+ * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
+ * 			or at least retained until this call has finished the blit. You can
+ * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
+ *
+ * @param[in] x,y		The start position
+ * @param[in] cx,cy		The size of the filled area
+ * @param[in] srcx,srcy The bitmap position to start the fill form
+ * @param[in] srccx		The width of a line in the bitmap
+ * @param[in] buffer	The bitmap in the driver's pixel format
+ *
+ * @api
+ */
+void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
 
 /**
  * @brief   Draw a rectangular box.
@@ -580,6 +391,167 @@ extern "C" {
  */
 void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
 
+/* Clipping Functions */
+
+#if GDISP_NEED_CLIP || defined(__DOXYGEN__)
+	/**
+	 * @brief   Clip all drawing to the defined area.
+	 *
+	 * @param[in] x,y     The start position
+	 * @param[in] cx,cy   The size of the clip area
+	 *
+	 * @api
+	 */
+	void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy);
+#endif
+
+/* Circle Functions */
+
+#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw a circle.
+	 *
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color);
+
+	/**
+	 * @brief   Draw a filled circle.
+	 *
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color);
+#endif
+
+/* Ellipse Functions */
+
+#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw an ellipse.
+	 *
+	 * @param[in] x,y   The center of the ellipse
+	 * @param[in] a,b     The dimensions of the ellipse
+	 * @param[in] color   The color to use
+	 *
+	 * @api
+	 */
+	void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
+
+	/**
+	 * @brief   Draw a filled ellipse.
+	 *
+	 * @param[in] x,y   The center of the ellipse
+	 * @param[in] a,b     The dimensions of the ellipse
+	 * @param[in] color   The color to use
+	 *
+	 * @api
+	 */
+	void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
+#endif
+
+/* Arc Functions */
+
+#if GDISP_NEED_ARC || defined(__DOXYGEN__)
+	/*
+	 * @brief	Draw an arc.
+	 *
+	 * @param[in] x0,y0		The center point
+	 * @param[in] radius	The radius of the arc
+	 * @param[in] start		The start angle (0 to 360)
+	 * @param[in] end		The end angle (0 to 360)
+	 * @param[in] color		The color of the arc
+	 *
+	 * @api
+	 */
+	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
+
+	/*
+	 * @brief	Draw a filled arc.
+	 * @note				Not very efficient currently - does lots of overdrawing
+	 *
+	 * @param[in] x0,y0		The center point
+	 * @param[in] radius	The radius of the arc
+	 * @param[in] start		The start angle (0 to 360)
+	 * @param[in] end		The end angle (0 to 360)
+	 * @param[in] color		The color of the arc
+	 *
+	 * @api
+	 */
+	void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
+#endif
+
+/* Read a pixel Function */
+
+#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
+	/**
+	 * @brief   Get the color of a pixel.
+	 * @return  The color of the pixel.
+	 *
+	 * @param[in] x,y     The position of the pixel
+	 *
+	 * @api
+	 */
+	color_t gdispGetPixelColor(coord_t x, coord_t y);
+#endif
+
+/* Scrolling Function - clears the area scrolled out */
+
+#if GDISP_NEED_SCROLL || defined(__DOXYGEN__)
+	/**
+	 * @brief   Scroll vertically a section of the screen.
+	 * @pre		GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h
+	 * @note    Optional.
+	 * @note    If lines is >= cy, it is equivelent to a area fill with bgcolor.
+	 *
+	 * @param[in] x, y     The start of the area to be scrolled
+	 * @param[in] cx, cy   The size of the area to be scrolled
+	 * @param[in] lines    The number of lines to scroll (Can be positive or negative)
+	 * @param[in] bgcolor  The color to fill the newly exposed area.
+	 *
+	 * @api
+	 */
+	void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
+#endif
+
+/* Set driver specific control */
+
+#if GDISP_NEED_CONTROL || defined(__DOXYGEN__)
+	/**
+	 * @brief   Control hardware specific parts of the display. eg powermodes, backlight etc
+	 * @note    Depending on the hardware implementation this function may not
+	 *          support some codes. They will be ignored.
+	 *
+	 * @param[in] what		what you want to control
+	 * @param[in] value		The value to be assigned
+	 *
+	 * @api
+	 */
+	void gdispControl(unsigned what, void *value);
+#endif
+
+/* Query driver specific data */
+
+#if GDISP_NEED_QUERY || defined(__DOXYGEN__)
+	/**
+	 * @brief   Query a property of the display.
+	 * @note    The result must be typecast to the correct type.
+	 * @note    An unsupported query will return (void *)-1.
+	 *
+	 * @param[in] what		What to query
+	 *
+	 * @api
+	 */
+	void *gdispQuery(unsigned what);
+#endif
+
 #if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
 	/**
 	 * @brief   Draw an enclosed polygon (convex, non-convex or complex).
@@ -803,19 +775,6 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
 	void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
 #endif
 
-
-/**
- * @brief   Blend 2 colors according to the alpha
- * @return	The combined color
- *
- * @param[in] fg		The foreground color
- * @param[in] bg		The background color
- * @param[in] alpha		The alpha value (0-255). 0 is all background, 255 is all foreground.
- *
- * @api
- */
-color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
-
 /* Support routine for packed pixel formats */
 #if !defined(gdispPackPixels) || defined(__DOXYGEN__)
 	/**
@@ -890,42 +849,42 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
  *
  * @api
  */
-#define gdispGetWidth()							(GDISP.Width)
+#define gdispGetWidth()							(GDISP->Width)
 
 /**
  * @brief   Get the display height in pixels.
  *
  * @api
  */
-#define gdispGetHeight()						(GDISP.Height)
+#define gdispGetHeight()						(GDISP->Height)
 
 /**
  * @brief   Get the current display power mode.
  *
  * @api
  */
-#define gdispGetPowerMode()						(GDISP.Powermode)
+#define gdispGetPowerMode()						(GDISP->Powermode)
 
 /**
  * @brief   Get the current display orientation.
  *
  * @api
  */
-#define gdispGetOrientation()					(GDISP.Orientation)
+#define gdispGetOrientation()					(GDISP->Orientation)
 
 /**
  * @brief   Get the current display backlight brightness.
  *
  * @api
  */
-#define gdispGetBacklight()						(GDISP.Backlight)
+#define gdispGetBacklight()						(GDISP->Backlight)
 
 /**
  * @brief   Get the current display contrast.
  *
  * @api
  */
-#define gdispGetContrast()						(GDISP.Contrast)
+#define gdispGetContrast()						(GDISP->Contrast)
 
 /* More interesting macro's */
 
@@ -936,7 +895,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
  */
 #define gdispUnsetClip()						gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight())
 
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/gdisp/lld/emulation.c b/include/gdisp/lld/emulation.c
deleted file mode 100644
index cb0c9c4b..00000000
--- a/include/gdisp/lld/emulation.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file	include/gdisp/lld/emulation.c
- * @brief	GDISP emulation routines for stuff the driver dosen't support
- *
- * @addtogroup GDISP
- *
- * @details	Even though this is a software emulation of a low level driver
- *			most validation doesn't need to happen here as eventually
- *			we call a real low level driver routine and if validation is
- *			required - it will do it.
- *
- * @{
- */
-#ifndef GDISP_EMULATION_C
-#define GDISP_EMULATION_C
-
-#if GFX_USE_GDISP
-
-/* Include the low level driver information */
-#include "gdisp/lld/gdisp_lld.h"
-
-/* Declare the GDISP structure */
-GDISPDriver	GDISP;
-
-#if !GDISP_HARDWARE_CLEARS 
-	void gdisp_lld_clear(color_t color) {
-		gdisp_lld_fill_area(0, 0, GDISP.Width, GDISP.Height, color);
-	}
-#endif
-
-#if !GDISP_HARDWARE_LINES 
-	void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
-		int16_t dy, dx;
-		int16_t addx, addy;
-		int16_t P, diff, i;
-
-		#if GDISP_HARDWARE_FILLS || GDISP_HARDWARE_SCROLL
-		// speed improvement if vertical or horizontal
-		if (x0 == x1) {
-			if (y1 > y0)
-				gdisp_lld_fill_area(x0, y0, 1, y1-y0+1, color);
-			else
-				gdisp_lld_fill_area(x0, y1, 1, y0-y1+1, color);
-			return;
-		}
-		if (y0 == y1) {
-			if (x1 > x0)
-				gdisp_lld_fill_area(x0, y0, x1-x0+1, 1, color);
-			else
-				gdisp_lld_fill_area(x1, y0, x0-x1+1, 1, color);
-			return;
-		}
-		#endif
-
-		if (x1 >= x0) {
-			dx = x1 - x0;
-			addx = 1;
-		} else {
-			dx = x0 - x1;
-			addx = -1;
-		}
-		if (y1 >= y0) {
-			dy = y1 - y0;
-			addy = 1;
-		} else {
-			dy = y0 - y1;
-			addy = -1;
-		}
-
-		if (dx >= dy) {
-			dy *= 2;
-			P = dy - dx;
-			diff = P - dx;
-
-			for(i=0; i<=dx; ++i) {
-				gdisp_lld_draw_pixel(x0, y0, color);
-				if (P < 0) {
-					P  += dy;
-					x0 += addx;
-				} else {
-					P  += diff;
-					x0 += addx;
-					y0 += addy;
-				}
-			}
-		} else {
-			dx *= 2;
-			P = dx - dy;
-			diff = P - dy;
-
-			for(i=0; i<=dy; ++i) {
-				gdisp_lld_draw_pixel(x0, y0, color);
-				if (P < 0) {
-					P  += dx;
-					y0 += addy;
-				} else {
-					P  += diff;
-					x0 += addx;
-					y0 += addy;
-				}
-			}
-		}
-	}
-#endif
-
-#if !GDISP_HARDWARE_FILLS
-	void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-		#if GDISP_HARDWARE_SCROLL
-			gdisp_lld_vertical_scroll(x, y, cx, cy, cy, color);
-		#elif GDISP_HARDWARE_LINES
-			coord_t x1, y1;
-			
-			x1 = x + cx - 1;
-			y1 = y + cy;
-			for(; y < y1; y++)
-				gdisp_lld_draw_line(x, y, x1, y, color);
-		#else
-			coord_t x0, x1, y1;
-			
-			x0 = x;
-			x1 = x + cx;
-			y1 = y + cy;
-			for(; y < y1; y++)
-				for(x = x0; x < x1; x++)
-					gdisp_lld_draw_pixel(x, y, color);
-		#endif
-	}
-#endif
-
-#if !GDISP_HARDWARE_BITFILLS
-	void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
-			coord_t x0, x1, y1;
-			
-			x0 = x;
-			x1 = x + cx;
-			y1 = y + cy;
-			buffer += srcy*srccx+srcx;
-			srccx -= cx;
-			for(; y < y1; y++, buffer += srccx)
-				for(x=x0; x < x1; x++)
-					gdisp_lld_draw_pixel(x, y, *buffer++);
-	}
-#endif
-
-#if GDISP_NEED_CLIP && !GDISP_HARDWARE_CLIP
-	void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy) {
-		#if GDISP_NEED_VALIDATION
-			if (x >= GDISP.Width || y >= GDISP.Height || cx < 0 || cy < 0)
-				return;
-			if (x < 0) x = 0;
-			if (y < 0) y = 0;
-			if (x+cx > GDISP.Width) cx = GDISP.Width - x;
-			if (y+cy > GDISP.Height) cy = GDISP.Height - y;
-		#endif
-		GDISP.clipx0 = x;
-		GDISP.clipy0 = y;
-		GDISP.clipx1 = x+cx;
-		GDISP.clipy1 = y+cy;
-	}
-#endif
-
-#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLES
-	void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		coord_t a, b, P;
-
-		a = 0;
-		b = radius;
-		P = 1 - radius;
-
-		do {
-			gdisp_lld_draw_pixel(x+a, y+b, color);
-			gdisp_lld_draw_pixel(x+b, y+a, color);
-			gdisp_lld_draw_pixel(x-a, y+b, color);
-			gdisp_lld_draw_pixel(x-b, y+a, color);
-			gdisp_lld_draw_pixel(x+b, y-a, color);
-			gdisp_lld_draw_pixel(x+a, y-b, color);
-			gdisp_lld_draw_pixel(x-a, y-b, color);
-			gdisp_lld_draw_pixel(x-b, y-a, color);
-			if (P < 0)
-				P += 3 + 2*a++;
-			else
-				P += 5 + 2*(a++ - b--);
-		} while(a <= b);
-	}
-#endif
-
-#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLEFILLS
-	void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		coord_t a, b, P;
-		
-		a = 0;
-		b = radius;
-		P = 1 - radius;
-
-		do {
-			gdisp_lld_draw_line(x-a, y+b, x+a, y+b, color);
-			gdisp_lld_draw_line(x-a, y-b, x+a, y-b, color);
-			gdisp_lld_draw_line(x-b, y+a, x+b, y+a, color);
-			gdisp_lld_draw_line(x-b, y-a, x+b, y-a, color);
-			if (P < 0)
-				P += 3 + 2*a++;
-			else
-				P += 5 + 2*(a++ - b--);
-		} while(a <= b);
-	}
-#endif
-
-#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSES
-	void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		int  dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */
-		long a2 = a*a, b2 = b*b;
-		long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */
-
-		do {
-			gdisp_lld_draw_pixel(x+dx, y+dy, color); /* I. Quadrant */
-			gdisp_lld_draw_pixel(x-dx, y+dy, color); /* II. Quadrant */
-			gdisp_lld_draw_pixel(x-dx, y-dy, color); /* III. Quadrant */
-			gdisp_lld_draw_pixel(x+dx, y-dy, color); /* IV. Quadrant */
-
-			e2 = 2*err;
-			if(e2 <  (2*dx+1)*b2) {
-				dx++;
-				err += (2*dx+1)*b2;
-			}
-			if(e2 > -(2*dy-1)*a2) {
-				dy--;
-				err -= (2*dy-1)*a2;
-			}
-		} while(dy >= 0); 
-
-		while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */
-			gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */
-			gdisp_lld_draw_pixel(x-dx, y, color);
-	   }   
-	}
-#endif
-
-#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSEFILLS
-	void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		int  dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */
-		long a2 = a*a, b2 = b*b;
-		long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */
-
-		do {
-			gdisp_lld_draw_line(x-dx,y+dy,x+dx,y+dy, color);
-			gdisp_lld_draw_line(x-dx,y-dy,x+dx,y-dy, color);
-
-			e2 = 2*err;
-			if(e2 <  (2*dx+1)*b2) {
-				dx++;
-				err += (2*dx+1)*b2;
-			}
-			if(e2 > -(2*dy-1)*a2) {
-				dy--;
-				err -= (2*dy-1)*a2;
-			}
-		} while(dy >= 0); 
-
-		while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */
-			gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */
-			gdisp_lld_draw_pixel(x-dx, y, color);
-	   }   
-	}
-#endif
-
-#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCS
-
-	#include <math.h>
-
-	/*
-	 * @brief				Internal helper function for gdispDrawArc()
-	 *
-	 * @note				DO NOT USE DIRECTLY!
-	 *
-	 * @param[in] x, y		The middle point of the arc
-	 * @param[in] start		The start angle of the arc
-	 * @param[in] end		The end angle of the arc
-	 * @param[in] radius	The radius of the arc
-	 * @param[in] color		The color in which the arc will be drawn
-	 *
-	 * @notapi
-	 */
-	static void _draw_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) {
-	    if (/*start >= 0 && */start <= 180) {
-	        float x_maxI = x + radius*cos(start*M_PI/180);
-	        float x_minI;
-
-	        if (end > 180)
-	            x_minI = x - radius;
-	        else
-	            x_minI = x + radius*cos(end*M_PI/180);
-
-	        int a = 0;
-	        int b = radius;
-	        int P = 1 - radius;
-
-	        do {
-	            if(x-a <= x_maxI && x-a >= x_minI)
-	            	gdisp_lld_draw_pixel(x-a, y-b, color);
-	            if(x+a <= x_maxI && x+a >= x_minI)
-	            	gdisp_lld_draw_pixel(x+a, y-b, color);
-	            if(x-b <= x_maxI && x-b >= x_minI)
-	            	gdisp_lld_draw_pixel(x-b, y-a, color);
-	            if(x+b <= x_maxI && x+b >= x_minI)
-	            	gdisp_lld_draw_pixel(x+b, y-a, color);
-
-	            if (P < 0) {
-	                P = P + 3 + 2*a;
-	                a = a + 1;
-	            } else {
-	                P = P + 5 + 2*(a - b);
-	                a = a + 1;
-	                b = b - 1;
-	            }
-	        } while(a <= b);
-	    }
-
-	    if (end > 180 && end <= 360) {
-	        float x_maxII = x+radius*cos(end*M_PI/180);
-	        float x_minII;
-
-	        if(start <= 180)
-	            x_minII = x - radius;
-	        else
-	            x_minII = x+radius*cos(start*M_PI/180);
-
-	        int a = 0;
-	        int b = radius;
-	        int P = 1 - radius;
-
-	        do {
-	            if(x-a <= x_maxII && x-a >= x_minII)
-	            	gdisp_lld_draw_pixel(x-a, y+b, color);
-	            if(x+a <= x_maxII && x+a >= x_minII)
-	            	gdisp_lld_draw_pixel(x+a, y+b, color);
-	            if(x-b <= x_maxII && x-b >= x_minII)
-	            	gdisp_lld_draw_pixel(x-b, y+a, color);
-	            if(x+b <= x_maxII && x+b >= x_minII)
-	            	gdisp_lld_draw_pixel(x+b, y+a, color);
-
-	            if (P < 0) {
-	                P = P + 3 + 2*a;
-	                a = a + 1;
-	            } else {
-	                P = P + 5 + 2*(a - b);
-	                a = a + 1;
-	                b = b - 1;
-	            }
-	        } while (a <= b);
-	    }
-	}
-
-	void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) {
-		if(endangle < startangle) {
-	        _draw_arc(x, y, startangle, 360, radius, color);
-	        _draw_arc(x, y, 0, endangle, radius, color);
-	    } else {
-	        _draw_arc(x, y, startangle, endangle, radius, color);
-		}
-	}
-#endif
-
-#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCFILLS
-	/*
-	 * @brief				Internal helper function for gdispDrawArc()
-	 *
-	 * @note				DO NOT USE DIRECTLY!
-	 *
-	 * @param[in] x, y		The middle point of the arc
-	 * @param[in] start		The start angle of the arc
-	 * @param[in] end		The end angle of the arc
-	 * @param[in] radius	The radius of the arc
-	 * @param[in] color		The color in which the arc will be drawn
-	 *
-	 * @notapi
-	 */
-	static void _fill_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) {
-	    if (/*start >= 0 && */start <= 180) {
-	        float x_maxI = x + radius*cos(start*M_PI/180);
-	        float x_minI;
-
-	        if (end > 180)
-	            x_minI = x - radius;
-	        else
-	            x_minI = x + radius*cos(end*M_PI/180);
-
-	        int a = 0;
-	        int b = radius;
-	        int P = 1 - radius;
-
-	        do {
-	            if(x-a <= x_maxI && x-a >= x_minI)
-	            	gdisp_lld_draw_line(x, y, x-a, y-b, color);
-	            if(x+a <= x_maxI && x+a >= x_minI)
-	            	gdisp_lld_draw_line(x, y, x+a, y-b, color);
-	            if(x-b <= x_maxI && x-b >= x_minI)
-	            	gdisp_lld_draw_line(x, y, x-b, y-a, color);
-	            if(x+b <= x_maxI && x+b >= x_minI)
-	            	gdisp_lld_draw_line(x, y, x+b, y-a, color);
-
-	            if (P < 0) {
-	                P = P + 3 + 2*a;
-	                a = a + 1;
-	            } else {
-	                P = P + 5 + 2*(a - b);
-	                a = a + 1;
-	                b = b - 1;
-	            }
-	        } while(a <= b);
-	    }
-
-	    if (end > 180 && end <= 360) {
-	        float x_maxII = x+radius*cos(end*M_PI/180);
-	        float x_minII;
-
-	        if(start <= 180)
-	            x_minII = x - radius;
-	        else
-	            x_minII = x+radius*cos(start*M_PI/180);
-
-	        int a = 0;
-	        int b = radius;
-	        int P = 1 - radius;
-
-	        do {
-	            if(x-a <= x_maxII && x-a >= x_minII)
-	            	gdisp_lld_draw_line(x, y, x-a, y+b, color);
-	            if(x+a <= x_maxII && x+a >= x_minII)
-	            	gdisp_lld_draw_line(x, y, x+a, y+b, color);
-	            if(x-b <= x_maxII && x-b >= x_minII)
-	            	gdisp_lld_draw_line(x, y, x-b, y+a, color);
-	            if(x+b <= x_maxII && x+b >= x_minII)
-	            	gdisp_lld_draw_line(x, y, x+b, y+a, color);
-
-	            if (P < 0) {
-	                P = P + 3 + 2*a;
-	                a = a + 1;
-	            } else {
-	                P = P + 5 + 2*(a - b);
-	                a = a + 1;
-	                b = b - 1;
-	            }
-	        } while (a <= b);
-	    }
-	}
-
-	void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) {
-		if(endangle < startangle) {
-	        _fill_arc(x, y, startangle, 360, radius, color);
-	        _fill_arc(x, y, 0, endangle, radius, color);
-	    } else {
-	        _fill_arc(x, y, startangle, endangle, radius, color);
-		}
-	}
-#endif
-
-#if GDISP_NEED_CONTROL && !GDISP_HARDWARE_CONTROL
-	void gdisp_lld_control(unsigned what, void *value) {
-		(void)what;
-		(void)value;
-		/* Ignore everything */
-	}
-#endif
-
-#if GDISP_NEED_QUERY && !GDISP_HARDWARE_QUERY
-void *gdisp_lld_query(unsigned what) {
-	(void) what;
-	return (void *)-1;
-}
-#endif
-
-#if GDISP_NEED_MSGAPI
-	void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg) {
-		switch(msg->action) {
-		case GDISP_LLD_MSG_NOP:
-			break;
-		case GDISP_LLD_MSG_INIT:
-			gdisp_lld_init();
-			break;
-		case GDISP_LLD_MSG_CLEAR:
-			gdisp_lld_clear(msg->clear.color);
-			break;
-		case GDISP_LLD_MSG_DRAWPIXEL:
-			gdisp_lld_draw_pixel(msg->drawpixel.x, msg->drawpixel.y, msg->drawpixel.color);
-			break;
-		case GDISP_LLD_MSG_FILLAREA:
-			gdisp_lld_fill_area(msg->fillarea.x, msg->fillarea.y, msg->fillarea.cx, msg->fillarea.cy, msg->fillarea.color);
-			break;
-		case GDISP_LLD_MSG_BLITAREA:
-			gdisp_lld_blit_area_ex(msg->blitarea.x, msg->blitarea.y, msg->blitarea.cx, msg->blitarea.cy, msg->blitarea.srcx, msg->blitarea.srcy, msg->blitarea.srccx, msg->blitarea.buffer);
-			break;
-		case GDISP_LLD_MSG_DRAWLINE:
-			gdisp_lld_draw_line(msg->drawline.x0, msg->drawline.y0, msg->drawline.x1, msg->drawline.y1, msg->drawline.color);
-			break;
-		#if GDISP_NEED_CLIP
-			case GDISP_LLD_MSG_SETCLIP:
-				gdisp_lld_set_clip(msg->setclip.x, msg->setclip.y, msg->setclip.cx, msg->setclip.cy);
-				break;
-		#endif
-		#if GDISP_NEED_CIRCLE
-			case GDISP_LLD_MSG_DRAWCIRCLE:
-				gdisp_lld_draw_circle(msg->drawcircle.x, msg->drawcircle.y, msg->drawcircle.radius, msg->drawcircle.color);
-				break;
-			case GDISP_LLD_MSG_FILLCIRCLE:
-				gdisp_lld_fill_circle(msg->fillcircle.x, msg->fillcircle.y, msg->fillcircle.radius, msg->fillcircle.color);
-				break;
-		#endif
-		#if GDISP_NEED_ELLIPSE
-			case GDISP_LLD_MSG_DRAWELLIPSE:
-				gdisp_lld_draw_ellipse(msg->drawellipse.x, msg->drawellipse.y, msg->drawellipse.a, msg->drawellipse.b, msg->drawellipse.color);
-				break;
-			case GDISP_LLD_MSG_FILLELLIPSE:
-				gdisp_lld_fill_ellipse(msg->fillellipse.x, msg->fillellipse.y, msg->fillellipse.a, msg->fillellipse.b, msg->fillellipse.color);
-				break;
-		#endif
-		#if GDISP_NEED_ARC
-			case GDISP_LLD_MSG_DRAWARC:
-				gdisp_lld_draw_circle(msg->drawarc.x, msg->drawarc.y, msg->drawarc.radius, msg->drawarc.startangle, msg->drawarc.endangle, msg->drawarc.color);
-				break;
-			case GDISP_LLD_MSG_FILLARC:
-				gdisp_lld_fill_circle(msg->fillarc.x, msg->fillarc.y, msg->fillarc.radius, msg->fillarc.startangle, msg->fillarc.endangle, msg->fillarc.color);
-				break;
-		#endif
-		#if GDISP_NEED_PIXELREAD
-			case GDISP_LLD_MSG_GETPIXELCOLOR:
-				msg->getpixelcolor.result = gdisp_lld_get_pixel_color(msg->getpixelcolor.x, msg->getpixelcolor.y);
-				break;
-		#endif
-		#if GDISP_NEED_SCROLL
-			case GDISP_LLD_MSG_VERTICALSCROLL:
-				gdisp_lld_vertical_scroll(msg->verticalscroll.x, msg->verticalscroll.y, msg->verticalscroll.cx, msg->verticalscroll.cy, msg->verticalscroll.lines, msg->verticalscroll.bgcolor);
-				break;
-		#endif
-		#if GDISP_NEED_CONTROL
-			case GDISP_LLD_MSG_CONTROL:
-				gdisp_lld_control(msg->control.what, msg->control.value);
-				break;
-		#endif
-		#if GDISP_NEED_QUERY
-			case GDISP_LLD_MSG_QUERY:
-				msg->query.result = gdisp_lld_query(msg->query.what);
-				break;
-		#endif
-		}
-	}
-#endif
-
-#endif  /* GFX_USE_GDISP */
-#endif	/* GDISP_EMULATION_C */
-/** @} */
-
diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h
index 98c7569c..46d5488a 100644
--- a/include/gdisp/lld/gdisp_lld.h
+++ b/include/gdisp/lld/gdisp_lld.h
@@ -27,16 +27,35 @@
  * @{
  */
 	/**
-	 * @brief   Hardware accelerated line drawing.
+	 * @brief   Hardware streaming interface is supported.
 	 * @details If set to @p FALSE software emulation is used.
+	 * @note	Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver
 	 */
-	#ifndef GDISP_HARDWARE_LINES
-		#define GDISP_HARDWARE_LINES			FALSE
+	#ifndef GDISP_HARDWARE_STREAM
+		#define GDISP_HARDWARE_STREAM			FALSE
+	#endif
+
+	/**
+	 * @brief   Hardware streaming requires an explicit end call.
+	 * @details If set to @p FALSE if an explicit stream end call is not required.
+	 */
+	#ifndef GDISP_HARDWARE_STREAM_END
+		#define GDISP_HARDWARE_STREAM_END		FALSE
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated draw pixel.
+	 * @details If set to @p FALSE software emulation is used.
+	 * @note	Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver
+	 */
+	#ifndef GDISP_HARDWARE_DRAWPIXEL
+		#define GDISP_HARDWARE_DRAWPIXEL		FALSE
 	#endif
 
 	/**
 	 * @brief   Hardware accelerated screen clears.
 	 * @details If set to @p FALSE software emulation is used.
+	 * @note	This clears the entire display surface regardless of the clipping area currently set
 	 */
 	#ifndef GDISP_HARDWARE_CLEARS
 		#define GDISP_HARDWARE_CLEARS			FALSE
@@ -58,54 +77,6 @@
 		#define GDISP_HARDWARE_BITFILLS			FALSE
 	#endif
 
-	/**
-	 * @brief   Hardware accelerated circles.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_CIRCLES
-		#define GDISP_HARDWARE_CIRCLES			FALSE
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated filled circles.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_CIRCLEFILLS
-		#define GDISP_HARDWARE_CIRCLEFILLS		FALSE
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated ellipses.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_ELLIPSES
-		#define GDISP_HARDWARE_ELLIPSES			FALSE
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated filled ellipses.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_ELLIPSEFILLS
-		#define GDISP_HARDWARE_ELLIPSEFILLS		FALSE
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated arc's.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_ARCS
-		#define GDISP_HARDWARE_ARCS			FALSE
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated filled arcs.
-	 * @details If set to @p FALSE software emulation is used.
-	 */
-	#ifndef GDISP_HARDWARE_ARCFILLS
-		#define GDISP_HARDWARE_ARCFILLS		FALSE
-	#endif
-
 	/**
 	 * @brief   Hardware accelerated scrolling.
 	 * @details If set to @p FALSE there is no support for scrolling.
@@ -141,9 +112,14 @@
 	/**
 	 * @brief   The driver supports a clipping in hardware.
 	 * @details If set to @p FALSE there is no support for non-standard queries.
+	 * @note	If this is defined the driver must perform its own clipping on all calls to
+	 * 			the driver and respond appropriately if a parameter is outside the display area.
+	 * @note	If this is not defined then the software ensures that all calls to the
+	 * 			driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION
+	 * 			has been set).
 	 */
 	#ifndef GDISP_HARDWARE_CLIP
-		#define GDISP_HARDWARE_CLIP			FALSE
+		#define GDISP_HARDWARE_CLIP				FALSE
 	#endif
 /** @} */
 
@@ -161,6 +137,7 @@
 	 * @brief   The native pixel format for this device
 	 * @note	Should be set to one of the following:
 	 *				GDISP_PIXELFORMAT_RGB565
+	 *				GDISP_PIXELFORMAT_BGR565
 	 *				GDISP_PIXELFORMAT_RGB888
 	 *				GDISP_PIXELFORMAT_RGB444
 	 *				GDISP_PIXELFORMAT_RGB332
@@ -208,76 +185,85 @@
 /* External declarations.                                                    */
 /*===========================================================================*/
 
+typedef struct GDISPDriver {
+	GDISPControl			g;
+
+	uint16_t				flags;
+		#define GDISP_FLG_INSTREAM		0x0001
+
+	// Multithread Mutex
+	#if GDISP_NEED_MULTITHREAD
+		gfxMutex			mutex;
+	#endif
+
+	// Software clipping
+	#if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
+		coord_t				clipx0, clipy0;
+		coord_t				clipx1, clipy1;		/* not inclusive */
+	#endif
+
+	// Driver call parameters
+	struct {
+		coord_t			x, y;
+		coord_t			cx, cy;
+		coord_t			x1, y1;
+		coord_t			x2, y2;
+		color_t			color;
+		void			*ptr;
+	} p;
+
+	// Text rendering parameters
+	#if GDISP_NEED_TEXT
+		struct {
+			font_t		font;
+			color_t		color;
+			color_t		bgcolor;
+			coord_t		clipx0, clipy0;
+			coord_t		clipx1, clipy1;
+		} t;
+	#endif
+} GDISPDriver;
+
+extern GDISPDriver	GDISP_DRIVER_STRUCT;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-	/* Core functions */
-	extern bool_t gdisp_lld_init(void);
-
-	/* Some of these functions will be implemented in software by the high level driver
-	   depending on the GDISP_HARDWARE_XXX macros defined in gdisp_lld_config.h.
-	 */
-
-	/* Drawing functions */
-	extern void gdisp_lld_clear(color_t color);
-	extern void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color);
-	extern void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
-	extern void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
-	extern void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
-
-	/* Circular Drawing Functions */
-	#if GDISP_NEED_CIRCLE
-	extern void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color);
-	extern void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color);
+	bool_t gdisp_lld_init(void);
+	#if GDISP_HARDWARE_STREAM
+		void gdisp_lld_stream_start(void);		// Uses p.x,p.y  p.cx,p.cy
+		void gdisp_lld_stream_color(void);		// Uses p.color
+		#if GDISP_HARDWARE_STREAM_END
+			void gdisp_lld_stream_stop(void);	// Uses no parameters
+		#endif
 	#endif
-
-	#if GDISP_NEED_ELLIPSE
-	extern void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
-	extern void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
+	#if GDISP_HARDWARE_DRAWPIXEL
+		void gdisp_lld_draw_pixel(void);		// Uses p.x,p.y  p.color
 	#endif
-
-	/* Arc Drawing Functions */
-	#if GDISP_NEED_ARC
-	extern void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
-	extern void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
+	#if GDISP_HARDWARE_CLEARS
+		void gdisp_lld_clear(void);				// Uses p.color
 	#endif
-
-	/* Text Rendering Functions */
-	#if GDISP_NEED_TEXT
-	extern void gdisp_lld_draw_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color);
-	extern void gdisp_lld_fill_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor);
+	#if GDISP_HARDWARE_FILLS
+		void gdisp_lld_fill_area(void);			// Uses p.x,p.y  p.cx,p.cy  p.color
 	#endif
-
-	/* Pixel readback */
-	#if GDISP_NEED_PIXELREAD
-	extern color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y);
+	#if GDISP_HARDWARE_BITFILLS
+		void gdisp_lld_blit_area_ex(void);		// Uses p.x,p.y  p.cx,p.cy  p.x1,p.y1 (=srcx,srcy)  p.x2 (=srccx), p.ptr (=buffer)
 	#endif
-
-	/* Scrolling Function - clears the area scrolled out */
-	#if GDISP_NEED_SCROLL
-	extern void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
+	#if GDISP_HARDWARE_PIXELREAD && GDISP_NEED_PIXELREAD
+		color_t gdisp_lld_get_pixel_color(void);	// Uses p.x,p.y
 	#endif
-
-	/* Set driver specific control */
-	#if GDISP_NEED_CONTROL
-	extern void gdisp_lld_control(unsigned what, void *value);
+	#if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL
+		void gdisp_lld_vertical_scroll(void);	// Uses p.x,p.y  p.cx,p.cy, p.y1 (=lines) p.color
 	#endif
-
-	/* Query driver specific data */
-	#if GDISP_NEED_QUERY
-	extern void *gdisp_lld_query(unsigned what);
+	#if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL
+		void gdisp_lld_control(void);			// Uses p.x (=what)  p.ptr (=value)
 	#endif
-
-	/* Clipping Functions */
-	#if GDISP_NEED_CLIP
-	extern void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy);
+	#if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY
+		void *gdisp_lld_query(void);			// Uses p.x (=what);
 	#endif
-
-	/* Messaging API */
-	#if GDISP_NEED_MSGAPI
-	#include "gdisp_lld_msgs.h"
-	extern void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg);
+	#if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
+		void gdisp_lld_set_clip(void);			// Uses p.x,p.y  p.cx,p.cy
 	#endif
 
 #ifdef __cplusplus
diff --git a/include/gmisc/gmisc.h b/include/gmisc/gmisc.h
index 998dda50..5943e642 100644
--- a/include/gmisc/gmisc.h
+++ b/include/gmisc/gmisc.h
@@ -51,6 +51,7 @@ typedef int32_t	fixed;
  */
 #define FIXED(x)		((fixed)(x)<<16)			/* @< integer to fixed */
 #define NONFIXED(x)		((x)>>16)					/* @< fixed to integer */
+#define FIXED0_5		32768						/* @< 0.5 as a fixed (used for rounding) */
 #define FP2FIXED(x)		((fixed)((x)*65536.0))		/* @< floating point to fixed */
 #define FIXED2FP(x)		((double)(x)/65536.0)		/* @< fixed to floating point */
 /* @} */
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c
index 22773908..1aecd26c 100644
--- a/src/gdisp/gdisp.c
+++ b/src/gdisp/gdisp.c
@@ -19,438 +19,1526 @@
 /* Include the low level driver information */
 #include "gdisp/lld/gdisp_lld.h"
 
+#if !GDISP_HARDWARE_STREAM && !GDISP_HARDWARE_DRAWPIXEL
+	#error "GDISP Driver: Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be defined"
+#endif
+
+#if 1
+	#undef INLINE
+	#define INLINE	inline
+#else
+	#undef INLINE
+	#define INLINE
+#endif
+
 /*===========================================================================*/
 /* Driver local variables.                                                   */
 /*===========================================================================*/
 
-#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC
-	static gfxMutex			gdispMutex;
+#define	GC				((GDISPDriver *)GDISP)
+GDISPControl			*GDISP = &GDISP_DRIVER_STRUCT.g;
+
+#if GDISP_NEED_MULTITHREAD
+	#define MUTEX_INIT()		gfxMutexInit(&GC->mutex)
+	#define MUTEX_ENTER()		gfxMutexEnter(&GC->mutex)
+	#define MUTEX_EXIT()		gfxMutexExit(&GC->mutex)
+#else
+	#define MUTEX_INIT()
+	#define MUTEX_ENTER()
+	#define MUTEX_EXIT()
 #endif
 
-#if GDISP_NEED_ASYNC
-	#define GDISP_THREAD_STACK_SIZE	256		/* Just a number - not yet a reflection of actual use */
-	#define GDISP_QUEUE_SIZE		8		/* We only allow a short queue */
-
-	static gfxQueue 		gdispQueue;
-	static gfxMutex			gdispMsgsMutex;
-	static gfxSem			gdispMsgsSem;
-	static gdisp_lld_msg_t	gdispMsgs[GDISP_QUEUE_SIZE];
-	static 					DECLARE_THREAD_STACK(waGDISPThread, GDISP_THREAD_STACK_SIZE);
+#if GDISP_HARDWARE_STREAM_END
+	#define STREAM_CLEAR()		if ((GC->flags & GDISP_FLG_INSTREAM)) {	\
+									gdisp_lld_stream_end();				\
+									GC->flags &= ~GDISP_FLG_INSTREAM;	\
+								}
+#else
+	#define STREAM_CLEAR()		GC->flags &= ~GDISP_FLG_INSTREAM
 #endif
 
-/*===========================================================================*/
-/* Driver local functions.                                                   */
-/*===========================================================================*/
+#define NEED_CLIPPING	(!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP))
 
-#if GDISP_NEED_ASYNC
-	static DECLARE_THREAD_FUNCTION(GDISPThreadHandler, arg) {
-		(void)arg;
-		gdisp_lld_msg_t	*pmsg;
+/*==========================================================================*/
+/* Internal functions.														*/
+/*==========================================================================*/
 
-		while(1) {
-			/* Wait for msg with work to do. */
-			pmsg = (gdisp_lld_msg_t *)gfxQueueGet(&gdispQueue, TIME_INFINITE);
-
-			/* OK - we need to obtain the mutex in case a synchronous operation is occurring */
-			gfxMutexEnter(&gdispMutex);
-
-			gdisp_lld_msg_dispatch(pmsg);
-
-			/* Mark the message as free */
-			pmsg->action = GDISP_LLD_MSG_NOP;
-
-			gfxMutexExit(&gdispMutex);
+// drawpixel_clip()
+// Parameters:	x,y
+// Alters:		cx, cy (if using streaming)
+#if GDISP_HARDWARE_DRAWPIXEL
+	// Best is hardware accelerated pixel draw
+	#if NEED_CLIPPING
+		static INLINE void drawpixel_clip(void) {
+			if (GC->p.x >= GC->clipx0 && GC->p.x < GC->clipx1 && GC->p.y >= GC->clipy0 && GC->p.y < GC->clipy1)
+				gdisp_lld_draw_pixel();
 		}
-		return 0;
+	#else
+		#define drawpixel_clip()	gdisp_lld_draw_pixel()
+	#endif
+#else
+	// Worst is streaming
+	static INLINE void drawpixel_clip(void) {
+		#if NEED_CLIPPING
+			if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1)
+				return;
+		#endif
+
+		GC->cx = GC->cy = 1;
+		gdisp_lld_stream_start();
+		gdisp_lld_stream_color();
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end();
+		#endif
+	}
+#endif
+
+// fillarea()
+// Parameters:	x,y cx,cy and color
+// Alters:		nothing
+// Note:		This is not clipped
+#if GDISP_HARDWARE_FILLS
+	// Best is hardware accelerated area fill
+	#define fillarea()	gdisp_lld_fill_area()
+#elif GDISP_HARDWARE_STREAM
+	// Next best is hardware streaming
+	static INLINE void fillarea(void) {
+		uint32_t	area;
+
+		area = (uint32_t)GC->p.cx * GC->p.cy;
+
+		gdisp_lld_stream_start();
+		for(; area; area--)
+			gdisp_lld_stream_color();
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end(gc);
+		#endif
+	}
+#else
+	// Worst is drawing pixels
+	static INLINE void fillarea(void) {
+		coord_t x0, y0, x1, y1;
+
+		x0 = GC->p.x;
+		y0 = GC->p.y;
+		x1 = GC->p.x + GC->p.cx;
+		y1 = GC->p.y + GC->p.cy;
+		for(; GC->p.y < y1; GC->p.y++, GC->p.x = x0)
+			for(; GC->p.x < x1; GC->p.x++)
+				gdisp_lld_draw_pixel();
+		GC->p.y = y0;
+	}
+#endif
+
+#if NEED_CLIPPING
+	#define TEST_CLIP_AREA(x,y,cx,cy)													\
+				if ((x) < GC->clipx0) { (cx) -= GC->clipx0 - (x); (x) = GC->clipx0; }	\
+				if ((y) < GC->clipy0) { (cy) -= GC->clipy0 - (y); (y) = GC->clipy0; }	\
+				if ((x) + (cx) > GC->clipx1)	(cx) = GC->clipx1 - (x);				\
+				if ((y) + (cy) > GC->clipy1)	(cy) = GC->clipy1 - (y);				\
+				if ((cx) > 0 && (cy) > 0)
+#else
+	#define TEST_CLIP_AREA(x,y,cx,cy)
+#endif
+
+// Parameters:	x,y and x1
+// Alters:		x,y x1,y1 cx,cy
+static void hline_clip(void) {
+	// Swap the points if necessary so it always goes from x to x1
+	if (GC->p.x1 < GC->p.x) {
+		GC->p.cx = GC->p.x; GC->p.x = GC->p.x1; GC->p.x1 = GC->p.cx;
 	}
 
-	static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) {
-		gdisp_lld_msg_t	*p;
+	// Clipping
+	#if NEED_CLIPPING
+		if (GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) return;
+		if (GC->p.x < GC->clipx0) GC->p.x = GC->clipx0;
+		if (GC->p.x1 >= GC->clipx1) GC->p.x1 = GC->clipx1 - 1;
+		if (GC->p.x1 < GC->p.x) return;
+	#endif
 
-		while(1) {		/* To be sure, to be sure */
+	// This is an optimization for the point case. It is only worthwhile however if we
+	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
+	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM)
+		// Is this a point
+		if (GC->p.x == GC->p.x1) {
+			#if GDISP_HARDWARE_DRAWPIXEL
+				// Best is hardware accelerated pixel draw
+				gdisp_lld_draw_pixel();
+			#else
+				// Worst is streaming
+				GC->p.cx = GC->p.cy = 1;
+				gdisp_lld_stream_start();
+				gdisp_lld_stream_color();
+				#if GDISP_HARDWARE_STREAM_END
+					gdisp_lld_stream_end();
+				#endif
+			#endif
+			return;
+		}
+	#endif
 
-			/* Wait for a slot */
-			gfxSemWait(&gdispMsgsSem, TIME_INFINITE);
+	#if GDISP_HARDWARE_FILLS
+		// Best is hardware accelerated area fill
+		GC->p.cx = GC->p.x1 - GC->p.x + 1;
+		GC->p.cy = 1;
+		gdisp_lld_fill_area();
+	#elif GDISP_HARDWARE_STREAM
+		// Next best is streaming
+		GC->p.cx = GC->p.x1 - GC->p.x;
+		gdisp_lld_stream_start();
+		do { gdisp_lld_stream_color(); } while(GC->p.cx--);
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end();
+		#endif
+	#else
+		// Worst is drawing pixels
+		for(; GC->p.x <= GC->p.x1; GC->p.x++)
+			gdisp_lld_draw_pixel();
+	#endif
+}
 
-			/* Find the slot */
-			gfxMutexEnter(&gdispMsgsMutex);
-			for(p=gdispMsgs; p < &gdispMsgs[GDISP_QUEUE_SIZE]; p++) {
-				if (p->action == GDISP_LLD_MSG_NOP) {
-					/* Allocate it */
-					p->action = action;
-					gfxMutexExit(&gdispMsgsMutex);
-					return p;
-				}
+// Parameters:	x,y and y1
+// Alters:		x,y x1,y1 cx,cy
+static void vline_clip(void) {
+	// Swap the points if necessary so it always goes from y to y1
+	if (GC->p.y1 < GC->p.y) {
+		GC->p.cy = GC->p.y; GC->p.y = GC->p.y1; GC->p.y1 = GC->p.cy;
+	}
+
+	// Clipping
+	#if NEED_CLIPPING
+		if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1) return;
+		if (GC->p.y < GC->clipy0) GC->p.y = GC->clipy0;
+		if (GC->p.y1 >= GC->clipy1) GC->p.y1 = GC->clipy1 - 1;
+		if (GC->p.y1 < GC->p.y) return;
+	#endif
+
+	// This is an optimization for the point case. It is only worthwhile however if we
+	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
+	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM)
+		// Is this a point
+		if (GC->p.y == GC->p.y1) {
+			#if GDISP_HARDWARE_DRAWPIXEL
+				// Best is hardware accelerated pixel draw
+				gdisp_lld_draw_pixel();
+			#else
+				// Worst is streaming
+				GC->p.cx = GC->p.cy = 1;
+				gdisp_lld_stream_start();
+				gdisp_lld_stream_color();
+				#if GDISP_HARDWARE_STREAM_END
+					gdisp_lld_stream_end();
+				#endif
+			#endif
+			return;
+		}
+	#endif
+
+	#if GDISP_HARDWARE_FILLS
+		// Best is hardware accelerated area fill
+		GC->p.cy = GC->p.y1 - GC->p.y + 1;
+		GC->p.cx = 1;
+		gdisp_lld_fill_area();
+	#elif GDISP_HARDWARE_STREAM
+		// Next best is streaming
+		GC->p.cy = GC->p.y1 - GC->p.y;
+		gdisp_lld_stream_start();
+		do { gdisp_lld_stream_color(); } while(GC->p.cy--);
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end();
+		#endif
+	#else
+		// Worst is drawing pixels
+		for(; GC->p.y <= GC->p.y1; GC->p.y++)
+			gdisp_lld_draw_pixel();
+	#endif
+}
+
+// Parameters:	x,y and x1,y1
+// Alters:		x,y x1,y1 cx,cy
+static void line_clip(void) {
+	int16_t dy, dx;
+	int16_t addx, addy;
+	int16_t P, diff, i;
+
+	// Is this a horizontal line (or a point)
+	if (GC->p.y == GC->p.y1) {
+		hline_clip();
+		return;
+	}
+
+	// Is this a vertical line (or a point)
+	if (GC->p.x == GC->p.x1) {
+		vline_clip();
+		return;
+	}
+
+	// Not horizontal or vertical
+
+	// Use Bresenham's line drawing algorithm.
+	//	This should be replaced with fixed point slope based line drawing
+	//	which is more efficient on modern processors as it branches less.
+	//	When clipping is needed, all the clipping could also be done up front
+	//	instead of on each pixel.
+
+	if (GC->p.x1 >= GC->p.x) {
+		dx = GC->p.x1 - GC->p.x;
+		addx = 1;
+	} else {
+		dx = GC->p.x - GC->p.x1;
+		addx = -1;
+	}
+	if (GC->p.y1 >= GC->p.y) {
+		dy = GC->p.y1 - GC->p.y;
+		addy = 1;
+	} else {
+		dy = GC->p.y - GC->p.y1;
+		addy = -1;
+	}
+
+	if (dx >= dy) {
+		dy <<= 1;
+		P = dy - dx;
+		diff = P - dx;
+
+		for(i=0; i<=dx; ++i) {
+			drawpixel_clip();
+			if (P < 0) {
+				P  += dy;
+				GC->p.x += addx;
+			} else {
+				P  += diff;
+				GC->p.x += addx;
+				GC->p.y += addy;
 			}
-			gfxMutexExit(&gdispMsgsMutex);
+		}
+	} else {
+		dx <<= 1;
+		P = dx - dy;
+		diff = P - dy;
 
-			/* Oops - none found, try again */
-			gfxSemSignal(&gdispMsgsSem);
+		for(i=0; i<=dy; ++i) {
+			drawpixel_clip();
+			if (P < 0) {
+				P  += dx;
+				GC->p.y += addy;
+			} else {
+				P  += diff;
+				GC->p.x += addx;
+				GC->p.y += addy;
+			}
 		}
 	}
-#endif
+}
 
 /*===========================================================================*/
 /* Driver exported functions.                                                */
 /*===========================================================================*/
 
 /* Our module initialiser */
-#if GDISP_NEED_MULTITHREAD
-	void _gdispInit(void) {
-		/* Initialise Mutex */
-		gfxMutexInit(&gdispMutex);
+void _gdispInit(void) {
+	MUTEX_INIT();
 
-		/* Initialise driver */
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_init();
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ASYNC
-	void _gdispInit(void) {
-		unsigned		i;
-		gfxThreadHandle	hth;
+	/* Initialise driver */
+	MUTEX_ENTER();
+	gdisp_lld_init();
+	#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+		#if GDISP_HARDWARE_CLIP
+			GC->p.x = x;
+			GC->p.y = y;
+			GC->p.cx = cx;
+			GC->p.cy = cy;
+			gdisp_lld_set_clip();
+		#else
+			GC->clipx0 = 0;
+			GC->clipy0 = 0;
+			GC->clipx1 = GC->g.Width;
+			GC->clipy1 = GC->g.Height;
+		#endif
+	#endif
+	MUTEX_EXIT();
+}
 
-		/* Mark all the Messages as free */
-		for(i=0; i < GDISP_QUEUE_SIZE; i++)
-			gdispMsgs[i].action = GDISP_LLD_MSG_NOP;
+void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) {
+	MUTEX_ENTER();
 
-		/* Initialise our Queue, Mutex's and Counting Semaphore.
-		 * 	A Mutex is required as well as the Queue and Thread because some calls have to be synchronous.
-		 *	Synchronous calls get handled by the calling thread, asynchronous by our worker thread.
-		 */
-		gfxQueueInit(&gdispQueue);
-		gfxMutexInit(&gdispMutex);
-		gfxMutexInit(&gdispMsgsMutex);
-		gfxSemInit(&gdispMsgsSem, GDISP_QUEUE_SIZE, GDISP_QUEUE_SIZE);
+	#if NEED_CLIPPING
+		// Test if the area is valid - if not then exit
+		if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) {
+			MUTEX_EXIT();
+			return;
+		}
+	#endif
 
-		hth = gfxThreadCreate(waGDISPThread, sizeof(waGDISPThread), NORMAL_PRIORITY, GDISPThreadHandler, NULL);
-		if (hth) gfxThreadClose(hth);
+	GC->flags |= GDISP_FLG_INSTREAM;
 
-		/* Initialise driver - synchronous */
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_init();
-		gfxMutexExit(&gdispMutex);
-	}
-#else
-	void _gdispInit(void) {
-		gdisp_lld_init();
-	}
-#endif
+	#if GDISP_HARDWARE_STREAM
+		// Best is hardware streaming
+		GC->p.x = x;
+		GC->p.y = y;
+		GC->p.cx = cx;
+		GC->p.cy = cy;
+		gdisp_lld_stream_start();
+	#else
+		// Worst - save the parameters and use pixel drawing
 
-#if GDISP_NEED_MULTITHREAD
-	bool_t gdispIsBusy(void) {
-		return FALSE;
-	}
-#elif GDISP_NEED_ASYNC
-	bool_t gdispIsBusy(void) {
-		return !gfxQueueIsEmpty(&gdispQueue);
-	}
-#endif
+		// Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position
+		GC->p.x1 = GC->p.x = x;
+		GC->p.y1 = GC->p.y = y;
+		GC->p.x2 = GC->p.x + GC->p.cx;
+		GC->p.x2 = GC->p.x + GC->p.cx;
+	#endif
 
-#if GDISP_NEED_MULTITHREAD
-	void gdispClear(color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_clear(color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ASYNC
-	void gdispClear(color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CLEAR);
-		p->clear.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+	// Don't release the mutex as gdispStreamEnd() will do that.
+}
 
-#if GDISP_NEED_MULTITHREAD
-	void gdispDrawPixel(coord_t x, coord_t y, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_draw_pixel(x, y, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ASYNC
-	void gdispDrawPixel(coord_t x, coord_t y, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWPIXEL);
-		p->drawpixel.x = x;
-		p->drawpixel.y = y;
-		p->drawpixel.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+void gdispStreamColor(color_t color) {
+	// Don't touch the mutex as we should already own it
+
+	// Ignore this call if we are not streaming
+	if (!(GC->flags & GDISP_FLG_INSTREAM))
+		return;
+
+	#if GDISP_HARDWARE_STREAM
+		// Best is hardware streaming
+		GC->p.color = color;
+		gdisp_lld_stream_color();
+	#else
+		// Worst is using pixel drawing
+		GC->p.color = color;
+		gdisp_lld_draw_pixel();
+
+		// Just wrap at end-of-line and end-of-buffer
+		if (++GC->p.x >= GC->p.x2) {
+			GC->p.x = GC->p.x1;
+			if (++GC->p.y >= GC->p.x2)
+				GC->p.y = GC->p.y1;
+		}
+	#endif
+}
+
+void gdispStreamEnd(void) {
+	// Only release the mutex and end the stream if we are actually streaming.
+	if (!(GC->flags & GDISP_FLG_INSTREAM))
+		return;
+
+	#if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_END
+		gdisp_lld_stream_end();
+	#endif
+	GC->flags &= ~GDISP_FLG_INSTREAM;
+	MUTEX_EXIT();
+}
+
+void gdispDrawPixel(coord_t x, coord_t y, color_t color) {
+	MUTEX_ENTER();
+	GC->p.x		= x;
+	GC->p.y		= y;
+	GC->p.color	= color;
+	drawpixel_clip();
+	MUTEX_EXIT();
+}
 	
-#if GDISP_NEED_MULTITHREAD
-	void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_draw_line(x0, y0, x1, y1, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ASYNC
-	void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWLINE);
-		p->drawline.x0 = x0;
-		p->drawline.y0 = y0;
-		p->drawline.x1 = x1;
-		p->drawline.y1 = y1;
-		p->drawline.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
+	MUTEX_ENTER();
+	GC->p.x = x0;
+	GC->p.y = y0;
+	GC->p.x1 = x1;
+	GC->p.y1 = y1;
+	GC->p.color = color;
+	line_clip();
+	MUTEX_EXIT();
+}
 
-#if GDISP_NEED_MULTITHREAD
-	void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_fill_area(x, y, cx, cy, color);
-		gfxMutexExit(&gdispMutex);
+void gdispClear(color_t color) {
+	// Note - clear() ignores the clipping area. It clears the screen.
+	MUTEX_ENTER();
+
+	#if GDISP_HARDWARE_CLEARS
+		// Best is hardware accelerated clear
+		GC->p.color = color;
+		gdisp_lld_clear();
+	#elif GDISP_HARDWARE_FILLS
+		// Next best is hardware accelerated area fill
+		GC->p.x = GC->p.y = 0;
+		GC->p.cx = GC->g.Width;
+		GC->p.cy = GC->g.Height;
+		GC->p.color = color;
+		gdisp_lld_fill_area();
+	#elif GDISP_HARDWARE_STREAM
+		// Next best is streaming
+		uint32_t	area;
+
+		GC->p.x = GC->p.y = 0;
+		GC->p.cx = GC->g.Width;
+		GC->p.cy = GC->g.Height;
+		GC->p.color = color;
+		area = (uint32_t)GC->p.cx * GC->p.cy;
+
+		gdisp_lld_stream_start();
+		for(; area; area--)
+			gdisp_lld_stream_color();
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end(gc);
+		#endif
+	#else
+		// Worst is drawing pixels
+		GC->p.color = color;
+		for(GC->p.y = 0; GC->p.y < GC->g.Height; GC->p.y++)
+			for(GC->p.x = 0; GC->p.x < GC->g.Width; GC->p.x++)
+				gdisp_lld_draw_pixel();
+	#endif
+	MUTEX_EXIT();
+}
+
+void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
+	MUTEX_ENTER();
+	TEST_CLIP_AREA(x,y,cx,cy) {
+		GC->p.x = x;
+		GC->p.y = y;
+		GC->p.cx = cx;
+		GC->p.cy = cy;
+		GC->p.color = color;
+		fillarea();
 	}
-#elif GDISP_NEED_ASYNC
-	void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLAREA);
-		p->fillarea.x = x;
-		p->fillarea.y = y;
-		p->fillarea.cx = cx;
-		p->fillarea.cy = cy;
-		p->fillarea.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+	MUTEX_EXIT();
+}
 	
-#if GDISP_NEED_MULTITHREAD
-	void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_blit_area_ex(x, y, cx, cy, srcx, srcy, srccx, buffer);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ASYNC
-	void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_BLITAREA);
-		p->blitarea.x = x;
-		p->blitarea.y = y;
-		p->blitarea.cx = cx;
-		p->blitarea.cy = cy;
-		p->blitarea.srcx = srcx;
-		p->blitarea.srcy = srcy;
-		p->blitarea.srccx = srccx;
-		p->blitarea.buffer = buffer;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
+	MUTEX_ENTER();
+
+	#if NEED_CLIPPING
+		// This is a different cliping to fillarea() as it needs to take into account srcx,srcy
+		if (x < GC->clipx0) { cx -= GC->clipx0 - x; srcx += GC->clipx0 - x; x = GC->clipx0; }
+		if (y < GC->clipy0) { cy -= GC->clipy0 - y; srcy += GC->clipy0 - x; y = GC->clipy0; }
+		if (x+cx > GC->clipx1)	cx = GC->clipx1 - x;
+		if (y+cy > GC->clipy1)	cy = GC->clipy1 - y;
+		if (srcx+cx > srccx) cx = srccx - srcx;
+		if (cx <= 0 || cy <= 0) { MUTEX_EXIT(); return; }
+	#endif
+
+	#if GDISP_HARDWARE_BITFILLS
+		// Best is hardware bitfills
+		GC->p.x = x;
+		GC->p.y = y;
+		GC->p.cx = cx;
+		GC->p.cy = cy;
+		GC->p.x1 = srcx;
+		GC->p.y1 = srcy;
+		GC->p.x2 = srccx;
+		GC->p.ptr = (void *)buffer;
+		gdisp_lld_blit_area_ex();
+	#elif GDISP_HARDWARE_STREAM
+		// Next best is hardware streaming
+
+		// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
+		buffer += srcy*srccx+srcx;
+		srcx = x + cx;
+		srcy = y + cy;
+		srccx -= cx;
+
+		gdisp_lld_stream_start(gc);
+		for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) {
+			for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) {
+				GC->p.color = *buffer++;
+				gdisp_lld_stream_color();
+			}
+		}
+		#if GDISP_HARDWARE_STREAM_END
+			gdisp_lld_stream_end(gc);
+		#endif
+	#else
+		// Worst is drawing pixels
+
+		// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
+		buffer += srcy*srccx+srcx;
+		srcx = x + cx;
+		srcy = y + cy;
+		srccx -= cx;
+
+		for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) {
+			for(GC->p.x=x; GC->p.x < srcx; GC->p.x++) {
+				GC->p.color = *buffer++;
+				gdisp_lld_draw_pixel();
+			}
+		}
+	#endif
+	MUTEX_EXIT();
+}
 	
-#if (GDISP_NEED_CLIP && GDISP_NEED_MULTITHREAD)
+#if GDISP_NEED_CLIP
 	void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_set_clip(x, y, cx, cy);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_CLIP && GDISP_NEED_ASYNC
-	void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_SETCLIP);
-		p->setclip.x = x;
-		p->setclip.y = y;
-		p->setclip.cx = cx;
-		p->setclip.cy = cy;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
+		MUTEX_ENTER();
+		#if GDISP_HARDWARE_CLIP
+			// Best is using hardware clipping
+			GC->p.x = x;
+			GC->p.y = y;
+			GC->p.cx = cx;
+			GC->p.cy = cy;
+			gdisp_lld_set_clip();
+		#else
+			// Worst is using software clipping
+			if (x < 0) { cx += x; x = 0; }
+			if (y < 0) { cy += y; y = 0; }
+			if (cx <= 0 || cy <= 0 || x >= GC->g.Width || y >= GC->g.Height) { MUTEX_EXIT(); return; }
+			GC->clipx0 = x;
+			GC->clipy0 = y;
+			GC->clipx1 = x+cx;	if (GC->clipx1 > GC->g.Width) GC->clipx1 = GC->g.Width;
+			GC->clipy1 = y+cy;	if (GC->clipy1 > GC->g.Height) GC->clipy1 = GC->g.Height;
+		#endif
+		MUTEX_EXIT();
 	}
 #endif
 
-#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD)
+#if GDISP_NEED_CIRCLE
 	void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_draw_circle(x, y, radius, color);
-		gfxMutexExit(&gdispMutex);
+		coord_t a, b, P;
+
+		MUTEX_ENTER();
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		GC->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// Optimized to prevent double drawing
+		GC->p.x = x; GC->p.y = y + b; drawpixel_clip();
+		GC->p.x = x; GC->p.y = y - b; drawpixel_clip();
+		GC->p.x = x + b; GC->p.y = y; drawpixel_clip();
+		GC->p.x = x - b; GC->p.y = y; drawpixel_clip();
+		do {
+			GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip();
+			GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip();
+			GC->p.x = x + b; GC->p.y = y + a; drawpixel_clip();
+			GC->p.x = x - b; GC->p.y = y + a; drawpixel_clip();
+			GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip();
+			GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip();
+			GC->p.x = x + b; GC->p.y = y - a; drawpixel_clip();
+			GC->p.x = x - b; GC->p.y = y - a; drawpixel_clip();
+			if (P < 0)
+				P += 3 + 2*a++;
+			else
+				P += 5 + 2*(a++ - b--);
+		} while(a < b);
+		GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip();
+		GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip();
+		GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip();
+		GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip();
+		MUTEX_EXIT();
 	}
-#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC
-	void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCIRCLE);
-		p->drawcircle.x = x;
-		p->drawcircle.y = y;
-		p->drawcircle.radius = radius;
-		p->drawcircle.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
+#endif
+
+#if GDISP_NEED_CIRCLE
+	void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) {
+		coord_t a, b, P;
+
+		MUTEX_ENTER();
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		GC->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
+		GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();
+		GC->p.y = y+b; GC->p.x = x; drawpixel_clip();
+		GC->p.y = y-b; GC->p.x = x; drawpixel_clip();
+		do {
+			GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();
+			GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();
+			if (P < 0) {
+				P += 3 + 2*a++;
+			} else {
+				GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();
+				GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();
+				P += 5 + 2*(a++ - b--);
+			}
+		} while(a < b);
+		GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();
+		GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();
+		MUTEX_EXIT();
+	}
+#endif
+
+#if GDISP_NEED_ELLIPSE
+	void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
+		coord_t	dx, dy;
+		int32_t	a2, b2;
+		int32_t	err, e2;
+
+		MUTEX_ENTER();
+
+		// Calculate intermediates
+		dx = 0;
+		dy = b;
+		a2 = a*a;
+		b2 = b*b;
+		err = b2-(2*b-1)*a2;
+		GC->p.color = color;
+
+		// Away we go using Bresenham's ellipse algorithm
+		do {
+			GC->p.x = x + dx; GC->p.y = y + dy; drawpixel_clip();
+			GC->p.x = x - dx; GC->p.y = y + dy; drawpixel_clip();
+			GC->p.x = x - dx; GC->p.y = y - dy; drawpixel_clip();
+			GC->p.x = x + dx; GC->p.y = y - dy; drawpixel_clip();
+
+			e2 = 2*err;
+			if(e2 <  (2*dx+1)*b2) {
+				dx++;
+				err += (2*dx+1)*b2;
+			}
+			if(e2 > -(2*dy-1)*a2) {
+				dy--;
+				err -= (2*dy-1)*a2;
+			}
+		} while(dy >= 0);
+		MUTEX_EXIT();
 	}
 #endif
 	
-#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD)
-	void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_fill_circle(x, y, radius, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC
-	void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCIRCLE);
-		p->fillcircle.x = x;
-		p->fillcircle.y = y;
-		p->fillcircle.radius = radius;
-		p->fillcircle.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
-
-#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD)
-	void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_draw_ellipse(x, y, a, b, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC
-	void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWELLIPSE);
-		p->drawellipse.x = x;
-		p->drawellipse.y = y;
-		p->drawellipse.a = a;
-		p->drawellipse.b = b;
-		p->drawellipse.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
-	
-#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD)
+#if GDISP_NEED_ELLIPSE
 	void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_fill_ellipse(x, y, a, b, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC
-	void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLELLIPSE);
-		p->fillellipse.x = x;
-		p->fillellipse.y = y;
-		p->fillellipse.a = a;
-		p->fillellipse.b = b;
-		p->fillellipse.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+		coord_t	dx, dy;
+		int32_t	a2, b2;
+		int32_t	err, e2;
 
-#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD)
-	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_draw_arc(x, y, radius, start, end, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC
-	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWARC);
-		p->drawarc.x = x;
-		p->drawarc.y = y;
-		p->drawarc.radius = radius;
-		p->drawarc.start = start;
-		p->drawarc.end = end;
-		p->drawarc.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
-#endif
+		MUTEX_ENTER();
 
-#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD)
-	void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_fill_arc(x, y, radius, start, end, color);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC
-	void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLARC);
-		p->fillarc.x = x;
-		p->fillarc.y = y;
-		p->fillarc.radius = radius;
-		p->fillarc.start = start;
-		p->fillarc.end = end;
-		p->fillarc.color = color;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
+		// Calculate intermediates
+		dx = 0;
+		dy = b;
+		a2 = a*a;
+		b2 = b*b;
+		err = b2-(2*b-1)*a2;
+		GC->p.color = color;
+
+		// Away we go using Bresenham's ellipse algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a y is about to change value
+		do {
+			e2 = 2*err;
+			if(e2 <  (2*dx+1)*b2) {
+				dx++;
+				err += (2*dx+1)*b2;
+			}
+			if(e2 > -(2*dy-1)*a2) {
+				GC->p.y = y + dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip();
+				if (y) { GC->p.y = y - dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); }
+				dy--;
+				err -= (2*dy-1)*a2;
+			}
+		} while(dy >= 0);
+		MUTEX_EXIT();
 	}
 #endif
 
 #if GDISP_NEED_ARC
-void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
-	if (2*radius > cx || 2*radius > cy) {
-		gdispDrawBox(x, y, cx, cy, color);
-		return;
+	#if !GMISC_NEED_FIXEDTRIG && !GMISC_NEED_FASTTRIG
+		#include <math.h>
+	#endif
+
+	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
+		coord_t a, b, P, sedge, eedge;
+		uint8_t	full, sbit, ebit, tbit;
+
+		// Normalize the angles
+		if (start < 0)
+			start -= (start/360-1)*360;
+		else if (start >= 360)
+			start %= 360;
+		if (end < 0)
+			end -= (end/360-1)*360;
+		else if (end >= 360)
+			end %= 360;
+
+		sbit = 1<<(start/45);
+		ebit = 1<<(end/45);
+		full = 0;
+		if (start == end) {
+			full = 0xFF;
+		} else if (end < start) {
+			for(tbit=sbit<<1; tbit; tbit<<=1) full |= tbit;
+			for(tbit=ebit>>1; tbit; tbit>>=1) full |= tbit;
+		} else if (sbit < 0x80) {
+			for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit;
+		}
+
+		MUTEX_ENTER();
+		GC->p.color = color;
+
+		if (full) {
+			// Draw full sectors
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if (full & 0x60) { GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); }
+			if (full & 0x06) { GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); }
+			if (full & 0x81) { GC->p.y = y; GC->p.x = x+b; drawpixel_clip(); }
+			if (full & 0x18) { GC->p.y = y; GC->p.x = x-b; drawpixel_clip(); }
+			do {
+				if (full & 0x01) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); }
+				if (full & 0x02) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+				if (full & 0x04) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+				if (full & 0x08) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); }
+				if (full & 0x10) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); }
+				if (full & 0x20) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+				if (full & 0x40) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+				if (full & 0x80) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (full & 0xC0) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+			if (full & 0x0C) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+			if (full & 0x03) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+			if (full & 0x30) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+			if (full == 0xFF)
+				return;
+		}
+
+		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
+			sedge = NONFIXED(radius * ((sbit & 0x99) ? ffsin(start) : ffcos(start)) + FIXED0_5);
+			eedge = NONFIXED(radius * ((ebit & 0x99) ? ffsin(end) : ffcos(end)) + FIXED0_5);
+		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
+			sedge = round(radius * ((sbit & 0x99) ? fsin(start) : fcos(start)));
+			eedge = round(radius * ((ebit & 0x99) ? fsin(end) : fcos(end)));
+		#else
+			sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180)));
+			eedge = round(radius * ((ebit & 0x99) ? sin(end*M_PI/180) : cos(end*M_PI/180)));
+		#endif
+		if (sbit & 0xB4) sedge = -sedge;
+		if (ebit & 0xB4) eedge = -eedge;
+
+		if (sbit != ebit) {
+			// Draw start and end sectors
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if ((sbit & 0x20) || (ebit & 0x40)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); }
+			if ((sbit & 0x02) || (ebit & 0x04)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); }
+			if ((sbit & 0x80) || (ebit & 0x01)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); }
+			if ((sbit & 0x08) || (ebit & 0x10)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); }
+			do {
+				if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); }
+				if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+				if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+				if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); }
+				if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); }
+				if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+				if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+				if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge))
+				{ GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+			if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge))
+				{ GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge))
+				{ GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge))
+				{ GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+		} else if (end < start) {
+			// Draw start/end sector where it is a non-internal angle
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if (sbit & 0x60) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); }
+			if (sbit & 0x06) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); }
+			if (sbit & 0x81) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); }
+			if (sbit & 0x18) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); }
+			do {
+				if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); }
+				if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+				if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+				if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); }
+				if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); }
+				if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+				if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+				if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge)))
+				{ GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge)))
+				{ GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+			if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge)))
+				{ GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge)))
+				{ GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+		} else {
+			// Draw start/end sector where it is a internal angle
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); }
+			if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); }
+			if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); }
+			do {
+				if (((sbit & 0x01) && a >= sedge && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); }
+				if (((sbit & 0x02) && a <= sedge && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+				if (((sbit & 0x04) && a >= sedge && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+				if (((sbit & 0x08) && a <= sedge && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); }
+				if (((sbit & 0x10) && a >= sedge && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); }
+				if (((sbit & 0x20) && a <= sedge && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+				if (((sbit & 0x40) && a >= sedge && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+				if (((sbit & 0x80) && a <= sedge && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge))
+				{ GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge))
+				{ GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); }
+			if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge))
+				{ GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); }
+			if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge))
+				{ GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); }
+		}
+		MUTEX_EXIT();
 	}
-	gdispDrawArc(x+radius, y+radius, radius, 90, 180, color);
-	gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color);
-	gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
-	gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color);
-	gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
-	gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color);
-	gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
-	gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color);
-}
 #endif
 
 #if GDISP_NEED_ARC
-void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
-	coord_t radius2;
+	void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
+		coord_t a, b, P;
+		coord_t	sy, ey;
+		fixed	sxa, sxb, sxd, exa, exb, exd;
+		uint8_t	qtr;
 
-	radius2 = radius*2;
-	if (radius2 > cx || radius2 > cy) {
-		gdispFillArea(x, y, cx, cy, color);
-		return;
+		MUTEX_ENTER();
+
+		// Do the trig to get the formulas for the start and end lines.
+		sxa = exa = FIXED(x)+FIXED0_5;
+		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
+			sxb = radius*ffcos(start);	sy = -NONFIXED(radius*ffsin(start) + FIXED0_5);
+			exb = radius*ffcos(end);	ey = -NONFIXED(radius*ffsin(end) + FIXED0_5);
+		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
+			sxb = FP2FIXED(radius*fcos(start));	sy = -round(radius*fsin(start));
+			exb = FP2FIXED(radius*fcos(end));	ey = -round(radius*fsin(end));
+		#else
+			sxb = FP2FIXED(radius*cos(start*M_PI/180));	sy = -round(radius*sin(start*M_PI/180));
+			exb = FP2FIXED(radius*cos(end*M_PI/180));	ey = -round(radius*sin(end*M_PI/180));
+		#endif
+		sxd = sy ? sxb/sy : sxb;
+		exd = ey ? exb/ey : exb;
+
+		// Calculate which quarters and which direction we are traveling
+		qtr = 0;
+		if (sxb > 0)	qtr |= 0x01;		// S1=0001(1), S2=0000(0), S3=0010(2), S4=0011(3)
+		if (sy > 0) 	qtr |= 0x02;
+		if (exb > 0)	qtr |= 0x04;		// E1=0100(4), E2=0000(0), E3=1000(8), E4=1100(12)
+		if (ey > 0) 	qtr |= 0x08;
+		if (sy > ey)	qtr |= 0x10;		// order of start and end lines
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		GC->p.color = color;
+		sxb += sxa;
+		exb += exa;
+
+		// Away we go using Bresenham's circle algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
+
+		switch(qtr) {
+		case 0:		// S2E2 sy <= ey
+		case 1:		// S1E2 sy <= ey
+			if (ey && sy) {
+				GC->p.x = x; GC->p.x1 = x;									// E2S
+				sxa -= sxd; exa -= exd;
+			} else if (sy) {
+				GC->p.x = x-b; GC->p.x1 = x;								// C2S
+				sxa -= sxd;
+			} else if (ey) {
+				GC->p.x = x; GC->p.x1 = x+b;								// E2C
+				exa -= exd;
+			} else {
+				GC->p.x = x-b; GC->p.x1 = x+b;								// C2C
+			}
+			GC->p.y = y;
+			hline_clip();
+			do {
+				if (-a >= ey) {
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip();		// E2S
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= sy) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();				// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip();	// E2S
+						sxb += sxd; exb += exd;
+					} else if (-b >= sy) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip();			// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip();			// E2S
+			} else if (-a >= sy) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();					// C2S
+			} else if (qtr & 1) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			break;
+
+		case 2:		// S3E2 sy <= ey
+		case 3:		// S4E2 sy <= ey
+		case 6:		// S3E1 sy <= ey
+		case 7:		// S4E1 sy <= ey
+		case 18:	// S3E2 sy > ey
+		case 19:	// S4E2 sy > ey
+		case 22:	// S3E1 sy > ey
+		case 23:	// S4E1 sy > ey
+			GC->p.y = y; GC->p.x = x; GC->p.x1 = x+b; hline_clip();								// SE2C
+			sxa += sxd; exa -= exd;
+			do {
+				if (-a >= ey) {
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();		// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();					// C2C
+				}
+				if (a <= sy) {
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();		// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();					// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip();		// E2C
+						exb += exd;
+					} else if (!(qtr & 4)) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();					// C2C
+					}
+					if (b <= sy) {
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip();		// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); 				// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();				// E2C
+			} else if (!(qtr & 4)) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+			}
+			if (a <= sy) {
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+a; hline_clip();				// S2C
+			} else if (!(qtr & 1)) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip();							// C2C
+			}
+			break;
+
+		case 4:		// S2E1 sy <= ey
+		case 5:		// S1E1 sy <= ey
+			GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			do {
+				if (-a >= ey) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();				// C2S
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();				// E2C
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= sy) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();				// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip();			// C2S
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip();			// E2C
+						sxb += sxd; exb += exd;
+					} else if (-b >= sy) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip();			// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();							// C2C
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();					// C2S
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();					// E2C
+			} else if (-a >= sy) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();					// C2S
+			} else if (qtr & 1) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();									// C2C
+			break;
+
+		case 8:		// S2E3 sy <= ey
+		case 9:		// S1E3 sy <= ey
+		case 12:	// S2E4 sy <= ey
+		case 13:	// S1E4 sy <= ey
+		case 24:	// S2E3 sy > ey
+		case 25:	// S1E3 sy > ey
+		case 28:	// S2E3 sy > ey
+		case 29:	// S1E3 sy > ey
+			GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x; hline_clip();								// C2SE
+			sxa -= sxd; exa += exd;
+			do {
+				if (-a >= sy) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();		// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();					// C2C
+				}
+				if (a <= ey) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();		// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();					// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip();		// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();					// C2C
+					}
+					if (b <= ey) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip();		// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); 				// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();				// C2S
+			} else if (qtr & 1) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+			}
+			if (a <= ey) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+			} else if (qtr & 4) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip();							// C2C
+			}
+			break;
+
+		case 10:	// S3E3 sy <= ey
+		case 14:	// S3E4 sy <= ey
+			GC->p.y = y; GC->p.x = x; drawpixel_clip();													// S2E
+			sxa += sxd; exa += exd;
+			do {
+				if (a <= sy) {
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip();		// S2E
+					sxa += sxd; exa += exd;
+				} else if (a <= ey) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (b <= sy) {
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip();		// S2E
+						sxb -= sxd; exb -= exd;
+					} else if (b <= ey) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip();				// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();							// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (a <= sy) {
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip();		// S2E
+			} else if (a <= ey) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+			} else if (qtr & 4) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+			}
+			break;
+
+		case 11:	// S4E3 sy <= ey
+		case 15:	// S4E4 sy <= ey
+			GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			do {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+				if (a <= sy) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();				// S2C
+					sxa += sxd; exa += exd;
+				} else if (a <= ey) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();							// C2C
+					if (b <= sy) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip();			// C2E
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip();			// S2C
+						sxb -= sxd; exb -= exd;
+					} else if (b <= ey) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip();			// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			if (a <= sy) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();					// C2E
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();					// S2C
+			} else if (a <= ey) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();					// C2E
+			} else if (qtr & 4) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			break;
+
+		case 16:	// S2E2	sy > ey
+		case 20:	// S2E1 sy > ey
+			GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			sxa -= sxd; exa -= exd;
+			do {
+				if (-a >= sy) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();				// C2S
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();				// E2C
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= ey) {
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();				// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)){
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); 						// C2C
+				}
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); 							// C2C
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip();			// C2S
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip();			// E2C
+						sxb += sxd; exb += exd;
+					} else if (-b >= ey) {
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip();			// E2C
+						exb += exd;
+					} else if (!(qtr & 4)){
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); 					// C2C
+					}
+					GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); 						// C2C
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip();					// C2S
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();					// E2C
+			} else if (-a >= ey) {
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();					// E2C
+			} else if (!(qtr & 4)){
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); 							// C2C
+			}
+			GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); 								// C2C
+			break;
+
+		case 17:	// S1E2 sy > ey
+		case 21:	// S1E1 sy > ey
+			if (sy) {
+				GC->p.x = x; GC->p.x1 = x;																// E2S
+				sxa -= sxd; exa -= exd;
+			} else {
+				GC->p.x = x; GC->p.x1 = x+b;															// E2C
+				exa -= exd;
+			}
+			GC->p.y = y;
+			hline_clip();
+			do {
+				if (-a >= sy) {
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip();		// E2S
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= ey) {
+					GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();				// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)) {
+					GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip();	// E2S
+						sxb += sxd; exb += exd;
+					} else if (-b >= ey) {
+						GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip();			// E2C
+						exb += exd;
+					} else if (!(qtr & 4)) {
+						GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip();			// E2S
+			} else if (-a >= ey) {
+				GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip();					// E2C
+			} else if (!(qtr & 4)) {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			break;
+
+		case 26:	// S3E3 sy > ey
+		case 27:	// S4E3 sy > ey
+			GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			do {
+				GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+				if (a <= ey) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();				// C2E
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();				// S2C
+					sxa += sxd; exa += exd;
+				} else if (a <= sy) {
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();				// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();							// C2C
+					if (b <= ey) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip();			// C2E
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip();			// S2C
+						sxb -= sxd; exb -= exd;
+					} else if (b <= sy) {
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip();			// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();									// C2C
+			if (a <= ey) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip();					// C2E
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();					// S2C
+			} else if (a <= sy) {
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();					// S2C
+			} else if (!(qtr & 4)) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			break;
+
+		case 30:	// S3E4 sy > ey
+		case 31:	// S4E4 sy > ey
+			do {
+				if (a <= ey) {
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip();		// S2E
+					sxa += sxd; exa += exd;
+				} else if (a <= sy) {
+					GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();				// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (b <= ey) {
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip();	// S2E
+						sxb -= sxd; exb -= exd;
+					} else if (b <= sy) {
+						GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip();			// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip();						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (a <= ey) {
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();				// S2C
+			} else if (a <= sy) {
+				GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip();					// S2C
+			} else if (!(qtr & 4)) {
+				GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip();								// C2C
+			}
+			break;
+		}
+
+		MUTEX_EXIT();
 	}
-	gdispFillArc(x+radius, y+radius, radius, 90, 180, color);
-	gdispFillArea(x+radius+1, y, cx-radius2, radius, color);
-	gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
-	gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
-	gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color);
-	gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
-	gdispFillArea(x, y+radius, cx, cy-radius2, color);
-}
+
 #endif
 
-#if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC))
+#if GDISP_NEED_ARC
+	void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
+		if (2*radius > cx || 2*radius > cy) {
+			gdispDrawBox(x, y, cx, cy, color);
+			return;
+		}
+		gdispDrawArc(x+radius, y+radius, radius, 90, 180, color);
+		gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color);
+		gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
+		gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color);
+		gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
+		gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color);
+		gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
+		gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color);
+	}
+#endif
+
+#if GDISP_NEED_ARC
+	void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
+		coord_t radius2;
+
+		radius2 = radius*2;
+		if (radius2 > cx || radius2 > cy) {
+			gdispFillArea(x, y, cx, cy, color);
+			return;
+		}
+		gdispFillArc(x+radius, y+radius, radius, 90, 180, color);
+		gdispFillArea(x+radius+1, y, cx-radius2, radius, color);
+		gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
+		gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
+		gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color);
+		gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
+		gdispFillArea(x, y+radius, cx, cy-radius2, color);
+	}
+#endif
+
+#if GDISP_NEED_PIXELREAD
 	color_t gdispGetPixelColor(coord_t x, coord_t y) {
 		color_t		c;
 
 		/* Always synchronous as it must return a value */
-		gfxMutexEnter(&gdispMutex);
-		c = gdisp_lld_get_pixel_color(x, y);
-		gfxMutexExit(&gdispMutex);
+		MUTEX_ENTER();
+		GC->p.x = x;
+		GC->p.y = y;
+		c = gdisp_lld_get_pixel_color();
+		MUTEX_EXIT();
 
 		return c;
 	}
 #endif
 
-#if (GDISP_NEED_SCROLL && GDISP_NEED_MULTITHREAD)
+#if GDISP_NEED_SCROLL
 	void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_SCROLL && GDISP_NEED_ASYNC
-	void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_VERTICALSCROLL);
-		p->verticalscroll.x = x;
-		p->verticalscroll.y = y;
-		p->verticalscroll.cx = cx;
-		p->verticalscroll.cy = cy;
-		p->verticalscroll.lines = lines;
-		p->verticalscroll.bgcolor = bgcolor;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
+		MUTEX_ENTER();
+		#if NEED_CLIPPING
+			if (x < GC->clipx0) { cx -= GC->clipx0 - x; x = GC->clipx0; }
+			if (y < GC->clipy0) { cy -= GC->clipy0 - y; y = GC->clipy0; }
+			if (cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; }
+			if (x+cx > GC->clipx1)	cx = GC->clipx1 - x;
+			if (y+cy > GC->clipy1)	cy = GC->clipy1 - y;
+		#endif
+		GC->p.x = x;
+		GC->p.y = y;
+		GC->p.cx = cx;
+		GC->p.cy = cy;
+		GC->p.y1 = lines;
+		GC->p.color = bgcolor;
+		gdisp_lld_vertical_scroll();
+		MUTEX_EXIT();
 	}
 #endif
 
-#if (GDISP_NEED_CONTROL && GDISP_NEED_MULTITHREAD)
-	void gdispControl(unsigned what, void *value) {
-		gfxMutexEnter(&gdispMutex);
-		gdisp_lld_control(what, value);
-		gfxMutexExit(&gdispMutex);
-	}
-#elif GDISP_NEED_CONTROL && GDISP_NEED_ASYNC
-	void gdispControl(unsigned what, void *value) {
-		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CONTROL);
-		p->control.what = what;
-		p->control.value = value;
-		gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE);
-	}
+#if GDISP_NEED_CONTROL
+	#if GDISP_HARDWARE_CONTROL
+		void gdispControl(unsigned what, void *value) {
+			MUTEX_ENTER();
+			GC->p.x = what;
+			GC->p.ptr = value;
+			gdisp_lld_control();
+			#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
+				if (what == GDISP_CONTROL_ORIENTATION) {
+					#if GDISP_HARDWARE_CLIP
+						// Best is hardware clipping
+						GC->p.x = 0;
+						GC->p.y = 0;
+						GC->p.cx = GC->g.Width;
+						GC->p.cy = GC->g.Height;
+						gdisp_lld_set_clip();
+					#else
+						// Worst is software clipping
+						GC->clipx0 = 0;
+						GC->clipy0 = 0;
+						GC->clipx1 = GC->g.Width;
+						GC->clipy1 = GC->g.Height;
+					#endif
+				}
+			#endif
+			MUTEX_EXIT();
+		}
+	#else
+		void gdispControl(unsigned what, void *value) {
+			(void)what;
+			(void)value;
+			/* Ignore everything */
+		}
+	#endif
 #endif
 
-#if (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) && GDISP_NEED_QUERY
-	void *gdispQuery(unsigned what) {
-		void *res;
+#if GDISP_NEED_QUERY
+	#if GDISP_HARDWARE_QUERY
+		void *gdispQuery(unsigned what) {
+			void *res;
 
-		gfxMutexEnter(&gdispMutex);
-		res = gdisp_lld_query(what);
-		gfxMutexExit(&gdispMutex);
-		return res;
-	}
+			MUTEX_ENTER();
+			GC->p.x = (coord_t)what;
+			res = gdisp_lld_query();
+			MUTEX_EXIT();
+			return res;
+		}
+	#else
+		void *gdispQuery(unsigned what) {
+			(void) what;
+			return (void *)-1;
+		}
+	#endif
 #endif
 
 /*===========================================================================*/
@@ -458,29 +1546,30 @@ void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t r
 /*===========================================================================*/
 
 void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-	/* No mutex required as we only call high level functions which have their own mutex */
-	coord_t	x1, y1;
+	if (cx <= 0 || cy <= 0) return;
+	cx = x+cx-1; cy = y+cy-1;			// cx, cy are now the end point.
 
-	x1 = x+cx-1;
-	y1 = y+cy-1;
+	MUTEX_ENTER();
 
-	if (cx > 2) {
-		if (cy >= 1) {
-			gdispDrawLine(x, y, x1, y, color);
-			if (cy >= 2) {
-				gdispDrawLine(x, y1, x1, y1, color);
-				if (cy > 2) {
-					gdispDrawLine(x, y+1, x, y1-1, color);
-					gdispDrawLine(x1, y+1, x1, y1-1, color);
-				}
+	GC->p.color = color;
+
+	if (cx - x > 2) {
+		GC->p.x = x; GC->p.y = y; GC->p.x1 = cx; hline_clip();
+		if (y != cy) {
+			GC->p.x = x; GC->p.y = cy; GC->p.x1 = cx; hline_clip();
+			if (cy - y > 2) {
+				y++; cy--;
+				GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip();
+				GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip();
 			}
 		}
-	} else if (cx == 2) {
-		gdispDrawLine(x, y, x, y1, color);
-		gdispDrawLine(x1, y, x1, y1, color);
-	} else if (cx == 1) {
-		gdispDrawLine(x, y, x, y1, color);
+	} else {
+		GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip();
+		if (x != cx) {
+			GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip();
+		}
 	}
+	MUTEX_EXIT();
 }
 
 #if GDISP_NEED_CONVEX_POLYGON
@@ -488,9 +1577,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 		const point	*epnt, *p;
 
 		epnt = &pntarray[cnt-1];
-		for(p = pntarray; p < epnt; p++)
-			gdispDrawLine(tx+p->x, ty+p->y, tx+p[1].x, ty+p[1].y, color);
-		gdispDrawLine(tx+p->x, ty+p->y, tx+pntarray->x, ty+pntarray->y, color);
+
+		MUTEX_ENTER();
+		GC->p.color = color;
+		for(p = pntarray; p < epnt; p++) {
+			GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+p[1].x; GC->p.y1=ty+p[1].y; line_clip();
+		}
+		GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+pntarray->x; GC->p.y1=ty+pntarray->y; line_clip();
+		MUTEX_EXIT();
 	}
 
 	void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) {
@@ -510,21 +1604,21 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 		y = rpnt->y;
 
 		/* Work out the slopes of the two attached line segs */
-		lpnt = rpnt <= pntarray ? epnts : rpnt-1;
-		while (lpnt->y == y) {
+		for (lpnt = rpnt <= pntarray ? epnts : rpnt-1; lpnt->y == y; cnt--) {
+			if (!cnt) return;
 			lx = FIXED(lpnt->x);
 			lpnt = lpnt <= pntarray ? epnts : lpnt-1;
-			if (!cnt--) return;
 		}
-		rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-		while (rpnt->y == y) {
-			rx = rpnt->x<<16;
+		for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
+			if (!cnt) return;
+			rx = FIXED(rpnt->x);
 			rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-			if (!cnt--) return;
 		}
 		lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
 		rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
 
+		MUTEX_ENTER();
+		GC->p.color = color;
 		while(1) {
 			/* Determine our boundary */
 			ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y;
@@ -539,38 +1633,40 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 				 * of pixels.
 				 */
 				if (lxc < rxc) {
-					if (rxc - lxc == 1)
-						gdispDrawPixel(tx+lxc, ty+y, color);
-					else
-						gdispDrawLine(tx+lxc, ty+y, tx+rxc-1, ty+y, color);
+					GC->p.x=tx+lxc; GC->p.y=ty+y; GC->p.x1=tx+rxc-1; hline_clip();
 				} else if (lxc > rxc) {
-					if (lxc - rxc == 1)
-						gdispDrawPixel(tx+rxc, ty+y, color);
-					else
-						gdispDrawLine(tx+rxc, ty+y, tx+lxc-1, ty+y, color);
+					GC->p.x=tx+rxc; GC->p.y=ty+y; GC->p.x1=tx+lxc-1; hline_clip();
 				}
 
 				lx += lk;
 				rx += rk;
 			}
 
-			if (!cnt--) return;
+			if (!cnt) {
+				MUTEX_EXIT();
+				return;
+			}
+			cnt--;
 
 			/* Replace the appropriate point */
 			if (ymax == lpnt->y) {
-				lpnt = lpnt <= pntarray ? epnts : lpnt-1;
-				while (lpnt->y == y) {
+				for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) {
+					if (!cnt) {
+						MUTEX_EXIT();
+						return;
+					}
 					lx = FIXED(lpnt->x);
 					lpnt = lpnt <= pntarray ? epnts : lpnt-1;
-					if (!cnt--) return;
 				}
 				lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
 			} else {
-				rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-				while (rpnt->y == y) {
+				for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
+					if (!cnt) {
+						MUTEX_EXIT();
+						return;
+					}
 					rx = FIXED(rpnt->x);
 					rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-					if (!cnt--) return;
 				}
 				rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
 			}
@@ -582,146 +1678,130 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 	#include "mcufont.h"
 
 	#if GDISP_NEED_ANTIALIAS && GDISP_NEED_PIXELREAD
-		static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return;
 			if (alpha == 255) {
-				if (count == 1)
-					gdispDrawPixel(x, y, ((color_t *)state)[0]);
-				else
-					gdispFillArea(x, y, count, 1, ((color_t *)state)[0]);
+				GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color;
+				hline_clip();
 			} else {
-				while (count--) {
-					gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], gdispGetPixelColor(x, y), alpha));
-					x++;
+				for (; count; count--, x++) {
+					GC->p.x = x; GC->p.y = y;
+					GC->p.color = gdispBlendColor(GC->t.color, gdisp_lld_get_pixel_color(), alpha);
+					drawpixel_clip();
 				}
 			}
 		}
 	#else
-		static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			(void) state;
+			if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return;
 			if (alpha > 0x80) {			// A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased
-				if (count == 1)
-					gdispDrawPixel(x, y, ((color_t *)state)[0]);
-				else
-					gdispFillArea(x, y, count, 1, ((color_t *)state)[0]);
+				GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color;
+				hline_clip();
 			}
 		}
 	#endif
 
-	void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		mf_render_character(font, x, y, c, text_draw_char_callback, &color);
-	}
-
 	#if GDISP_NEED_ANTIALIAS
-		static void text_fill_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+		static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			(void) state;
+			if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return;
 			if (alpha == 255) {
-				if (count == 1)
-					gdispDrawPixel(x, y, ((color_t *)state)[0]);
-				else
-					gdispFillArea(x, y, count, 1, ((color_t *)state)[0]);
+				GC->p.color = GC->t.color;
 			} else {
-				while (count--) {
-					gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], ((color_t *)state)[1], alpha));
-					x++;
-				}
+				GC->p.color = gdispBlendColor(GC->t.color, GC->t.bgcolor, alpha);
 			}
+			GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1;
+			hline_clip();
 		}
 	#else
-		#define text_fill_char_callback	text_draw_char_callback
+		#define fillcharline	drawcharline
 	#endif
 
-	void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		color_t		state[2];
-
-		state[0] = color;
-		state[1] = bgcolor;
-
-		gdispFillArea(x, y, mf_character_width(font, c) + font->baseline_x, font->height, bgcolor);
-		mf_render_character(font, x, y, c, text_fill_char_callback, state);
+	/* Callback to render characters. */
+	static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
+		(void) state;
+		return mf_render_character(GC->t.font, x, y, ch, drawcharline, 0);
 	}
 
-	typedef struct
-	{
-		font_t font;
-		color_t color;
-		coord_t	x, y;
-		coord_t	cx, cy;
-	} gdispDrawString_state_t;
-
 	/* Callback to render characters. */
-	static uint8_t gdispDrawString_callback(int16_t x, int16_t y, mf_char character, void *state)
-	{
-		gdispDrawString_state_t *s = state;
-		uint8_t w;
-		
-		w = mf_character_width(s->font, character);
-		if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy)
-			mf_render_character(s->font, x, y, character, text_draw_char_callback, &s->color);
-		return w;
+	static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
+		(void) state;
+		return mf_render_character(GC->t.font, x, y, ch, fillcharline, 0);
+	}
+
+	void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) {
+		MUTEX_ENTER();
+		GC->t.font = font;
+		GC->t.clipx0 = x;
+		GC->t.clipy0 = y;
+		GC->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x;
+		GC->t.clipy1 = y + font->height;
+		GC->t.color = color;
+		mf_render_character(font, x, y, c, drawcharline, 0);
+		MUTEX_EXIT();
+	}
+
+	void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) {
+		MUTEX_ENTER();
+		GC->p.cx = mf_character_width(font, c) + font->baseline_x;
+		GC->p.cy = font->height;
+		GC->t.font = font;
+		GC->t.clipx0 = GC->p.x = x;
+		GC->t.clipy0 = GC->p.y = y;
+		GC->t.clipx1 = GC->p.x+GC->p.cx;
+		GC->t.clipy1 = GC->p.y+GC->p.cy;
+		GC->t.color = color;
+		GC->t.bgcolor = GC->p.color = bgcolor;
+
+		TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) {
+			fillarea();
+			mf_render_character(font, x, y, c, fillcharline, 0);
+		}
+		MUTEX_EXIT();
 	}
 
 	void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		gdispDrawString_state_t state;
-		
-		state.font = font;
-		state.color = color;
-		state.x = x;
-		state.y = y;
-		state.cx = GDISP.Width - x;
-		state.cy = GDISP.Height - y;
-		
-		x += font->baseline_x;
-		mf_render_aligned(font, x, y, MF_ALIGN_LEFT, str, 0, gdispDrawString_callback, &state);
-	}
+		MUTEX_ENTER();
+		GC->t.font = font;
+		GC->t.clipx0 = x;
+		GC->t.clipy0 = y;
+		GC->t.clipx1 = x + mf_get_string_width(font, str, 0, 0);
+		GC->t.clipy1 = y + font->height;
+		GC->t.color = color;
 
-	typedef struct
-	{
-		font_t font;
-		color_t color[2];
-		coord_t	x, y;
-		coord_t	cx, cy;
-	} gdispFillString_state_t;
-
-	/* Callback to render characters. */
-	static uint8_t gdispFillString_callback(int16_t x, int16_t y, mf_char character, void *state)
-	{
-		gdispFillString_state_t *s = state;
-		uint8_t w;
-
-		w = mf_character_width(s->font, character);
-		if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy)
-			mf_render_character(s->font, x, y, character, text_fill_char_callback, s->color);
-		return w;
+		mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, 0);
+		MUTEX_EXIT();
 	}
 
 	void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		gdispFillString_state_t state;
-		
-		state.font = font;
-		state.color[0] = color;
-		state.color[1] = bgcolor;
-		state.x = x;
-		state.y = y;
-		state.cx = mf_get_string_width(font, str, 0, 0);
-		state.cy = font->height;
-		
-		gdispFillArea(x, y, state.cx, state.cy, bgcolor);
-		mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, gdispFillString_callback, &state);
+		MUTEX_ENTER();
+		GC->p.cx = mf_get_string_width(font, str, 0, 0);
+		GC->p.cy = font->height;
+		GC->t.font = font;
+		GC->t.clipx0 = GC->p.x = x;
+		GC->t.clipy0 = GC->p.y = y;
+		GC->t.clipx1 = GC->p.x+GC->p.cx;
+		GC->t.clipy1 = GC->p.y+GC->p.cy;
+		GC->t.color = color;
+		GC->t.bgcolor = GC->p.color = bgcolor;
+
+		TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) {
+			fillarea();
+			mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, 0);
+		}
+		MUTEX_EXIT();
 	}
 
 	void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		gdispDrawString_state_t state;
-		
-		state.font = font;
-		state.color = color;
-		state.x = x;
-		state.y = y;
-		state.cx = cx;
-		state.cy = cy;
-		
+		MUTEX_ENTER();
+		GC->t.font = font;
+		GC->t.clipx0 = x;
+		GC->t.clipy0 = y;
+		GC->t.clipx1 = x+cx;
+		GC->t.clipy1 = y+cy;
+		GC->t.color = color;
+
 		/* Select the anchor position */
 		switch(justify) {
 		case justifyCenter:
@@ -736,39 +1816,45 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 		}
 		y += (cy+1 - font->height)/2;
 
-		mf_render_aligned(font, x, y, justify, str, 0, gdispDrawString_callback, &state);
+		mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, 0);
+		MUTEX_EXIT();
 	}
 
 	void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) {
-		/* No mutex required as we only call high level functions which have their own mutex */
-		gdispFillString_state_t state;
+		MUTEX_ENTER();
+		GC->p.cx = cx;
+		GC->p.cy = cy;
+		GC->t.font = font;
+		GC->t.clipx0 = GC->p.x = x;
+		GC->t.clipy0 = GC->p.y = y;
+		GC->t.clipx1 = x+cx;
+		GC->t.clipy1 = y+cy;
+		GC->t.color = color;
+		GC->t.bgcolor = GC->p.color = bgcolor;
 
-		state.font = font;
-		state.color[0] = color;
-		state.color[1] = bgcolor;
-		state.x = x;
-		state.y = y;
-		state.cx = cx;
-		state.cy = cy;
+		TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) {
 
-		gdispFillArea(x, y, cx, cy, bgcolor);
-		
-		/* Select the anchor position */
-		switch(justify) {
-		case justifyCenter:
-			x += (cx + 1) / 2;
-			break;
-		case justifyRight:
-			x += cx;
-			break;
-		default:	// justifyLeft
-			x += font->baseline_x;
-			break;
+			// background fill
+			fillarea();
+
+			/* Select the anchor position */
+			switch(justify) {
+			case justifyCenter:
+				x += (cx + 1) / 2;
+				break;
+			case justifyRight:
+				x += cx;
+				break;
+			default:	// justifyLeft
+				x += font->baseline_x;
+				break;
+			}
+			y += (cy+1 - font->height)/2;
+
+			/* Render */
+			mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, 0);
 		}
-		y += (cy+1 - font->height)/2;
-		
-		/* Render */
-		mf_render_aligned(font, x, y, justify, str, 0, gdispFillString_callback, &state);
+		MUTEX_EXIT();
 	}
 
 	coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) {
@@ -831,5 +1917,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha)
 	}
 #endif
 
+
 #endif /* GFX_USE_GDISP */
 /** @} */