Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / portable / image-operations.h
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
19 #define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/bitmap.h>
26 #include <dali/public-api/images/image-attributes.h>
27
28 namespace Dali
29 {
30 namespace Internal
31 {
32 namespace Platform
33 {
34
35 /**
36  * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
37  */
38 enum BoxDimensionTest
39 {
40   BoxDimensionTestEither,
41   BoxDimensionTestBoth,
42   BoxDimensionTestX,
43   BoxDimensionTestY
44 };
45
46 /**
47  * @brief Simple class for passing around pairs of small ints.
48  *
49  * These are immutable. If you want to change a value, make a whole new object.
50  * @note One of these can be passed in a single 32 bit integer register on
51  * common architectures.
52  */
53 class Vector2Uint16
54 {
55 public:
56   /**
57    * @brief Default constructor for the (0, 0) vector.
58    */
59   Vector2Uint16() : mData(0) {}
60
61   /**
62    * @brief Constructor taking separate x and y (width and height) parameters.
63    * @param[in] width The width or X dimension of the vector. Make sure it is less than 65536,
64    * @param[in] height The height or Y dimension of the vector. Make sure it is less than 65536,
65    */
66   Vector2Uint16( uint32_t width, uint32_t height )
67   {
68     DALI_ASSERT_DEBUG( width < ( 1u << 16 ) && "Width parameter not representable." );
69     DALI_ASSERT_DEBUG( height < ( 1u << 16 ) && "Height parameter not representable." );
70
71     /* Do equivalent of the code below with one aligned memory access:
72      * mComponents[0] = width;
73      * mComponents[1] = height;
74      * Unit tests make sure this is equivalent.
75      **/
76     mData = (height << 16u) + width;
77   }
78
79   /**
80    * @brief Copy constructor.
81    */
82   Vector2Uint16( const Vector2Uint16& rhs )
83   {
84     mData = rhs.mData;
85   }
86
87   /**
88    * @returns the x dimension stored in this 2-tuple.
89    */
90   uint16_t GetWidth() const
91   {
92     return mComponents[0];
93   }
94
95   /**
96    * @returns the y dimension stored in this 2-tuple.
97    */
98   uint16_t GetHeight() const
99   {
100     return mComponents[1];
101   }
102
103   /**
104    * @returns the x dimension stored in this 2-tuple.
105    */
106   uint16_t GetX()  const
107   {
108     return mComponents[0];
109   }
110
111   /**
112    * @returns the y dimension stored in this 2-tuple.
113    */
114   uint16_t GetY() const
115   {
116     return mComponents[1];
117   }
118
119 private:
120   union
121   {
122     // Addressable view of X and Y:
123     uint16_t mComponents[2];
124     // Packed view of X and Y to force alignment and allow a faster copy:
125     uint32_t mData;
126   };
127 };
128
129 /**
130  * @brief The integer dimensions of an image or a region of an image packed into
131  *        16 bits per component.
132  * @note  This can only be used for images of up to 65535 x 65535 pixels.
133   */
134 typedef Vector2Uint16 ImageDimensions;
135
136 /**
137  * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
138  * @{
139  */
140
141 /**
142  * @brief Apply requested attributes to bitmap.
143  *
144  * This is the top-level function which runs the on-load image post-processing
145  * pipeline. Bitmaps enter here as loaded from the file system by the file
146  * loaders and leave downscaled and filtered as requested by the application,
147  * ready for use.
148  *
149  * @param[in] bitmap The input bitmap.
150  * @param[in] requestedAttributes Attributes which should be applied to bitmap.
151  * @return A bitmap which results from applying the requested attributes to the
152  *         bitmap passed-in, or the original bitmap passed in if the attributes
153  *         have no effect.
154  */
155 Integration::BitmapPtr ApplyAttributesToBitmap( Integration::BitmapPtr bitmap, const ImageAttributes& requestedAttributes );
156
157 /**
158  * @brief Apply downscaling to a bitmap according to requested attributes.
159  * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
160  **/
161 Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap, ImageDimensions desired, ImageAttributes::ScalingMode scalingMode, ImageAttributes::FilterMode filterMode );
162 /**@}*/
163
164 /**
165  * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
166  * @{
167  */
168
169 /**
170  * @brief Destructive in-place downscaling by a power of 2 factor.
171  *
172  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
173  * of the next downscaling step would not be smaller than the desired
174  * dimensions.
175  * @param[in,out] pixels The buffer both to read from and write the result to.
176  * @param[in]     pixelFormat The format of the image pointed at by pixels.
177  * @param[in]     inputWidth The width of the input image.
178  * @param[in]     inputHeight The height of the input image.
179  * @param[in]     desiredWidth The width the client is requesting.
180  * @param[in]     desiredHeight The height the client is requesting.
181  * @param[out]    outWidth  The resulting width after downscaling.
182  * @param[out]    outHeight The resulting height after downscaling.
183  */
184 void DownscaleInPlacePow2( unsigned char * const pixels,
185                            Pixel::Format pixelFormat,
186                            unsigned int inputWidth,
187                            unsigned int inputHeight,
188                            unsigned int desiredWidth,
189                            unsigned int desiredHeight,
190                            ImageAttributes::ScalingMode scalingMode,
191                            ImageAttributes::FilterMode filterMode,
192                            unsigned& outWidth,
193                            unsigned& outHeight );
194
195 /**
196  * @brief Destructive in-place downscaling by a power of 2 factor.
197  *
198  * A box filter with a 2x2 kernel is repeatedly applied as long as the result
199  * of the next downscaling step would not be smaller than the desired
200  * dimensions.
201  * @param[in,out] pixels The buffer both to read from and write the result to.
202  * @param[in]     inputWidth The width of the input image.
203  * @param[in]     inputHeight The height of the input image.
204  * @param[in]     desiredWidth The width the client is requesting.
205  * @param[in]     desiredHeight The height the client is requesting.
206  * @param[out]    outWidth  The resulting width after downscaling.
207  * @param[out]    outHeight The resulting height after downscaling.
208  */
209 void DownscaleInPlacePow2RGB888( unsigned char * pixels,
210                                  unsigned int inputWidth,
211                                  unsigned int inputHeight,
212                                  unsigned int desiredWidth,
213                                  unsigned int desiredHeight,
214                                  BoxDimensionTest dimensionTest,
215                                  unsigned int& outWidth,
216                                  unsigned int& outHeight );
217
218 /**
219  * @copydoc DownscaleInPlacePow2RGB888
220  */
221 void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
222                                    unsigned int inputWidth,
223                                    unsigned int inputHeight,
224                                    unsigned int desiredWidth,
225                                    unsigned int desiredHeight,
226                                    BoxDimensionTest dimensionTest,
227                                    unsigned int& outWidth,
228                                    unsigned int& outHeight );
229
230 /**
231  * @copydoc DownscaleInPlacePow2RGB888
232  *
233  * For the 2-byte packed 16 bit format RGB565.
234  */
235 void DownscaleInPlacePow2RGB565( unsigned char * pixels,
236                                  unsigned int inputWidth,
237                                  unsigned int inputHeight,
238                                  unsigned int desiredWidth,
239                                  unsigned int desiredHeight,
240                                  BoxDimensionTest dimensionTest,
241                                  unsigned int& outWidth,
242                                  unsigned int& outHeight );
243
244 /**
245  * @copydoc DownscaleInPlacePow2RGB888
246  *
247  * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
248  */
249 void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
250                                         unsigned int inputWidth,
251                                         unsigned int inputHeight,
252                                         unsigned int desiredWidth,
253                                         unsigned int desiredHeight,
254                                         BoxDimensionTest dimensionTest,
255                                         unsigned int& outWidth,
256                                         unsigned int& outHeight );
257
258 /**
259  * @copydoc DownscaleInPlacePow2RGB888
260  *
261  * For single-byte formats such as lum8 or alpha8.
262  */
263 void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
264                                              unsigned int inputWidth,
265                                              unsigned int inputHeight,
266                                              unsigned int desiredWidth,
267                                              unsigned int desiredHeight,
268                                              BoxDimensionTest dimensionTest,
269                                              unsigned int& outWidth,
270                                              unsigned int& outHeight );
271
272 /**
273  * @brief Rescales an input image into the exact output dimensions passed-in.
274  *
275  * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
276  * fastest results, at the expense of aliasing (noisy images) when downscaling.
277  * @note inPixels is allowed to alias outPixels if this is a downscaling,
278  * but not for upscaling.
279  */
280 void PointSample( const unsigned char * inPixels,
281                   unsigned int inputWidth,
282                   unsigned int inputHeight,
283                   Pixel::Format pixelFormat,
284                   unsigned char * outPixels,
285                   unsigned int desiredWidth,
286                   unsigned int desiredHeight );
287
288 /**
289  * @copydoc PointSample
290  *
291  * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
292  */
293 void PointSample4BPP( const unsigned char * inPixels,
294                       unsigned int inputWidth,
295                       unsigned int inputHeight,
296                       unsigned char * outPixels,
297                       unsigned int desiredWidth,
298                       unsigned int desiredHeight );
299
300 /**
301  * @copydoc PointSample
302  *
303  * Specialised for 3-byte formats like RGB888 and BGR888.
304  */
305 void PointSample3BPP( const unsigned char * inPixels,
306                       unsigned int inputWidth,
307                       unsigned int inputHeight,
308                       unsigned char * outPixels,
309                       unsigned int desiredWidth,
310                       unsigned int desiredHeight );
311
312 /**
313  * @copydoc PointSample
314  *
315  * Specialised for 2-byte formats like LA88.
316  */
317 void PointSample2BPP( const unsigned char * inPixels,
318                       unsigned int inputWidth,
319                       unsigned int inputHeight,
320                       unsigned char * outPixels,
321                       unsigned int desiredWidth,
322                       unsigned int desiredHeight );
323
324 /**
325  * @copydoc PointSample
326  *
327  * Specialised for 1-byte formats like L8 and A8.
328  */
329 void PointSample1BPP( const unsigned char * inPixels,
330                       unsigned int inputWidth,
331                       unsigned int inputHeight,
332                       unsigned char * outPixels,
333                       unsigned int desiredWidth,
334                       unsigned int desiredHeight );
335
336 /**
337  * @brief Resample input image to output image using a bilinear filter.
338  *
339  * Each output pixel is formed of a weighted sum of a 2x2 block of four input
340  * pixels
341  * @pre inPixels must not alias outPixels. The input image should be a totally
342  * separate buffer from the input one.
343  */
344 void LinearSample( const unsigned char * __restrict__ inPixels,
345                    ImageDimensions inDimensions,
346                    Pixel::Format pixelFormat,
347                    unsigned char * __restrict__ outPixels,
348                    ImageDimensions outDimensions );
349
350 /**
351  * @copydoc LinearSample
352  *
353  * Specialised for one byte per pixel formats.
354  */
355 void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
356                        ImageDimensions inputDimensions,
357                        unsigned char * __restrict__ outPixels,
358                        ImageDimensions desiredDimensions );
359
360 /**
361  * @copydoc LinearSample
362  *
363  * Specialised for two byte per pixel formats.
364  */
365 void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
366                        ImageDimensions inputDimensions,
367                        unsigned char * __restrict__ outPixels,
368                        ImageDimensions desiredDimensions );
369
370 /**
371  * @copydoc LinearSample
372  *
373  * Specialised for RGB565 16 bit pixel format.
374  */
375 void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
376                        ImageDimensions inputDimensions,
377                        unsigned char * __restrict__ outPixels,
378                        ImageDimensions desiredDimensions );
379
380 /**
381  * @copydoc LinearSample
382  *
383  * Specialised for three byte per pixel formats like RGB888.
384  */
385 void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
386                        ImageDimensions inputDimensions,
387                        unsigned char * __restrict__ outPixels,
388                        ImageDimensions desiredDimensions );
389
390 /**
391  * @copydoc LinearSample
392  *
393  * Specialised for four byte per pixel formats like RGBA888.
394  * @note, If used on RGBA8888, the A component will be blended independently.
395  */
396 void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
397                        ImageDimensions inputDimensions,
398                        unsigned char * __restrict__ outPixels,
399                        ImageDimensions desiredDimensions );
400
401 /**@}*/
402
403 /**
404  * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
405  * @{
406  */
407
408 /**
409  * @brief Average adjacent pairs of pixels, overwriting the input array.
410  * @param[in,out] pixels The array of pixels to work on.
411  * @param[i]      width  The number of pixels in the array passed-in.
412  */
413 void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
414
415 /**
416  * @copydoc HalveScanlineInPlaceRGB888
417  */
418 void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
419
420 /**
421  * @copydoc HalveScanlineInPlaceRGB888
422  */
423 void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
424
425 /**
426  * @copydoc HalveScanlineInPlaceRGB888
427  */
428 void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
429
430 /**
431  * @copydoc HalveScanlineInPlaceRGB888
432  */
433 void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
434
435 /**
436  * @brief Average pixels at corresponding offsets in two scanlines.
437  *
438  * outputScanline is allowed to alias scanline1.
439  * @param[in] scanline1 First scanline of pixels to average.
440  * @param[in] scanline2 Second scanline of pixels to average.
441  * @param[out] outputScanline Destination for the averaged pixels.
442  * @param[in] width The widths of all the scanlines passed-in.
443  */
444 void AverageScanlines1( const unsigned char * scanline1,
445                         const unsigned char * scanline2,
446                         unsigned char* outputScanline,
447                         /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
448                         unsigned int width );
449
450 /**
451  * @copydoc AverageScanlines1
452  */
453 void AverageScanlines2( const unsigned char * scanline1,
454                         const unsigned char * scanline2,
455                         unsigned char* outputScanline,
456                         /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
457                         unsigned int width );
458
459 /**
460  * @copydoc AverageScanlines1
461  */
462 void AverageScanlines3( const unsigned char * scanline1,
463                         const unsigned char * scanline2,
464                         unsigned char* outputScanline,
465                         /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
466                         unsigned int width );
467
468 /**
469  * @copydoc AverageScanlines1
470  */
471 void AverageScanlinesRGBA8888( const unsigned char * scanline1,
472                                const unsigned char * scanline2,
473                                unsigned char * outputScanline,
474                                unsigned int width );
475
476 /**
477  * @copydoc AverageScanlines1
478  */
479 void AverageScanlinesRGB565( const unsigned char * scanline1,
480                              const unsigned char * scanline2,
481                              unsigned char* outputScanline,
482                              unsigned int width );
483 /**@}*/
484
485 /**
486  * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
487  * @{
488  */
489
490 /**
491  * @brief Average two integer arguments.
492  * @return The average of two uint arguments.
493  * @param[in] a First component to average.
494  * @param[in] b Second component to average.
495  **/
496 inline unsigned int AverageComponent( unsigned int a, unsigned int b )
497 {
498   unsigned int avg = (a + b) >> 1u;
499   return avg;
500 }
501
502 /**
503  * @brief Average a pair of RGBA8888 pixels.
504  * @return The average of two RGBA8888 pixels.
505  * @param[in] a First pixel to average.
506  * @param[in] b Second pixel to average
507  **/
508 inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
509 {
510   const unsigned int avg =
511     ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
512     (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
513     (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
514     (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
515   return avg;
516   ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
517   ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
518 }
519
520 /**
521  * @brief Average a pair of RGB565 pixels.
522  * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
523  * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
524  * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
525  **/
526 inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
527 {
528   const unsigned int avg =
529     (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
530     (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
531     (AverageComponent( a & 0x1f,   b & 0x1f ) );
532   return avg;
533 }
534
535 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
536 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
537 {
538   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
539   const unsigned int weightedAFixed = a * (65535u - fractBlend);
540   const unsigned int weightedBFixed = b * fractBlend;
541   const unsigned blended = (weightedAFixed + weightedBFixed);
542   return blended;
543 }
544
545 /** @brief Blend two 16.16 inputs to give a 16.32 output. */
546 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
547 {
548   DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
549   // Blend while promoting intermediates to 16.32 fixed point:
550   const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
551   const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
552   const uint64_t blended = (weightedAFixed + weightedBFixed);
553   return blended;
554 }
555
556 /**
557  * @brief Blend 4 taps into one value using horizontal and vertical weights.
558  */
559 inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
560 {
561   DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
562   DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
563   //
564   const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
565   const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
566   const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
567   const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
568   return rounded;
569 }
570
571 /**@}*/
572
573 } /* namespace Platform */
574 } /* namespace Internal */
575 } /* namespace Dali */
576
577 #endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */