sync with latest
[sdk/emulator/qemu.git] / pflib.c
1 /*
2  * PixelFormat conversion library.
3  *
4  * Author: Gerd Hoffmann <kraxel@redhat.com>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2.  See
7  * the COPYING file in the top-level directory.
8  *
9  * Contributions after 2012-01-13 are licensed under the terms of the
10  * GNU GPL, version 2 or (at your option) any later version.
11  */
12 #include "qemu-common.h"
13 #include "console.h"
14 #include "pflib.h"
15
16 typedef struct QemuPixel QemuPixel;
17
18 typedef void (*pf_convert)(QemuPfConv *conv,
19                            void *dst, void *src, uint32_t cnt);
20 typedef void (*pf_convert_from)(PixelFormat *pf,
21                                 QemuPixel *dst, void *src, uint32_t cnt);
22 typedef void (*pf_convert_to)(PixelFormat *pf,
23                               void *dst, QemuPixel *src, uint32_t cnt);
24
25 struct QemuPfConv {
26     pf_convert        convert;
27     PixelFormat       src;
28     PixelFormat       dst;
29
30     /* for copy_generic() */
31     pf_convert_from   conv_from;
32     pf_convert_to     conv_to;
33     QemuPixel         *conv_buf;
34     uint32_t          conv_cnt;
35 };
36
37 struct QemuPixel {
38     uint8_t red;
39     uint8_t green;
40     uint8_t blue;
41     uint8_t alpha;
42 };
43
44 /* ----------------------------------------------------------------------- */
45 /* PixelFormat -> QemuPixel conversions                                    */
46
47 static void conv_16_to_pixel(PixelFormat *pf,
48                              QemuPixel *dst, void *src, uint32_t cnt)
49 {
50     uint16_t *src16 = src;
51
52     while (cnt > 0) {
53         dst->red   = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
54         dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
55         dst->blue  = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
56         dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
57         dst++, src16++, cnt--;
58     }
59 }
60
61 /* assumes pf->{r,g,b,a}bits == 8 */
62 static void conv_32_to_pixel_fast(PixelFormat *pf,
63                                   QemuPixel *dst, void *src, uint32_t cnt)
64 {
65     uint32_t *src32 = src;
66
67     while (cnt > 0) {
68         dst->red   = (*src32 & pf->rmask) >> pf->rshift;
69         dst->green = (*src32 & pf->gmask) >> pf->gshift;
70         dst->blue  = (*src32 & pf->bmask) >> pf->bshift;
71         dst->alpha = (*src32 & pf->amask) >> pf->ashift;
72         dst++, src32++, cnt--;
73     }
74 }
75
76 static void conv_32_to_pixel_generic(PixelFormat *pf,
77                                      QemuPixel *dst, void *src, uint32_t cnt)
78 {
79     uint32_t *src32 = src;
80
81     while (cnt > 0) {
82         if (pf->rbits < 8) {
83             dst->red   = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
84         } else {
85             dst->red   = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
86         }
87         if (pf->gbits < 8) {
88             dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
89         } else {
90             dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
91         }
92         if (pf->bbits < 8) {
93             dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
94         } else {
95             dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
96         }
97         if (pf->abits < 8) {
98             dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
99         } else {
100             dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
101         }
102         dst++, src32++, cnt--;
103     }
104 }
105
106 /* ----------------------------------------------------------------------- */
107 /* QemuPixel -> PixelFormat conversions                                    */
108
109 static void conv_pixel_to_16(PixelFormat *pf,
110                              void *dst, QemuPixel *src, uint32_t cnt)
111 {
112     uint16_t *dst16 = dst;
113
114     while (cnt > 0) {
115         *dst16  = ((uint16_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
116         *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
117         *dst16 |= ((uint16_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
118         *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
119         dst16++, src++, cnt--;
120     }
121 }
122
123 static void conv_pixel_to_32(PixelFormat *pf,
124                              void *dst, QemuPixel *src, uint32_t cnt)
125 {
126     uint32_t *dst32 = dst;
127
128     while (cnt > 0) {
129         *dst32  = ((uint32_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
130         *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
131         *dst32 |= ((uint32_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
132         *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
133         dst32++, src++, cnt--;
134     }
135 }
136
137 /* ----------------------------------------------------------------------- */
138 /* PixelFormat -> PixelFormat conversions                                  */
139
140 static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
141 {
142     uint32_t bytes = cnt * conv->src.bytes_per_pixel;
143     memcpy(dst, src, bytes);
144 }
145
146 static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
147 {
148     if (conv->conv_cnt < cnt) {
149         conv->conv_cnt = cnt;
150         conv->conv_buf = g_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
151     }
152     conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
153     conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
154 }
155
156 /* ----------------------------------------------------------------------- */
157 /* public interface                                                        */
158
159 QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
160 {
161     QemuPfConv *conv = g_malloc0(sizeof(QemuPfConv));
162
163     conv->src = *src;
164     conv->dst = *dst;
165
166     if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
167         /* formats identical, can simply copy */
168         conv->convert = convert_copy;
169     } else {
170         /* generic two-step conversion: src -> QemuPixel -> dst  */
171         switch (conv->src.bytes_per_pixel) {
172         case 2:
173             conv->conv_from = conv_16_to_pixel;
174             break;
175         case 4:
176             if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
177                 conv->conv_from = conv_32_to_pixel_fast;
178             } else {
179                 conv->conv_from = conv_32_to_pixel_generic;
180             }
181             break;
182         default:
183             goto err;
184         }
185         switch (conv->dst.bytes_per_pixel) {
186         case 2:
187             conv->conv_to = conv_pixel_to_16;
188             break;
189         case 4:
190             conv->conv_to = conv_pixel_to_32;
191             break;
192         default:
193             goto err;
194         }
195         conv->convert = convert_generic;
196     }
197     return conv;
198
199 err:
200     g_free(conv);
201     return NULL;
202 }
203
204 void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
205 {
206     conv->convert(conv, dst, src, cnt);
207 }
208
209 void qemu_pf_conv_put(QemuPfConv *conv)
210 {
211     if (conv) {
212         g_free(conv->conv_buf);
213         g_free(conv);
214     }
215 }