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