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