1/****************************************************************************
2**
3** Copyright (C) 2016 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#include "qmemrotate_p.h"
41#include "qpixellayout_p.h"
42
43QT_BEGIN_NAMESPACE
44
45static const int tileSize = 32;
46
47template <class T>
48static
49inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
50{
51 sstride /= sizeof(T);
52 dstride /= sizeof(T);
53
54 const int pack = sizeof(quint32) / sizeof(T);
55 const int unaligned =
56 qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
57 const int restX = w % tileSize;
58 const int restY = (h - unaligned) % tileSize;
59 const int unoptimizedY = restY % pack;
60 const int numTilesX = w / tileSize + (restX > 0);
61 const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
62
63 for (int tx = 0; tx < numTilesX; ++tx) {
64 const int startx = w - tx * tileSize - 1;
65 const int stopx = qMax(startx - tileSize, 0);
66
67 if (unaligned) {
68 for (int x = startx; x >= stopx; --x) {
69 T *d = dest + (w - x - 1) * dstride;
70 for (int y = 0; y < unaligned; ++y) {
71 *d++ = src[y * sstride + x];
72 }
73 }
74 }
75
76 for (int ty = 0; ty < numTilesY; ++ty) {
77 const int starty = ty * tileSize + unaligned;
78 const int stopy = qMin(starty + tileSize, h - unoptimizedY);
79
80 for (int x = startx; x >= stopx; --x) {
81 quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride + starty);
82 for (int y = starty; y < stopy; y += pack) {
83 quint32 c = src[y * sstride + x];
84 for (int i = 1; i < pack; ++i) {
85 const int shift = (sizeof(T) * 8 * i);
86 const T color = src[(y + i) * sstride + x];
87 c |= color << shift;
88 }
89 *d++ = c;
90 }
91 }
92 }
93
94 if (unoptimizedY) {
95 const int starty = h - unoptimizedY;
96 for (int x = startx; x >= stopx; --x) {
97 T *d = dest + (w - x - 1) * dstride + starty;
98 for (int y = starty; y < h; ++y) {
99 *d++ = src[y * sstride + x];
100 }
101 }
102 }
103 }
104}
105
106template <class T>
107static
108inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
109 int dstride)
110{
111 const int numTilesX = (w + tileSize - 1) / tileSize;
112 const int numTilesY = (h + tileSize - 1) / tileSize;
113
114 for (int tx = 0; tx < numTilesX; ++tx) {
115 const int startx = w - tx * tileSize - 1;
116 const int stopx = qMax(startx - tileSize, 0);
117
118 for (int ty = 0; ty < numTilesY; ++ty) {
119 const int starty = ty * tileSize;
120 const int stopy = qMin(starty + tileSize, h);
121
122 for (int x = startx; x >= stopx; --x) {
123 T *d = (T *)((char*)dest + (w - x - 1) * dstride) + starty;
124 const char *s = (const char*)(src + x) + starty * sstride;
125 for (int y = starty; y < stopy; ++y) {
126 *d++ = *(const T *)(s);
127 s += sstride;
128 }
129 }
130 }
131 }
132}
133
134template <class T>
135static
136inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
137{
138 sstride /= sizeof(T);
139 dstride /= sizeof(T);
140
141 const int pack = sizeof(quint32) / sizeof(T);
142 const int unaligned =
143 qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
144 const int restX = w % tileSize;
145 const int restY = (h - unaligned) % tileSize;
146 const int unoptimizedY = restY % pack;
147 const int numTilesX = w / tileSize + (restX > 0);
148 const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
149
150 for (int tx = 0; tx < numTilesX; ++tx) {
151 const int startx = tx * tileSize;
152 const int stopx = qMin(startx + tileSize, w);
153
154 if (unaligned) {
155 for (int x = startx; x < stopx; ++x) {
156 T *d = dest + x * dstride;
157 for (int y = h - 1; y >= h - unaligned; --y) {
158 *d++ = src[y * sstride + x];
159 }
160 }
161 }
162
163 for (int ty = 0; ty < numTilesY; ++ty) {
164 const int starty = h - 1 - unaligned - ty * tileSize;
165 const int stopy = qMax(starty - tileSize, unoptimizedY);
166
167 for (int x = startx; x < stopx; ++x) {
168 quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
169 + h - 1 - starty);
170 for (int y = starty; y >= stopy; y -= pack) {
171 quint32 c = src[y * sstride + x];
172 for (int i = 1; i < pack; ++i) {
173 const int shift = (sizeof(T) * 8 * i);
174 const T color = src[(y - i) * sstride + x];
175 c |= color << shift;
176 }
177 *d++ = c;
178 }
179 }
180 }
181 if (unoptimizedY) {
182 const int starty = unoptimizedY - 1;
183 for (int x = startx; x < stopx; ++x) {
184 T *d = dest + x * dstride + h - 1 - starty;
185 for (int y = starty; y >= 0; --y) {
186 *d++ = src[y * sstride + x];
187 }
188 }
189 }
190 }
191}
192
193template <class T>
194static
195inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
196 int dstride)
197{
198 const int numTilesX = (w + tileSize - 1) / tileSize;
199 const int numTilesY = (h + tileSize - 1) / tileSize;
200
201 for (int tx = 0; tx < numTilesX; ++tx) {
202 const int startx = tx * tileSize;
203 const int stopx = qMin(startx + tileSize, w);
204
205 for (int ty = 0; ty < numTilesY; ++ty) {
206 const int starty = h - 1 - ty * tileSize;
207 const int stopy = qMax(starty - tileSize, 0);
208
209 for (int x = startx; x < stopx; ++x) {
210 T *d = (T*)((char*)dest + x * dstride) + h - 1 - starty;
211 const char *s = (const char*)(src + x) + starty * sstride;
212 for (int y = starty; y >= stopy; --y) {
213 *d++ = *(const T*)s;
214 s -= sstride;
215 }
216 }
217 }
218 }
219}
220
221
222template <class T>
223static
224inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, int srcStride,
225 T *dest, int dstStride)
226{
227#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
228 // packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
229 if (sizeof(quint32) % sizeof(T) == 0)
230 qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
231 else
232#endif
233 qt_memrotate90_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
234}
235
236template <>
237inline void qt_memrotate90_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
238{
239 // packed algorithm doesn't have any benefit for quint32
240 qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
241}
242
243template <>
244inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
245{
246 qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
247}
248
249template <class T>
250static
251inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
252{
253 const char *s = (const char*)(src) + (h - 1) * sstride;
254 for (int dy = 0; dy < h; ++dy) {
255 T *d = reinterpret_cast<T*>((char *)(dest) + dy * dstride);
256 src = reinterpret_cast<const T*>(s);
257 for (int dx = 0; dx < w; ++dx) {
258 d[dx] = src[w - 1 - dx];
259 }
260 s -= sstride;
261 }
262}
263
264template <class T>
265static
266inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight, int srcStride,
267 T *dest, int dstStride)
268{
269#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
270 // packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
271 if (sizeof(quint32) % sizeof(T) == 0)
272 qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
273 else
274#endif
275 qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
276}
277
278template <>
279inline void qt_memrotate270_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
280{
281 // packed algorithm doesn't have any benefit for quint32
282 qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
283}
284
285template <>
286inline void qt_memrotate270_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
287{
288 qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
289}
290
291#define QT_IMPL_MEMROTATE(type) \
292Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
293 type *dest, int dstride) \
294{ \
295 qt_memrotate90_template(src, w, h, sstride, dest, dstride); \
296} \
297Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
298 type *dest, int dstride) \
299{ \
300 qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
301} \
302Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
303 type *dest, int dstride) \
304{ \
305 qt_memrotate270_template(src, w, h, sstride, dest, dstride); \
306}
307
308#define QT_IMPL_SIMPLE_MEMROTATE(type) \
309Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
310 type *dest, int dstride) \
311{ \
312 qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride); \
313} \
314Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
315 type *dest, int dstride) \
316{ \
317 qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
318} \
319Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
320 type *dest, int dstride) \
321{ \
322 qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride); \
323}
324
325QT_IMPL_MEMROTATE(quint64)
326QT_IMPL_MEMROTATE(quint32)
327QT_IMPL_MEMROTATE(quint16)
328QT_IMPL_MEMROTATE(quint24)
329QT_IMPL_MEMROTATE(quint8)
330
331void qt_memrotate90_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
332{
333 qt_memrotate90(srcPixels, w, h, sbpl, destPixels, dbpl);
334}
335
336void qt_memrotate180_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
337{
338 qt_memrotate180(srcPixels, w, h, sbpl, destPixels, dbpl);
339}
340
341void qt_memrotate270_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
342{
343 qt_memrotate270(srcPixels, w, h, sbpl, destPixels, dbpl);
344}
345
346void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
347{
348 qt_memrotate90((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
349}
350
351void qt_memrotate180_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
352{
353 qt_memrotate180((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
354}
355
356void qt_memrotate270_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
357{
358 qt_memrotate270((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
359}
360
361void qt_memrotate90_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
362{
363 qt_memrotate90((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
364}
365
366void qt_memrotate180_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
367{
368 qt_memrotate180((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
369}
370
371void qt_memrotate270_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
372{
373 qt_memrotate270((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
374}
375
376void qt_memrotate90_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
377{
378 qt_memrotate90((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
379}
380
381void qt_memrotate180_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
382{
383 qt_memrotate180((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
384}
385
386void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
387{
388 qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
389}
390
391
392void qt_memrotate90_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
393{
394 qt_memrotate90((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
395}
396
397void qt_memrotate180_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
398{
399 qt_memrotate180((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
400}
401
402void qt_memrotate270_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
403{
404 qt_memrotate270((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
405}
406
407MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
408// 90, 180, 270
409{
410 { nullptr, nullptr, nullptr }, // BPPNone,
411 { nullptr, nullptr, nullptr }, // BPP1MSB,
412 { nullptr, nullptr, nullptr }, // BPP1LSB,
413 { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // BPP8,
414 { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // BPP16,
415 { qt_memrotate90_24, qt_memrotate180_24, qt_memrotate270_24 }, // BPP24
416 { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // BPP32
417 { qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP64
418};
419
420QT_END_NAMESPACE
421