1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageScaling.h"
9 #include "DataSurfaceHelpers.h"
17 inline uint32_t Avg2x2(uint32_t a
, uint32_t b
, uint32_t c
, uint32_t d
) {
18 // Prepare half-adder work
19 uint32_t sum
= a
^ b
^ c
;
20 uint32_t carry
= (a
& b
) | (a
& c
) | (b
& c
);
22 // Before shifting, mask lower order bits of each byte to avoid underflow.
23 uint32_t mask
= 0xfefefefe;
25 // Add d to sum and divide by 2.
26 sum
= (((sum
^ d
) & mask
) >> 1) + (sum
& d
);
28 // Sum is now shifted into place relative to carry, add them together.
29 return (((sum
^ carry
) & mask
) >> 1) + (sum
& carry
);
32 inline uint32_t Avg2(uint32_t a
, uint32_t b
) {
33 // Prepare half-adder work
35 uint32_t carry
= (a
& b
);
37 // Before shifting, mask lower order bits of each byte to avoid underflow.
38 uint32_t mask
= 0xfefefefe;
40 // Add d to sum and divide by 2.
41 return ((sum
& mask
) >> 1) + carry
;
44 void ImageHalfScaler::ScaleForSize(const IntSize
& aSize
) {
45 uint32_t horizontalDownscales
= 0;
46 uint32_t verticalDownscales
= 0;
48 IntSize scaleSize
= mOrigSize
;
49 while ((scaleSize
.height
/ 2) > aSize
.height
) {
51 scaleSize
.height
/= 2;
54 while ((scaleSize
.width
/ 2) > aSize
.width
) {
55 horizontalDownscales
++;
59 if (scaleSize
== mOrigSize
) {
63 delete[] mDataStorage
;
65 IntSize internalSurfSize
;
66 internalSurfSize
.width
= std::max(scaleSize
.width
, mOrigSize
.width
/ 2);
67 internalSurfSize
.height
= std::max(scaleSize
.height
, mOrigSize
.height
/ 2);
70 mStride
= GetAlignedStride
<16>(internalSurfSize
.width
, 4);
72 // Allocate 15 bytes extra to make sure we can get 16 byte alignment. We
73 // should add tools for this, see bug 751696.
75 BufferSizeFromStrideAndHeight(mStride
, internalSurfSize
.height
, 15);
80 mDataStorage
= nullptr;
83 mDataStorage
= new uint8_t[bufLen
];
85 if (uintptr_t(mDataStorage
) % 16) {
86 // Our storage does not start at a 16-byte boundary. Make sure mData does!
87 mData
= (uint8_t*)(uintptr_t(mDataStorage
) +
88 (16 - (uintptr_t(mDataStorage
) % 16)));
95 /* The surface we sample from might not be even sized, if it's not we will
96 * ignore the last row/column. This means we lose some data but it keeps the
97 * code very simple. There's also no perfect answer that provides a better
100 IntSize currentSampledSize
= mOrigSize
;
101 uint32_t currentSampledStride
= mOrigStride
;
102 uint8_t* currentSampledData
= mOrigData
;
104 while (verticalDownscales
&& horizontalDownscales
) {
105 if (currentSampledSize
.width
% 2) {
106 currentSampledSize
.width
-= 1;
108 if (currentSampledSize
.height
% 2) {
109 currentSampledSize
.height
-= 1;
112 HalfImage2D(currentSampledData
, currentSampledStride
, currentSampledSize
,
115 verticalDownscales
--;
116 horizontalDownscales
--;
117 currentSampledSize
.width
/= 2;
118 currentSampledSize
.height
/= 2;
119 currentSampledData
= mData
;
120 currentSampledStride
= mStride
;
123 while (verticalDownscales
) {
124 if (currentSampledSize
.height
% 2) {
125 currentSampledSize
.height
-= 1;
128 HalfImageVertical(currentSampledData
, currentSampledStride
,
129 currentSampledSize
, mData
, mStride
);
131 verticalDownscales
--;
132 currentSampledSize
.height
/= 2;
133 currentSampledData
= mData
;
134 currentSampledStride
= mStride
;
137 while (horizontalDownscales
) {
138 if (currentSampledSize
.width
% 2) {
139 currentSampledSize
.width
-= 1;
142 HalfImageHorizontal(currentSampledData
, currentSampledStride
,
143 currentSampledSize
, mData
, mStride
);
145 horizontalDownscales
--;
146 currentSampledSize
.width
/= 2;
147 currentSampledData
= mData
;
148 currentSampledStride
= mStride
;
152 void ImageHalfScaler::HalfImage2D(uint8_t* aSource
, int32_t aSourceStride
,
153 const IntSize
& aSourceSize
, uint8_t* aDest
,
154 uint32_t aDestStride
) {
156 if (Factory::HasSSE2()) {
157 HalfImage2D_SSE2(aSource
, aSourceStride
, aSourceSize
, aDest
, aDestStride
);
161 HalfImage2D_C(aSource
, aSourceStride
, aSourceSize
, aDest
, aDestStride
);
165 void ImageHalfScaler::HalfImageVertical(uint8_t* aSource
, int32_t aSourceStride
,
166 const IntSize
& aSourceSize
,
167 uint8_t* aDest
, uint32_t aDestStride
) {
169 if (Factory::HasSSE2()) {
170 HalfImageVertical_SSE2(aSource
, aSourceStride
, aSourceSize
, aDest
,
175 HalfImageVertical_C(aSource
, aSourceStride
, aSourceSize
, aDest
,
180 void ImageHalfScaler::HalfImageHorizontal(uint8_t* aSource
,
181 int32_t aSourceStride
,
182 const IntSize
& aSourceSize
,
184 uint32_t aDestStride
) {
186 if (Factory::HasSSE2()) {
187 HalfImageHorizontal_SSE2(aSource
, aSourceStride
, aSourceSize
, aDest
,
192 HalfImageHorizontal_C(aSource
, aSourceStride
, aSourceSize
, aDest
,
197 void ImageHalfScaler::HalfImage2D_C(uint8_t* aSource
, int32_t aSourceStride
,
198 const IntSize
& aSourceSize
, uint8_t* aDest
,
199 uint32_t aDestStride
) {
200 for (int y
= 0; y
< aSourceSize
.height
; y
+= 2) {
201 uint32_t* storage
= (uint32_t*)(aDest
+ (y
/ 2) * aDestStride
);
202 for (int x
= 0; x
< aSourceSize
.width
; x
+= 2) {
203 uint8_t* upperRow
= aSource
+ (y
* aSourceStride
+ x
* 4);
204 uint8_t* lowerRow
= aSource
+ ((y
+ 1) * aSourceStride
+ x
* 4);
206 *storage
++ = Avg2x2(*(uint32_t*)upperRow
, *((uint32_t*)upperRow
+ 1),
207 *(uint32_t*)lowerRow
, *((uint32_t*)lowerRow
+ 1));
212 void ImageHalfScaler::HalfImageVertical_C(uint8_t* aSource
,
213 int32_t aSourceStride
,
214 const IntSize
& aSourceSize
,
216 uint32_t aDestStride
) {
217 for (int y
= 0; y
< aSourceSize
.height
; y
+= 2) {
218 uint32_t* storage
= (uint32_t*)(aDest
+ (y
/ 2) * aDestStride
);
219 for (int x
= 0; x
< aSourceSize
.width
; x
++) {
220 uint32_t* upperRow
= (uint32_t*)(aSource
+ (y
* aSourceStride
+ x
* 4));
222 (uint32_t*)(aSource
+ ((y
+ 1) * aSourceStride
+ x
* 4));
224 *storage
++ = Avg2(*upperRow
, *lowerRow
);
229 void ImageHalfScaler::HalfImageHorizontal_C(uint8_t* aSource
,
230 int32_t aSourceStride
,
231 const IntSize
& aSourceSize
,
233 uint32_t aDestStride
) {
234 for (int y
= 0; y
< aSourceSize
.height
; y
++) {
235 uint32_t* storage
= (uint32_t*)(aDest
+ y
* aDestStride
);
236 for (int x
= 0; x
< aSourceSize
.width
; x
+= 2) {
237 uint32_t* pixels
= (uint32_t*)(aSource
+ (y
* aSourceStride
+ x
* 4));
239 *storage
++ = Avg2(*pixels
, *(pixels
+ 1));
245 } // namespace mozilla