• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2007 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkBitmapProcState_DEFINED
9 #define SkBitmapProcState_DEFINED
10 
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkShader.h"
14 #include "include/private/SkFixed.h"
15 #include "include/private/SkFloatBits.h"
16 #include "include/private/SkTemplates.h"
17 #include "src/core/SkArenaAlloc.h"
18 #include "src/core/SkBitmapController.h"
19 #include "src/core/SkMatrixPriv.h"
20 #include "src/core/SkMipMap.h"
21 
22 typedef SkFixed3232    SkFractionalInt;
23 #define SkScalarToFractionalInt(x)  SkScalarToFixed3232(x)
24 #define SkFractionalIntToFixed(x)   SkFixed3232ToFixed(x)
25 #define SkFixedToFractionalInt(x)   SkFixedToFixed3232(x)
26 #define SkFractionalIntToInt(x)     SkFixed3232ToInt(x)
27 
28 class SkPaint;
29 
30 struct SkBitmapProcInfo {
31     SkBitmapProcInfo(const SkImage_Base*, SkTileMode tmx, SkTileMode tmy);
32     ~SkBitmapProcInfo();
33 
34     const SkImage_Base*     fImage;
35 
36     SkPixmap                fPixmap;
37     SkMatrix                fInvMatrix;         // This changes based on tile mode.
38     SkColor                 fPaintColor;
39     SkTileMode              fTileModeX;
40     SkTileMode              fTileModeY;
41     SkFilterQuality         fFilterQuality;
42 
43     bool init(const SkMatrix& inverse, const SkPaint&);
44 
45 private:
46     enum {
47         kBMStateSize = 136  // found by inspection. if too small, we will call new/delete
48     };
49     SkSTArenaAlloc<kBMStateSize> fAlloc;
50     SkBitmapController::State* fBMState;
51 };
52 
53 struct SkBitmapProcState : public SkBitmapProcInfo {
SkBitmapProcStateSkBitmapProcState54     SkBitmapProcState(const SkImage_Base* image, SkTileMode tmx, SkTileMode tmy)
55         : SkBitmapProcInfo(image, tmx, tmy) {}
56 
setupSkBitmapProcState57     bool setup(const SkMatrix& inv, const SkPaint& paint) {
58         return this->init(inv, paint) && this->chooseProcs();
59     }
60 
61     typedef void (*ShaderProc32)(const void* ctx, int x, int y, SkPMColor[], int count);
62 
63     typedef void (*MatrixProc)(const SkBitmapProcState&,
64                                uint32_t bitmapXY[],
65                                int count,
66                                int x, int y);
67 
68     typedef void (*SampleProc32)(const SkBitmapProcState&,
69                                  const uint32_t[],
70                                  int count,
71                                  SkPMColor colors[]);
72 
73     SkMatrixPriv::MapXYProc fInvProc;           // chooseProcs
74     SkFractionalInt     fInvSxFractionalInt;
75     SkFractionalInt     fInvKyFractionalInt;
76 
77     SkFixed             fFilterOneX;
78     SkFixed             fFilterOneY;
79 
80     uint16_t            fAlphaScale;        // chooseProcs
81 
82     /** Given the byte size of the index buffer to be passed to the matrix proc,
83         return the maximum number of resulting pixels that can be computed
84         (i.e. the number of SkPMColor values to be written by the sample proc).
85         This routine takes into account that filtering and scale-vs-affine
86         affect the amount of buffer space needed.
87 
88         Only valid to call after chooseProcs (setContext) has been called. It is
89         safe to call this inside the shader's shadeSpan() method.
90      */
91     int maxCountForBufferSize(size_t bufferSize) const;
92 
93     // If a shader proc is present, then the corresponding matrix/sample procs
94     // are ignored
getShaderProc32SkBitmapProcState95     ShaderProc32 getShaderProc32() const { return fShaderProc32; }
96 
97 #ifdef SK_DEBUG
98     MatrixProc getMatrixProc() const;
99 #else
getMatrixProcSkBitmapProcState100     MatrixProc getMatrixProc() const { return fMatrixProc; }
101 #endif
getSampleProc32SkBitmapProcState102     SampleProc32 getSampleProc32() const { return fSampleProc32; }
103 
104 private:
105     ShaderProc32        fShaderProc32;      // chooseProcs
106     // These are used if the shaderproc is nullptr
107     MatrixProc          fMatrixProc;        // chooseProcs
108     SampleProc32        fSampleProc32;      // chooseProcs
109 
110     MatrixProc chooseMatrixProc(bool trivial_matrix);
111     bool chooseProcs(); // caller must have called init() first (on our base-class)
112     ShaderProc32 chooseShaderProc32();
113 
114     // Return false if we failed to setup for fast translate (e.g. overflow)
115     bool setupForTranslate();
116 
117 #ifdef SK_DEBUG
118     static void DebugMatrixProc(const SkBitmapProcState&,
119                                 uint32_t[], int count, int x, int y);
120 #endif
121 };
122 
123 /*  Macros for packing and unpacking pairs of 16bit values in a 32bit uint.
124     Used to allow access to a stream of uint16_t either one at a time, or
125     2 at a time by unpacking a uint32_t
126  */
127 #ifdef SK_CPU_BENDIAN
128     #define PACK_TWO_SHORTS(pri, sec) ((pri) << 16 | (sec))
129     #define UNPACK_PRIMARY_SHORT(packed)    ((uint32_t)(packed) >> 16)
130     #define UNPACK_SECONDARY_SHORT(packed)  ((packed) & 0xFFFF)
131 #else
132     #define PACK_TWO_SHORTS(pri, sec) ((pri) | ((sec) << 16))
133     #define UNPACK_PRIMARY_SHORT(packed)    ((packed) & 0xFFFF)
134     #define UNPACK_SECONDARY_SHORT(packed)  ((uint32_t)(packed) >> 16)
135 #endif
136 
137 #ifdef SK_DEBUG
pack_two_shorts(U16CPU pri,U16CPU sec)138     static inline uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) {
139         SkASSERT((uint16_t)pri == pri);
140         SkASSERT((uint16_t)sec == sec);
141         return PACK_TWO_SHORTS(pri, sec);
142     }
143 #else
144     #define pack_two_shorts(pri, sec)   PACK_TWO_SHORTS(pri, sec)
145 #endif
146 
147 // Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space.
148 // Discussion:
149 // Overall, this code takes a point in destination space, and uses the center of the pixel
150 // at (x, y) to determine the sample point in source space. It then adjusts the pixel by different
151 // amounts based in filtering and tiling.
152 // This code can be broken into two main cases based on filtering:
153 // * no filtering (nearest neighbor) - when using nearest neighbor filtering all tile modes reduce
154 // the sampled by one ulp. If a simple point pt lies precisely on XXX.1/2 then it forced down
155 // when positive making 1/2 + 1/2 = .999999 instead of 1.0.
156 // * filtering - in the filtering case, the code calculates the -1/2 shift for starting the
157 // bilerp kernel. There is a twist; there is a big difference between clamp and the other tile
158 // modes. In tile and repeat the matrix has been reduced by an additional 1/width and 1/height
159 // factor. This maps from destination space to [0, 1) (instead of source space) to allow easy
160 // modulo arithmetic. This means that the -1/2 needed by bilerp is actually 1/2 * 1/width for x
161 // and 1/2 * 1/height for y. This is what happens when the poorly named fFilterOne{X|Y} is
162 // divided by two.
163 class SkBitmapProcStateAutoMapper {
164 public:
165     SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y,
166                                 SkPoint* scalarPoint = nullptr) {
167         SkPoint pt;
168         s.fInvProc(s.fInvMatrix,
169                    SkIntToScalar(x) + SK_ScalarHalf,
170                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
171 
172         SkFixed biasX, biasY;
173         if (s.fFilterQuality == kNone_SkFilterQuality) {
174             // SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded
175             // consistently WRT geometry.  Note that we only need the bias for positive scales:
176             // for negative scales, the rounding is intrinsically correct.
177             // We scale it to persist SkFractionalInt -> SkFixed conversions.
178             biasX = (s.fInvMatrix.getScaleX() > 0);
179             biasY = (s.fInvMatrix.getScaleY() > 0);
180         } else {
181             biasX = s.fFilterOneX >> 1;
182             biasY = s.fFilterOneY >> 1;
183         }
184 
185         // punt to unsigned for defined underflow behavior
186         fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) -
187                                (uint64_t)SkFixedToFractionalInt(biasX));
188         fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) -
189                                (uint64_t)SkFixedToFractionalInt(biasY));
190 
191         if (scalarPoint) {
192             scalarPoint->set(pt.x() - SkFixedToScalar(biasX),
193                              pt.y() - SkFixedToScalar(biasY));
194         }
195     }
196 
fractionalIntX()197     SkFractionalInt fractionalIntX() const { return fX; }
fractionalIntY()198     SkFractionalInt fractionalIntY() const { return fY; }
199 
fixedX()200     SkFixed fixedX() const { return SkFractionalIntToFixed(fX); }
fixedY()201     SkFixed fixedY() const { return SkFractionalIntToFixed(fY); }
202 
intX()203     int intX() const { return SkFractionalIntToInt(fX); }
intY()204     int intY() const { return SkFractionalIntToInt(fY); }
205 
206 private:
207     SkFractionalInt fX, fY;
208 };
209 
210 #endif
211