aboutsummaryrefslogtreecommitdiffstats
path: root/src/gdisp/gdisp_driver.h
blob: 09a12b06362bdc96925f67ce1c17eef6d2026127 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
/*
 * 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    src/gdisp/gdisp_driver.h
 * @brief   GDISP Graphic Driver subsystem low level driver header.
 *
 * @addtogroup GDISP
 * @{
 */

#ifndef _GDISP_LLD_H
#define _GDISP_LLD_H

#if GFX_USE_GDISP

// Include the GDRIVER infrastructure
#include "../gdriver/gdriver.h"

// Are we currently compiling the driver itself?
#if defined(GDISP_DRIVER_VMT)
	#define	IN_DRIVER			TRUE
#else
	#define	IN_DRIVER			FALSE
#endif

// Is this a multiple driver situation?
#if defined(GDISP_DRIVER_LIST)
	#define IS_MULTIPLE			TRUE
#else
	#define IS_MULTIPLE			FALSE
#endif

// Do we need to use VMT calling rather than direct calls to the driver?
#if IS_MULTIPLE || GDISP_NEED_PIXMAP
	#define USE_VMT				TRUE
#else
	#define USE_VMT				FALSE
#endif

// Are we in the pixmap virtual driver
#ifndef IN_PIXMAP_DRIVER
	#define IN_PIXMAP_DRIVER	FALSE
#endif

//------------------------------------------------------------------------------------------------------------

// Our special auto-detect hardware code which uses the VMT.
#define HARDWARE_AUTODETECT		2

#if USE_VMT && !IN_DRIVER
	// Multiple controllers the default is to hardware detect
	#define HARDWARE_DEFAULT		HARDWARE_AUTODETECT
#else
	// The default is not to include code functions that aren't needed
	#define HARDWARE_DEFAULT		FALSE
#endif

//------------------------------------------------------------------------------------------------------------

/**
 * @name    GDISP hardware accelerated support
 * @{
 */
	/**
	 * @brief   The display hardware can benefit from being de-initialized when usage is complete.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	This is most useful for displays such as remote network displays.
	 */
	#ifndef GDISP_HARDWARE_DEINIT
		#define GDISP_HARDWARE_DEINIT		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   The display hardware can benefit from being flushed.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	Some controllers ** require ** the application to flush
	 */
	#ifndef GDISP_HARDWARE_FLUSH
		#define GDISP_HARDWARE_FLUSH		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware streaming writing is supported.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by each driver
	 */
	#ifndef GDISP_HARDWARE_STREAM_WRITE
		#define GDISP_HARDWARE_STREAM_WRITE		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware streaming reading of the display surface is supported.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 *
	 */
	#ifndef GDISP_HARDWARE_STREAM_READ
		#define GDISP_HARDWARE_STREAM_READ		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware supports setting the cursor position within the stream window.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	This is used to optimise setting of individual pixels within a stream window.
	 * 			It should therefore not be implemented unless it is cheaper than just setting
	 * 			a new window.
	 */
	#ifndef GDISP_HARDWARE_STREAM_POS
		#define GDISP_HARDWARE_STREAM_POS		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware accelerated draw pixel.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver
	 */
	#ifndef GDISP_HARDWARE_DRAWPIXEL
		#define GDISP_HARDWARE_DRAWPIXEL		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware accelerated screen clears.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @note	This clears the entire display surface regardless of the clipping area currently set
	 */
	#ifndef GDISP_HARDWARE_CLEARS
		#define GDISP_HARDWARE_CLEARS			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware accelerated rectangular fills.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_FILLS
		#define GDISP_HARDWARE_FILLS			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware accelerated fills from an image.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_BITFILLS
		#define GDISP_HARDWARE_BITFILLS			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Hardware accelerated scrolling.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_SCROLL
		#define GDISP_HARDWARE_SCROLL			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   Reading back of pixel values.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_PIXELREAD
		#define GDISP_HARDWARE_PIXELREAD		HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   The driver supports one or more control commands.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_CONTROL
		#define GDISP_HARDWARE_CONTROL			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   The driver supports a non-standard query.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 */
	#ifndef GDISP_HARDWARE_QUERY
		#define GDISP_HARDWARE_QUERY			HARDWARE_DEFAULT
	#endif

	/**
	 * @brief   The driver supports a clipping in hardware.
	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
	 *
	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
	 * @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				HARDWARE_DEFAULT
	#endif
/** @} */

//------------------------------------------------------------------------------------------------------------

// For pixmaps certain routines MUST not be FALSE as they are needed for pixmap drawing
//	Similarly some routines MUST not be TRUE as pixmap's don't provide them.
#if GDISP_NEED_PIXMAP && !IN_DRIVER
	#if !GDISP_HARDWARE_DEINIT
		#undef GDISP_HARDWARE_DEINIT
		#define GDISP_HARDWARE_DEINIT		HARDWARE_AUTODETECT
	#endif
	#if !GDISP_HARDWARE_DRAWPIXEL
		#undef GDISP_HARDWARE_DRAWPIXEL
		#define GDISP_HARDWARE_DRAWPIXEL	HARDWARE_AUTODETECT
	#endif
	#if !GDISP_HARDWARE_PIXELREAD
		#undef GDISP_HARDWARE_PIXELREAD
		#define GDISP_HARDWARE_PIXELREAD	HARDWARE_AUTODETECT
	#endif
	#if !GDISP_HARDWARE_CONTROL
		#undef GDISP_HARDWARE_CONTROL
		#define GDISP_HARDWARE_CONTROL		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_FLUSH == TRUE
		#undef GDISP_HARDWARE_FLUSH
		#define GDISP_HARDWARE_FLUSH		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_STREAM_WRITE == TRUE
		#undef GDISP_HARDWARE_STREAM_WRITE
		#define GDISP_HARDWARE_STREAM_WRITE	HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_STREAM_READ == TRUE
		#undef GDISP_HARDWARE_STREAM_READ
		#define GDISP_HARDWARE_STREAM_READ	HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_CLEARS == TRUE
		#undef GDISP_HARDWARE_CLEARS
		#define GDISP_HARDWARE_CLEARS		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_FILLS == TRUE
		#undef GDISP_HARDWARE_FILLS
		#define GDISP_HARDWARE_FILLS		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_BITFILLS == TRUE
		#undef GDISP_HARDWARE_BITFILLS
		#define GDISP_HARDWARE_BITFILLS		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_SCROLL == TRUE
		#undef GDISP_HARDWARE_SCROLL
		#define GDISP_HARDWARE_SCROLL		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_QUERY == TRUE
		#undef GDISP_HARDWARE_QUERY
		#define GDISP_HARDWARE_QUERY		HARDWARE_AUTODETECT
	#endif
	#if GDISP_HARDWARE_CLIP == TRUE
		#undef GDISP_HARDWARE_CLIP
		#define GDISP_HARDWARE_CLIP			HARDWARE_AUTODETECT
	#endif
#endif

//------------------------------------------------------------------------------------------------------------

/* Verify information for packed pixels and define a non-packed pixel macro */
#if !GDISP_PACKED_PIXELS
	#define gdispPackPixels(buf,cx,x,y,c)	{ ((color_t *)(buf))[(y)*(cx)+(x)] = (c); }
#elif !GDISP_HARDWARE_BITFILLS
	#error "GDISP: packed pixel formats are only supported for hardware accelerated drivers."
#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \
		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \
		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \
		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM
	#error "GDISP: A packed pixel format has been specified for an unsupported pixel format."
#endif

/* Support routine for packed pixel formats */
#if !defined(gdispPackPixels) || defined(__DOXYGEN__)
	/**
	 * @brief   Pack a pixel into a pixel buffer.
	 * @note    This function performs no buffer boundary checking
	 *			regardless of whether GDISP_NEED_CLIP has been specified.
	 *
	 * @param[in] buf		The buffer to put the pixel in
	 * @param[in] cx		The width of a pixel line
	 * @param[in] x, y		The location of the pixel to place
	 * @param[in] color		The color to put into the buffer
	 *
	 * @api
	 */
	void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color);
#endif

//------------------------------------------------------------------------------------------------------------

struct GDisplay {
	struct GDriver				d;					// This must be the first element
		#define gvmt(g)		((const GDISPVMT const *)((g)->d.vmt))	// For ease of access to the vmt member

	struct GDISPControl {
		coord_t					Width;
		coord_t					Height;
		orientation_t			Orientation;
		powermode_t				Powermode;
		uint8_t					Backlight;
		uint8_t					Contrast;
	} g;

	void *						priv;				// A private area just for the drivers use.
	void *						board;				// A private area just for the board interfaces use.

	uint8_t						systemdisplay;
	uint8_t						controllerdisplay;
	uint16_t					flags;
		#define GDISP_FLG_INSTREAM		0x0001		// We are in a user based stream operation
		#define GDISP_FLG_SCRSTREAM		0x0002		// The stream area currently covers the whole screen
		#define GDISP_FLG_DRIVER		0x0004		// This flags and above are for use by the driver

	// Multithread Mutex
	#if GDISP_NEED_MULTITHREAD
		gfxMutex				mutex;
	#endif

	// Software clipping
	#if GDISP_HARDWARE_CLIP != TRUE && (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;

	// In call working buffers

	#if GDISP_NEED_TEXT
		// Text rendering parameters
		struct {
			font_t		font;
			color_t		color;
			color_t		bgcolor;
			coord_t		clipx0, clipy0;
			coord_t		clipx1, clipy1;
			#if GDISP_NEED_TEXT_WORDWRAP
				coord_t		wrapx, wrapy;
				justify_t	lrj;
			#endif
		} t;
	#endif
	#if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM_WRITE && GDISP_HARDWARE_BITFILLS))
		// A pixel line buffer
		color_t		linebuf[GDISP_LINEBUF_SIZE];
	#endif
};

typedef struct GDISPVMT {
	GDriverVMT	d;
		#define GDISP_VFLG_DYNAMICONLY		0x0001		// This display should never be statically initialised
		#define GDISP_VFLG_PIXMAP			0x0002		// This is a pixmap display
	bool_t (*init)(GDisplay *g);
	void (*deinit)(GDisplay *g);
	void (*writestart)(GDisplay *g);				// Uses p.x,p.y  p.cx,p.cy
	void (*writepos)(GDisplay *g);					// Uses p.x,p.y
	void (*writecolor)(GDisplay *g);				// Uses p.color
	void (*writestop)(GDisplay *g);					// Uses no parameters
	void (*readstart)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
	color_t (*readcolor)(GDisplay *g);				// Uses no parameters
	void (*readstop)(GDisplay *g);					// Uses no parameters
	void (*pixel)(GDisplay *g);						// Uses p.x,p.y  p.color
	void (*clear)(GDisplay *g);						// Uses p.color
	void (*fill)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.color
	void (*blit)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.x1,p.y1 (=srcx,srcy)  p.x2 (=srccx), p.ptr (=buffer)
	color_t (*get)(GDisplay *g);					// Uses p.x,p.y
	void (*vscroll)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy, p.y1 (=lines) p.color
	void (*control)(GDisplay *g);					// Uses p.x (=what)  p.ptr (=value)
	void *(*query)(GDisplay *g);					// Uses p.x (=what);
	void (*setclip)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
	void (*flush)(GDisplay *g);						// Uses no parameters
} GDISPVMT;

//------------------------------------------------------------------------------------------------------------

// Do we need function definitions or macro's (via the VMT)
#if IN_DRIVER || !USE_VMT || defined(__DOXYGEN__)
	#ifdef __cplusplus
	extern "C" {
	#endif

	// Should the driver routines be static or not
	#if USE_VMT
		#define LLDSPEC         static
	#else
		#define LLDSPEC
	#endif

	/**
	 * @brief   Initialize the driver.
	 * @return	TRUE if successful.
	 * @param[in]	g					The driver structure
	 * @param[out]	g->g				The driver must fill in the GDISPControl structure
	 */
	LLDSPEC	bool_t gdisp_lld_init(GDisplay *g);

	#if GDISP_HARDWARE_DEINIT || defined(__DOXYGEN__)
		/**
		 * @brief   The driver is being de-initialized
		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 */
		LLDSPEC	void gdisp_lld_deinit(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_FLUSH || defined(__DOXYGEN__)
		/**
		 * @brief   Flush the current drawing operations to the display
		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_flush(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__)
		/**
		 * @brief   Start a streamed write operation
		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		g->p.x,g->p.y	The window position
		 * @note		g->p.cx,g->p.cy	The window size
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 * @note		Streaming operations that wrap the defined window have
		 * 				undefined results.
		 * @note		This must be followed by a call to @p gdisp_lld_write_pos() if GDISP_HARDWARE_STREAM_POS is TRUE.
		 */
		LLDSPEC	void gdisp_lld_write_start(GDisplay *g);

		/**
		 * @brief   Send a pixel to the current streaming position and then increment that position
		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		g->p.color		The color to display at the curent position
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_write_color(GDisplay *g);

		/**
		 * @brief   End the current streaming write operation
		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_write_stop(GDisplay *g);

		#if GDISP_HARDWARE_STREAM_POS || defined(__DOXYGEN__)
			/**
			 * @brief   Change the current position within the current streaming window
			 * @pre		GDISP_HARDWARE_STREAM_POS is TRUE and GDISP_HARDWARE_STREAM_WRITE is TRUE
			 *
			 * @param[in]	g				The driver structure
			 * @param[in]	g->p.x,g->p.y	The new position (which will always be within the existing stream window)
			 *
			 * @note		The parameter variables must not be altered by the driver.
			 */
			LLDSPEC	void gdisp_lld_write_pos(GDisplay *g);
		#endif
	#endif

	#if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__)
		/**
		 * @brief   Start a streamed read operation
		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The window position
		 * @param[in]	g->p.cx,g->p.cy	The window size
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 * @note		Streaming operations that wrap the defined window have
		 * 				undefined results.
		 */
		LLDSPEC	void gdisp_lld_read_start(GDisplay *g);

		/**
		 * @brief   Read a pixel from the current streaming position and then increment that position
		 * @return	The color at the current position
		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	color_t gdisp_lld_read_color(GDisplay *g);

		/**
		 * @brief   End the current streaming operation
		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
		 *
		 * @param[in]	g				The driver structure
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_read_stop(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__)
		/**
		 * @brief   Draw a pixel
		 * @pre		GDISP_HARDWARE_DRAWPIXEL is TRUE
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The pixel position
		 * @param[in]	g->p.color		The color to set
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_draw_pixel(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__)
		/**
		 * @brief   Clear the screen using the defined color
		 * @pre		GDISP_HARDWARE_CLEARS is TRUE
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.color		The color to set
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_clear(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
		/**
		 * @brief   Fill an area with a single color
		 * @pre		GDISP_HARDWARE_FILLS is TRUE
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The area position
		 * @param[in]	g->p.cx,g->p.cy	The area size
		 * @param[in]	g->p.color		The color to set
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_fill_area(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
		/**
		 * @brief   Fill an area using a bitmap
		 * @pre		GDISP_HARDWARE_BITFILLS is TRUE
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The area position
		 * @param[in]	g->p.cx,g->p.cy	The area size
		 * @param[in]	g->p.x1,g->p.y1	The starting position in the bitmap
		 * @param[in]	g->p.x2			The width of a bitmap line
		 * @param[in]	g->p.ptr		The pointer to the bitmap
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_blit_area(GDisplay *g);
	#endif

	#if GDISP_HARDWARE_PIXELREAD || defined(__DOXYGEN__)
		/**
		 * @brief   Read a pixel from the display
		 * @return	The color at the defined position
		 * @pre		GDISP_HARDWARE_PIXELREAD is TRUE (and the application needs it)
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The pixel position
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	color_t gdisp_lld_get_pixel_color(GDisplay *g);
	#endif

	#if (GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL) || defined(__DOXYGEN__)
		/**
		 * @brief   Scroll an area of the screen
		 * @pre		GDISP_HARDWARE_SCROLL is TRUE (and the application needs it)
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The area position
		 * @param[in]	g->p.cx,g->p.cy	The area size
		 * @param[in]	g->p.y1			The number of lines to scroll (positive or negative)
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 * @note		This can be easily implemented if the hardware supports
		 * 				display area to display area copying.
		 * @note		Clearing the exposed area on the scroll operation is not
		 * 				needed as the high level code handles this.
		 */
		LLDSPEC	void gdisp_lld_vertical_scroll(GDisplay *g);
	#endif

	#if (GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL) || defined(__DOXYGEN__)
		/**
		 * @brief   Control some feature of the hardware
		 * @pre		GDISP_HARDWARE_CONTROL is TRUE (and the application needs it)
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x			The operation to perform
		 * @param[in]	g->p.ptr		The operation parameter
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_control(GDisplay *g);
	#endif

	#if (GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY) || defined(__DOXYGEN__)
		/**
		 * @brief   Query some feature of the hardware
		 * @return	The information requested (typecast as void *)
		 * @pre		GDISP_HARDWARE_QUERY is TRUE (and the application needs it)
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x			What to query
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void *gdisp_lld_query(GDisplay *g);				// Uses p.x (=what);
	#endif

	#if (GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)) || defined(__DOXYGEN__)
		/**
		 * @brief   Set the hardware clipping area
		 * @pre		GDISP_HARDWARE_CLIP is TRUE (and the application needs it)
		 *
		 * @param[in]	g				The driver structure
		 * @param[in]	g->p.x,g->p.y	The area position
		 * @param[in]	g->p.cx,g->p.cy	The area size
		 *
		 * @note		The parameter variables must not be altered by the driver.
		 */
		LLDSPEC	void gdisp_lld_set_clip(GDisplay *g);
	#endif

	#ifdef __cplusplus
	}
	#endif

#else
	#define gdisp_lld_init(g)				gvmt(g)->init(g)
	#define gdisp_lld_deinit(g)				gvmt(g)->deinit(g)
	#define gdisp_lld_flush(g)				gvmt(g)->flush(g)
	#define gdisp_lld_write_start(g)		gvmt(g)->writestart(g)
	#define gdisp_lld_write_pos(g)			gvmt(g)->writepos(g)
	#define gdisp_lld_write_color(g)		gvmt(g)->writecolor(g)
	#define gdisp_lld_write_stop(g)			gvmt(g)->writestop(g)
	#define gdisp_lld_read_start(g)			gvmt(g)->readstart(g)
	#define gdisp_lld_read_color(g)			gvmt(g)->readcolor(g)
	#define gdisp_lld_read_stop(g)			gvmt(g)->readstop(g)
	#define gdisp_lld_draw_pixel(g)			gvmt(g)->pixel(g)
	#define gdisp_lld_clear(g)				gvmt(g)->clear(g)
	#define gdisp_lld_fill_area(g)			gvmt(g)->fill(g)
	#define gdisp_lld_blit_area(g)			gvmt(g)->blit(g)
	#define gdisp_lld_get_pixel_color(g)	gvmt(g)->get(g)
	#define gdisp_lld_vertical_scroll(g)	gvmt(g)->vscroll(g)
	#define gdisp_lld_control(g)			gvmt(g)->control(g)
	#define gdisp_lld_query(g)				gvmt(g)->query(g)
	#define gdisp_lld_set_clip(g)			gvmt(g)->setclip(g)
#endif

//------------------------------------------------------------------------------------------------------------

// If compiling the driver then build the VMT and set the low level driver color macros.
#if IN_DRIVER

	// Make sure the driver has a valid model
	#if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL
		#error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be TRUE"
	#endif

	// If we are not using multiple displays then hard-code the VMT name (except for the pixmap driver)
	#if !IS_MULTIPLE && !IN_PIXMAP_DRIVER
		#undef GDISP_DRIVER_VMT
		#define GDISP_DRIVER_VMT		GDISPVMT_OnlyOne
	#endif

	// Default the flags if the driver doesn't specify any
	#ifndef GDISP_DRIVER_VMT_FLAGS
		#define GDISP_DRIVER_VMT_FLAGS		0
	#endif

	// Routines needed by the general driver VMT
	#ifdef __cplusplus
	extern "C" {
	#endif
		bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
		void _gdispPostInitDriver(GDriver *g);
		void _gdispDeInitDriver(GDriver *g);
	#ifdef __cplusplus
	}
	#endif

	// Build the VMT
	const GDISPVMT const GDISP_DRIVER_VMT[1] = {{
		{ GDRIVER_TYPE_DISPLAY, 0, sizeof(GDisplay), _gdispInitDriver, _gdispPostInitDriver, _gdispDeInitDriver },
		gdisp_lld_init,
		#if GDISP_HARDWARE_DEINIT
			gdisp_lld_deinit,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_STREAM_WRITE
			gdisp_lld_write_start,
			#if GDISP_HARDWARE_STREAM_POS
				gdisp_lld_write_pos,
			#else
				0,
			#endif
			gdisp_lld_write_color,
			gdisp_lld_write_stop,
		#else
			0, 0, 0, 0,
		#endif
		#if GDISP_HARDWARE_STREAM_READ
			gdisp_lld_read_start,
			gdisp_lld_read_color,
			gdisp_lld_read_stop,
		#else
			0, 0, 0,
		#endif
		#if GDISP_HARDWARE_DRAWPIXEL
			gdisp_lld_draw_pixel,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_CLEARS
			gdisp_lld_clear,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_FILLS
			gdisp_lld_fill_area,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_BITFILLS
			gdisp_lld_blit_area,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_PIXELREAD
			gdisp_lld_get_pixel_color,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL
			gdisp_lld_vertical_scroll,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL
			gdisp_lld_control,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY
			gdisp_lld_query,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
			gdisp_lld_set_clip,
		#else
			0,
		#endif
		#if GDISP_HARDWARE_FLUSH
			gdisp_lld_flush,
		#else
			0,
		#endif
	}};

	//--------------------------------------------------------------------------------------------------------

	/* Low level driver pixel format information */
	//-------------------------
	//	True-Color color system
	//-------------------------
	#if GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_TRUECOLOR
		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_TRUECOLOR

		// Calculate the number of bits
		#define LLDCOLOR_BITS_R			((GDISP_LLD_PIXELFORMAT>>8) & 0x0F)
		#define LLDCOLOR_BITS_G			((GDISP_LLD_PIXELFORMAT>>4) & 0x0F)
		#define LLDCOLOR_BITS_B			((GDISP_LLD_PIXELFORMAT>>0) & 0x0F)
		#define LLDCOLOR_BITS			(LLDCOLOR_BITS_R + LLDCOLOR_BITS_G + LLDCOLOR_BITS_B)

		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
		#if LLDCOLOR_BITS <= 8
			#define LLDCOLOR_TYPE			uint8_t
			#define LLDCOLOR_TYPE_BITS		8
		#elif LLDCOLOR_BITS <= 16
			#define LLDCOLOR_TYPE			uint16_t
			#define LLDCOLOR_TYPE_BITS		16
		#elif LLDCOLOR_BITS <= 32
			#define LLDCOLOR_TYPE			uint32_t
			#define LLDCOLOR_TYPE_BITS		32
		#else
			#error "GDISP: Cannot define low level driver color types with more than 32 bits"
		#endif
		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
			#define LLDCOLOR_NEEDS_MASK	FALSE
		#else
			#define LLDCOLOR_NEEDS_MASK	TRUE
		#endif
		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)

		// Calculate the component bit shifts
		#if (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_RGB
			#define LLDCOLOR_SHIFT_R		(LLDCOLOR_BITS_B+LLDCOLOR_BITS_G)
			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_B
			#define LLDCOLOR_SHIFT_B		0
		#else
			#define LLDCOLOR_SHIFT_B		(LLDCOLOR_BITS_R+LLDCOLOR_BITS_G)
			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_R
			#define LLDCOLOR_SHIFT_R		0
		#endif

		// Calculate LLDRED_OF, LLDGREEN_OF, LLDBLUE_OF and LLDRGB2COLOR
		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 8
			#define LLDRED_OF(c)			((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R))
			#define LLDRGB2COLOR_R(r)		((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))))
		#elif LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R > 8
			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) >> (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
		#else // LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R < 8
			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) << (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) >> (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
		#endif
		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 8
			#define LLDGREEN_OF(c)			((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G))
			#define LLDRGB2COLOR_G(g)		((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))))
		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 8
			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) >> (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 8
			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) << (8-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) >> (8-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
		#endif
		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
			#define LLDBLUE_OF(c)			((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B))
			#define LLDRGB2COLOR_B(b)		((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))))
		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) >> (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
			#define LLDRGB2COLOR_B(b)		(((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) << (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
			#define LLDRGB2COLOR_B(b)		(((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
		#endif
		#define LLDLUMA_OF(c)				((LLDRED_OF(c)+((uint16_t)LLDGREEN_OF(c)<<1)+LLDBLUE_OF(c))>>2)
		#define LLDEXACT_RED_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_R)&((1<<LLDCOLOR_BITS_R)-1))*255)/((1<<LLDCOLOR_BITS_R)-1))
		#define LLDEXACT_GREEN_OF(c)		(((uint16_t)(((c)>>LLDCOLOR_SHIFT_G)&((1<<LLDCOLOR_BITS_G)-1))*255)/((1<<LLDCOLOR_BITS_G)-1))
		#define LLDEXACT_BLUE_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_B)&((1<<LLDCOLOR_BITS_B)-1))*255)/((1<<LLDCOLOR_BITS_B)-1))
		#define LLDEXACT_LUMA_OF(c)			((LLDEXACT_RED_OF(c)+((uint16_t)LLDEXACT_GREEN_OF(c)<<1)+LLDEXACT_BLUE_OF(c))>>2)
		#define LLDLUMA2COLOR(l)			(LLDRGB2COLOR_R(l) | LLDRGB2COLOR_G(l) | LLDRGB2COLOR_B(l))
		#define LLDRGB2COLOR(r,g,b)			(LLDRGB2COLOR_R(r) | LLDRGB2COLOR_G(g) | LLDRGB2COLOR_B(b))

		// Calculate LLDHTML2COLOR
		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 24
			#define LLDHTML2COLOR_R(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16))
		#elif COLOR_BITS_R + COLOR_SHIFT_R > 24
			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-24))
		#else // COLOR_BITS_R + COLOR_SHIFT_R < 24
			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) >> (24-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
		#endif
		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 16
			#define LLDHTML2COLOR_G(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8))
		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 16
			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-16))
		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 16
			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) >> (16-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
		#endif
		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
			#define LLDHTML2COLOR_B(h)		((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))
		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
		#endif
		#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(LLDHTML2COLOR_R(h) | LLDHTML2COLOR_G(h) | LLDHTML2COLOR_B(h)))

	//-------------------------
	//	Gray-scale color system
	//-------------------------
	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_GRAYSCALE
		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_GRAYSCALE

		// Calculate the number of bits and shifts
		#define LLDCOLOR_BITS			(GDISP_LLD_PIXELFORMAT & 0xFF)
		#define LLDCOLOR_BITS_R			LLDCOLOR_BITS
		#define LLDCOLOR_BITS_G			LLDCOLOR_BITS
		#define LLDCOLOR_BITS_B			LLDCOLOR_BITS
		#define LLDCOLOR_SHIFT_R		0
		#define LLDCOLOR_SHIFT_G		0
		#define LLDCOLOR_SHIFT_B		0

		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
		#if LLDCOLOR_BITS <= 8
			#define LLDCOLOR_TYPE		uint8_t
			#define LLDCOLOR_TYPE_BITS	8
		#else
			#error "GDISP: Cannot define gray-scale low level driver color types with more than 8 bits"
		#endif
		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
			#define LLDCOLOR_NEEDS_MASK	FALSE
		#else
			#define LLDCOLOR_NEEDS_MASK	TRUE
		#endif
		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)

		#if COLOR_BITS == 1
			#define LLDRGB2COLOR(r,g,b)		(((r)|(g)|(b)) ? 1 : 0)
			#define LLDLUMA2COLOR(l)		((l) ? 1 : 0)
			#define LLDHTML2COLOR(h)		((h) ? 1 : 0)
			#define LLDLUMA_OF(c)			((c) ? 255 : 0)
			#define LLDEXACT_LUMA_OF(c)		LLDLUMA_OF(c)
		#else
			// They eye is more sensitive to green
			#define LLDRGB2COLOR(r,g,b)		((LLDCOLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-LLDCOLOR_BITS)))
			#define LLDLUMA2COLOR(l)		((LLDCOLOR_TYPE)((l)>>(8-LLDCOLOR_BITS)))
			#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-LLDCOLOR_BITS)))
			#define LLDLUMA_OF(c)			(((c) & ((1<<LLDCOLOR_BITS)-1)) << (8-LLDCOLOR_BITS))
			#define LLDEXACT_LUMA_OF(c)		((((uint16_t)(c) & ((1<<LLDCOLOR_BITS)-1))*255)/((1<<LLDCOLOR_BITS)-1))
		#endif

		#define LLDRED_OF(c)			LLDLUMA_OF(c)
		#define LLDGREEN_OF(c)			LLDLUMA_OF(c)
		#define LLDBLUE_OF(c)			LLDLUMA_OF(c)
		#define LLDEXACT_RED_OF(c)		LLDEXACT_LUMA_OF(c)
		#define LLDEXACT_GREEN_OF(c)	LLDEXACT_LUMA_OF(c)
		#define LLDEXACT_BLUE_OF(c)		LLDEXACT_LUMA_OF(c)

	//-------------------------
	//	Palette color system
	//-------------------------
	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_PALETTE
		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_PALETTE

		#error "GDISP: A palette color system for low level drivers is not currently supported"

	//-------------------------
	//	Some other color system
	//-------------------------
	#else
		#error "GDISP: Unsupported color system for low level drivers"
	#endif

	/* Which is the larger color type */
	#if COLOR_BITS > LLDCOLOR_BITS
		#define LARGER_COLOR_BITS	COLOR_BITS
		#define LARGER_COLOR_TYPE	COLOR_TYPE
	#else
		#define LARGER_COLOR_BITS	LLDCOLOR_BITS
		#define LARGER_COLOR_TYPE	LLDCOLOR_TYPE
	#endif

	/**
	 * @brief	Controls color conversion accuracy for a low level driver
	 * @details	Should higher precision be used when converting colors.
	 * @note	Color conversion is only necessary if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT
	 * @note	It only makes sense to turn this on if you have a high bit depth display but
	 * 			are running the application in low bit depths.
	 * @note	To achieve higher color accuracy bit shifting is replaced with multiplies and divides.
	 */
	#ifndef GDISP_HARDWARE_USE_EXACT_COLOR
		#if LLDCOLOR_BITS_R - COLOR_BITS_R >= LLDCOLOR_BITS_R/2 || LLDCOLOR_BITS_G - COLOR_BITS_G >= LLDCOLOR_BITS_G/2 || LLDCOLOR_BITS_B - COLOR_BITS_B >= LLDCOLOR_BITS_B/2
			#define GDISP_HARDWARE_USE_EXACT_COLOR	TRUE
		#else
			#define GDISP_HARDWARE_USE_EXACT_COLOR	FALSE
		#endif
	#endif

	/* Low level driver pixel format conversion functions */
	#if GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT || defined(__DOXYGEN__)
		/**
		 * @brief	Convert from a standard color format to the low level driver pixel format
		 * @note	For use only by low level drivers
		 */
		#define gdispColor2Native(c)	(c)
		/**
		 * @brief	Convert from a low level driver pixel format to the standard color format
		 * @note	For use only by low level drivers
		 */
		#define gdispNative2Color(c)	(c)
	#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE
		#if GDISP_HARDWARE_USE_EXACT_COLOR
			#define gdispColor2Native(c)	LLDLUMA2COLOR(EXACT_LUMA_OF(c))
			#define gdispNative2Color(c)	LUMA2COLOR(LLDEXACT_LUMA_OF(c))
		#else
			#define gdispColor2Native(c)	LLDLUMA2COLOR(LUMA_OF(c))
			#define gdispNative2Color(c)	LUMA2COLOR(LLDLUMA_OF(c))
		#endif
	#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR
		#if GDISP_HARDWARE_USE_EXACT_COLOR
			#define gdispColor2Native(c)	LLDRGB2COLOR(EXACT_RED_OF(c), EXACT_GREEN_OF(c), EXACT_BLUE_OF(c))
			#define gdispNative2Color(c)	RGB2COLOR(LLDEXACT_RED_OF(c), LLDEXACT_GREEN_OF(c), LLDEXACT_BLUE_OF(c))
		#else
			#define gdispColor2Native(c)	LLDRGB2COLOR(RED_OF(c), GREEN_OF(c), BLUE_OF(c))
			#define gdispNative2Color(c)	RGB2COLOR(LLDRED_OF(c), LLDGREEN_OF(c), LLDBLUE_OF(c))
		#endif
	#else
		#error "GDISP: This pixel format conversion is not supported yet"
	#endif

#endif

//------------------------------------------------------------------------------------------------------------

#undef IN_PIXMAP_DRIVER
#undef IS_MULTIPLE
#undef IN_DRIVER
#undef USE_VMT
#endif	/* GFX_USE_GDISP */

#endif	/* _GDISP_LLD_H */
/** @} */