1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2020 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QPIXELLAYOUT_P_H |
41 | #define QPIXELLAYOUT_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists purely as an |
48 | // implementation detail. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <QtCore/qlist.h> |
55 | #include <QtGui/qimage.h> |
56 | #include <QtGui/qrgba64.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | enum QtPixelOrder { |
61 | PixelOrderRGB, |
62 | PixelOrderBGR |
63 | }; |
64 | |
65 | template<enum QtPixelOrder> inline uint qConvertArgb32ToA2rgb30(QRgb); |
66 | |
67 | template<enum QtPixelOrder> inline uint qConvertRgb32ToRgb30(QRgb); |
68 | |
69 | template<enum QtPixelOrder> inline QRgb qConvertA2rgb30ToArgb32(uint c); |
70 | |
71 | // A combined unpremultiply and premultiply with new simplified alpha. |
72 | // Needed when alpha loses precision relative to other colors during conversion (ARGB32 -> A2RGB30). |
73 | template<unsigned int Shift> |
74 | inline QRgb qRepremultiply(QRgb p) |
75 | { |
76 | const uint alpha = qAlpha(p); |
77 | if (alpha == 255 || alpha == 0) |
78 | return p; |
79 | p = qUnpremultiply(p); |
80 | constexpr uint mult = 255 / (255 >> Shift); |
81 | const uint newAlpha = mult * (alpha >> Shift); |
82 | p = (p & ~0xff000000) | (newAlpha<<24); |
83 | return qPremultiply(p); |
84 | } |
85 | |
86 | template<unsigned int Shift> |
87 | inline QRgba64 qRepremultiply(QRgba64 p) |
88 | { |
89 | const uint alpha = p.alpha(); |
90 | if (alpha == 65535 || alpha == 0) |
91 | return p; |
92 | p = p.unpremultiplied(); |
93 | constexpr uint mult = 65535 / (65535 >> Shift); |
94 | p.setAlpha(mult * (alpha >> Shift)); |
95 | return p.premultiplied(); |
96 | } |
97 | |
98 | template<> |
99 | inline uint qConvertArgb32ToA2rgb30<PixelOrderBGR>(QRgb c) |
100 | { |
101 | c = qRepremultiply<6>(c); |
102 | return (c & 0xc0000000) |
103 | | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) |
104 | | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) |
105 | | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); |
106 | } |
107 | |
108 | template<> |
109 | inline uint qConvertArgb32ToA2rgb30<PixelOrderRGB>(QRgb c) |
110 | { |
111 | c = qRepremultiply<6>(c); |
112 | return (c & 0xc0000000) |
113 | | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) |
114 | | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) |
115 | | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); |
116 | } |
117 | |
118 | template<> |
119 | inline uint qConvertRgb32ToRgb30<PixelOrderBGR>(QRgb c) |
120 | { |
121 | return 0xc0000000 |
122 | | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000)) |
123 | | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) |
124 | | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003)); |
125 | } |
126 | |
127 | template<> |
128 | inline uint qConvertRgb32ToRgb30<PixelOrderRGB>(QRgb c) |
129 | { |
130 | return 0xc0000000 |
131 | | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000)) |
132 | | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00)) |
133 | | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003)); |
134 | } |
135 | |
136 | template<> |
137 | inline QRgb qConvertA2rgb30ToArgb32<PixelOrderBGR>(uint c) |
138 | { |
139 | uint a = c >> 30; |
140 | a |= a << 2; |
141 | a |= a << 4; |
142 | return (a << 24) |
143 | | ((c << 14) & 0x00ff0000) |
144 | | ((c >> 4) & 0x0000ff00) |
145 | | ((c >> 22) & 0x000000ff); |
146 | } |
147 | |
148 | template<> |
149 | inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c) |
150 | { |
151 | uint a = c >> 30; |
152 | a |= a << 2; |
153 | a |= a << 4; |
154 | return (a << 24) |
155 | | ((c >> 6) & 0x00ff0000) |
156 | | ((c >> 4) & 0x0000ff00) |
157 | | ((c >> 2) & 0x000000ff); |
158 | } |
159 | |
160 | template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb); |
161 | |
162 | template<> |
163 | inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb) |
164 | { |
165 | quint16 alpha = rgb >> 30; |
166 | quint16 blue = (rgb >> 20) & 0x3ff; |
167 | quint16 green = (rgb >> 10) & 0x3ff; |
168 | quint16 red = rgb & 0x3ff; |
169 | // Expand the range. |
170 | alpha |= (alpha << 2); |
171 | alpha |= (alpha << 4); |
172 | alpha |= (alpha << 8); |
173 | red = (red << 6) | (red >> 4); |
174 | green = (green << 6) | (green >> 4); |
175 | blue = (blue << 6) | (blue >> 4); |
176 | return qRgba64(red, green, blue, alpha); |
177 | } |
178 | |
179 | template<> |
180 | inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb) |
181 | { |
182 | quint16 alpha = rgb >> 30; |
183 | quint16 red = (rgb >> 20) & 0x3ff; |
184 | quint16 green = (rgb >> 10) & 0x3ff; |
185 | quint16 blue = rgb & 0x3ff; |
186 | // Expand the range. |
187 | alpha |= (alpha << 2); |
188 | alpha |= (alpha << 4); |
189 | alpha |= (alpha << 8); |
190 | red = (red << 6) | (red >> 4); |
191 | green = (green << 6) | (green >> 4); |
192 | blue = (blue << 6) | (blue >> 4); |
193 | return qRgba64(red, green, blue, alpha); |
194 | } |
195 | |
196 | template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64); |
197 | |
198 | template<> |
199 | inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c) |
200 | { |
201 | c = qRepremultiply<14>(c); |
202 | const uint a = c.alpha() >> 14; |
203 | const uint r = c.red() >> 6; |
204 | const uint g = c.green() >> 6; |
205 | const uint b = c.blue() >> 6; |
206 | return (a << 30) | (b << 20) | (g << 10) | r; |
207 | } |
208 | |
209 | template<> |
210 | inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c) |
211 | { |
212 | c = qRepremultiply<14>(c); |
213 | const uint a = c.alpha() >> 14; |
214 | const uint r = c.red() >> 6; |
215 | const uint g = c.green() >> 6; |
216 | const uint b = c.blue() >> 6; |
217 | return (a << 30) | (r << 20) | (g << 10) | b; |
218 | } |
219 | |
220 | inline uint qRgbSwapRgb30(uint c) |
221 | { |
222 | const uint ag = c & 0xc00ffc00; |
223 | const uint rb = c & 0x3ff003ff; |
224 | return ag | (rb << 20) | (rb >> 20); |
225 | } |
226 | |
227 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
228 | static inline quint32 RGBA2ARGB(quint32 x) { |
229 | quint32 rgb = x >> 8; |
230 | quint32 a = x << 24; |
231 | return a | rgb; |
232 | } |
233 | |
234 | static inline quint32 ARGB2RGBA(quint32 x) { |
235 | quint32 rgb = x << 8; |
236 | quint32 a = x >> 24; |
237 | return a | rgb; |
238 | } |
239 | #else |
240 | static inline quint32 RGBA2ARGB(quint32 x) { |
241 | // RGBA8888 is ABGR32 on little endian. |
242 | quint32 ag = x & 0xff00ff00; |
243 | quint32 rg = x & 0x00ff00ff; |
244 | return ag | (rg << 16) | (rg >> 16); |
245 | } |
246 | |
247 | static inline quint32 ARGB2RGBA(quint32 x) { |
248 | return RGBA2ARGB(x); |
249 | } |
250 | #endif |
251 | |
252 | // We manually unalias the variables to make sure the compiler |
253 | // fully optimizes both aliased and unaliased cases. |
254 | #define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \ |
255 | if (src == buffer) { \ |
256 | for (int i = 0; i < count; ++i) \ |
257 | buffer[i] = conversion(buffer[i]); \ |
258 | } else { \ |
259 | for (int i = 0; i < count; ++i) \ |
260 | buffer[i] = conversion(src[i]); \ |
261 | } |
262 | |
263 | |
264 | inline const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count) |
265 | { |
266 | UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply); |
267 | return buffer; |
268 | } |
269 | |
270 | inline const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count) |
271 | { |
272 | UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));}); |
273 | return buffer; |
274 | } |
275 | |
276 | template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count); |
277 | |
278 | struct QDitherInfo { |
279 | int x; |
280 | int y; |
281 | }; |
282 | |
283 | typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const uchar *src, |
284 | int index, int count, |
285 | const QList<QRgb> *clut, |
286 | QDitherInfo *dither); |
287 | typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index, |
288 | int count, const QList<QRgb> *clut, |
289 | QDitherInfo *dither); |
290 | |
291 | typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src, |
292 | int index, int count, |
293 | const QList<QRgb> *clut, |
294 | QDitherInfo *dither); |
295 | typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index, |
296 | int count, const QList<QRgb> *clut, |
297 | QDitherInfo *dither); |
298 | |
299 | typedef void(QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QList<QRgb> *clut); |
300 | typedef void(QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QList<QRgb> *clut); |
301 | typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count, |
302 | const QList<QRgb> *clut, QDitherInfo *dither); |
303 | typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count); |
304 | |
305 | typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl); |
306 | |
307 | struct QPixelLayout |
308 | { |
309 | // Bits per pixel |
310 | enum BPP { |
311 | BPPNone, |
312 | BPP1MSB, |
313 | BPP1LSB, |
314 | BPP8, |
315 | BPP16, |
316 | BPP24, |
317 | BPP32, |
318 | BPP64, |
319 | BPPCount |
320 | }; |
321 | |
322 | bool hasAlphaChannel; |
323 | bool premultiplied; |
324 | BPP bpp; |
325 | RbSwapFunc rbSwap; |
326 | ConvertFunc convertToARGB32PM; |
327 | ConvertTo64Func convertToRGBA64PM; |
328 | FetchAndConvertPixelsFunc fetchToARGB32PM; |
329 | FetchAndConvertPixelsFunc64 fetchToRGBA64PM; |
330 | ConvertAndStorePixelsFunc storeFromARGB32PM; |
331 | ConvertAndStorePixelsFunc storeFromRGB32; |
332 | }; |
333 | |
334 | extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats]; |
335 | |
336 | extern QPixelLayout qPixelLayouts[QImage::NImageFormats]; |
337 | |
338 | extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3]; |
339 | |
340 | QT_END_NAMESPACE |
341 | |
342 | #endif // QPIXELLAYOUT_P_H |
343 | |