Line data Source code
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 "SkBitmap.h"
12 : #include "SkBitmapController.h"
13 : #include "SkBitmapFilter.h"
14 : #include "SkBitmapProvider.h"
15 : #include "SkFloatBits.h"
16 : #include "SkMatrix.h"
17 : #include "SkMipMap.h"
18 : #include "SkPaint.h"
19 : #include "SkShader.h"
20 : #include "SkTemplates.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 SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy);
32 : ~SkBitmapProcInfo();
33 :
34 : const SkBitmapProvider fProvider;
35 :
36 : SkPixmap fPixmap;
37 : SkMatrix fInvMatrix; // This changes based on tile mode.
38 : // TODO: combine fInvMatrix and fRealInvMatrix.
39 : SkMatrix fRealInvMatrix; // The actual inverse matrix.
40 : SkColor fPaintColor;
41 : SkShader::TileMode fTileModeX;
42 : SkShader::TileMode fTileModeY;
43 : SkFilterQuality fFilterQuality;
44 : SkMatrix::TypeMask fInvType;
45 :
46 : bool init(const SkMatrix& inverse, const SkPaint&);
47 :
48 : private:
49 : enum {
50 : kBMStateSize = 136 // found by inspection. if too small, we will call new/delete
51 : };
52 : SkAlignedSStorage<kBMStateSize> fBMStateStorage;
53 : SkBitmapController::State* fBMState;
54 : };
55 :
56 141 : struct SkBitmapProcState : public SkBitmapProcInfo {
57 141 : SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy)
58 141 : : SkBitmapProcInfo(prov, tmx, tmy) {}
59 :
60 141 : bool setup(const SkMatrix& inv, const SkPaint& paint) {
61 141 : return this->init(inv, paint) && this->chooseProcs();
62 : }
63 :
64 : typedef void (*ShaderProc32)(const void* ctx, int x, int y, SkPMColor[], int count);
65 :
66 : typedef void (*ShaderProc16)(const void* ctx, int x, int y, uint16_t[], int count);
67 :
68 : typedef void (*MatrixProc)(const SkBitmapProcState&,
69 : uint32_t bitmapXY[],
70 : int count,
71 : int x, int y);
72 :
73 : typedef void (*SampleProc32)(const SkBitmapProcState&,
74 : const uint32_t[],
75 : int count,
76 : SkPMColor colors[]);
77 :
78 : typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF
79 : typedef U16CPU (*IntTileProc)(int value, int count); // returns 0..count-1
80 :
81 : SkMatrix::MapXYProc fInvProc; // chooseProcs
82 : SkFractionalInt fInvSxFractionalInt;
83 : SkFractionalInt fInvKyFractionalInt;
84 :
85 : FixedTileProc fTileProcX; // chooseProcs
86 : FixedTileProc fTileProcY; // chooseProcs
87 : IntTileProc fIntTileProcY; // chooseProcs
88 : SkFixed fFilterOneX;
89 : SkFixed fFilterOneY;
90 :
91 : SkFixed fInvSx; // chooseProcs
92 : SkFixed fInvKy; // chooseProcs
93 : SkPMColor fPaintPMColor; // chooseProcs - A8 config
94 : uint16_t fAlphaScale; // chooseProcs
95 :
96 : /** Platforms implement this, and can optionally overwrite only the
97 : following fields:
98 :
99 : fShaderProc32
100 : fShaderProc16
101 : fMatrixProc
102 : fSampleProc32
103 : fSampleProc32
104 :
105 : They will already have valid function pointers, so a platform that does
106 : not have an accelerated version can just leave that field as is. A valid
107 : implementation can do nothing (see SkBitmapProcState_opts_none.cpp)
108 : */
109 : void platformProcs();
110 :
111 : /** Given the byte size of the index buffer to be passed to the matrix proc,
112 : return the maximum number of resulting pixels that can be computed
113 : (i.e. the number of SkPMColor values to be written by the sample proc).
114 : This routine takes into account that filtering and scale-vs-affine
115 : affect the amount of buffer space needed.
116 :
117 : Only valid to call after chooseProcs (setContext) has been called. It is
118 : safe to call this inside the shader's shadeSpan() method.
119 : */
120 : int maxCountForBufferSize(size_t bufferSize) const;
121 :
122 : // If a shader proc is present, then the corresponding matrix/sample procs
123 : // are ignored
124 7820 : ShaderProc32 getShaderProc32() const { return fShaderProc32; }
125 : ShaderProc16 getShaderProc16() const { return fShaderProc16; }
126 :
127 : #ifdef SK_DEBUG
128 : MatrixProc getMatrixProc() const;
129 : #else
130 : MatrixProc getMatrixProc() const { return fMatrixProc; }
131 : #endif
132 1854 : SampleProc32 getSampleProc32() const { return fSampleProc32; }
133 :
134 : private:
135 : ShaderProc32 fShaderProc32; // chooseProcs
136 : ShaderProc16 fShaderProc16; // chooseProcs
137 : // These are used if the shaderproc is nullptr
138 : MatrixProc fMatrixProc; // chooseProcs
139 : SampleProc32 fSampleProc32; // chooseProcs
140 :
141 : MatrixProc chooseMatrixProc(bool trivial_matrix);
142 : bool chooseProcs(); // caller must have called init() first (on our base-class)
143 : bool chooseScanlineProcs(bool trivialMatrix, bool clampClamp);
144 : ShaderProc32 chooseShaderProc32();
145 :
146 : // Return false if we failed to setup for fast translate (e.g. overflow)
147 : bool setupForTranslate();
148 :
149 : #ifdef SK_DEBUG
150 : static void DebugMatrixProc(const SkBitmapProcState&,
151 : uint32_t[], int count, int x, int y);
152 : #endif
153 : };
154 :
155 : /* Macros for packing and unpacking pairs of 16bit values in a 32bit uint.
156 : Used to allow access to a stream of uint16_t either one at a time, or
157 : 2 at a time by unpacking a uint32_t
158 : */
159 : #ifdef SK_CPU_BENDIAN
160 : #define PACK_TWO_SHORTS(pri, sec) ((pri) << 16 | (sec))
161 : #define UNPACK_PRIMARY_SHORT(packed) ((uint32_t)(packed) >> 16)
162 : #define UNPACK_SECONDARY_SHORT(packed) ((packed) & 0xFFFF)
163 : #else
164 : #define PACK_TWO_SHORTS(pri, sec) ((pri) | ((sec) << 16))
165 : #define UNPACK_PRIMARY_SHORT(packed) ((packed) & 0xFFFF)
166 : #define UNPACK_SECONDARY_SHORT(packed) ((uint32_t)(packed) >> 16)
167 : #endif
168 :
169 : #ifdef SK_DEBUG
170 0 : static inline uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) {
171 0 : SkASSERT((uint16_t)pri == pri);
172 0 : SkASSERT((uint16_t)sec == sec);
173 0 : return PACK_TWO_SHORTS(pri, sec);
174 : }
175 : #else
176 : #define pack_two_shorts(pri, sec) PACK_TWO_SHORTS(pri, sec)
177 : #endif
178 :
179 : // These functions are generated via macros, but are exposed here so that
180 : // platformProcs may test for them by name.
181 : void S32_opaque_D32_filter_DX(const SkBitmapProcState& s, const uint32_t xy[],
182 : int count, SkPMColor colors[]);
183 : void S32_alpha_D32_filter_DX(const SkBitmapProcState& s, const uint32_t xy[],
184 : int count, SkPMColor colors[]);
185 : void S32_opaque_D32_filter_DXDY(const SkBitmapProcState& s,
186 : const uint32_t xy[], int count, SkPMColor colors[]);
187 : void S32_alpha_D32_filter_DXDY(const SkBitmapProcState& s,
188 : const uint32_t xy[], int count, SkPMColor colors[]);
189 : void ClampX_ClampY_filter_scale(const SkBitmapProcState& s, uint32_t xy[],
190 : int count, int x, int y);
191 : void ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[],
192 : int count, int x, int y);
193 : void ClampX_ClampY_filter_affine(const SkBitmapProcState& s,
194 : uint32_t xy[], int count, int x, int y);
195 : void ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s,
196 : uint32_t xy[], int count, int x, int y);
197 :
198 : // Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space.
199 : // Discussion:
200 : // Overall, this code takes a point in destination space, and uses the center of the pixel
201 : // at (x, y) to determine the sample point in source space. It then adjusts the pixel by different
202 : // amounts based in filtering and tiling.
203 : // This code can be broken into two main cases based on filtering:
204 : // * no filtering (nearest neighbor) - when using nearest neighbor filtering all tile modes reduce
205 : // the sampled by one ulp. If a simple point pt lies precisely on XXX.1/2 then it forced down
206 : // when positive making 1/2 + 1/2 = .999999 instead of 1.0.
207 : // * filtering - in the filtering case, the code calculates the -1/2 shift for starting the
208 : // bilerp kernel. There is a twist; there is a big difference between clamp and the other tile
209 : // modes. In tile and repeat the matrix has been reduced by an additional 1/width and 1/height
210 : // factor. This maps from destination space to [0, 1) (instead of source space) to allow easy
211 : // modulo arithmetic. This means that the -1/2 needed by bilerp is actually 1/2 * 1/width for x
212 : // and 1/2 * 1/height for y. This is what happens when the poorly named fFilterOne{X|Y} is
213 : // divided by two.
214 : class SkBitmapProcStateAutoMapper {
215 : public:
216 2925 : SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y,
217 2925 : SkPoint* scalarPoint = nullptr) {
218 : SkPoint pt;
219 8775 : s.fInvProc(s.fInvMatrix,
220 2925 : SkIntToScalar(x) + SK_ScalarHalf,
221 5850 : SkIntToScalar(y) + SK_ScalarHalf, &pt);
222 :
223 : SkFixed biasX, biasY;
224 2925 : if (s.fFilterQuality == kNone_SkFilterQuality) {
225 : // SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded
226 : // consistently WRT geometry. Note that we only need the bias for positive scales:
227 : // for negative scales, the rounding is intrinsically correct.
228 : // We scale it to persist SkFractionalInt -> SkFixed conversions.
229 1579 : biasX = (s.fInvMatrix.getScaleX() > 0);
230 1579 : biasY = (s.fInvMatrix.getScaleY() > 0);
231 : } else {
232 1346 : biasX = s.fFilterOneX >> 1;
233 1346 : biasY = s.fFilterOneY >> 1;
234 : }
235 :
236 : // punt to unsigned for defined underflow behavior
237 5850 : fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) -
238 2925 : (uint64_t)SkFixedToFractionalInt(biasX));
239 5850 : fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) -
240 2925 : (uint64_t)SkFixedToFractionalInt(biasY));
241 :
242 2925 : if (scalarPoint) {
243 83 : scalarPoint->set(pt.x() - SkFixedToScalar(biasX),
244 166 : pt.y() - SkFixedToScalar(biasY));
245 : }
246 2925 : }
247 :
248 620 : SkFractionalInt fractionalIntX() const { return fX; }
249 0 : SkFractionalInt fractionalIntY() const { return fY; }
250 :
251 726 : SkFixed fixedX() const { return SkFractionalIntToFixed(fX); }
252 1346 : SkFixed fixedY() const { return SkFractionalIntToFixed(fY); }
253 :
254 1187 : int intX() const { return SkFractionalIntToInt(fX); }
255 1579 : int intY() const { return SkFractionalIntToInt(fY); }
256 :
257 : private:
258 : SkFractionalInt fX, fY;
259 : };
260 :
261 : #endif
|