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 "SkBitmapProvider.h" 14 #include "SkFixed.h" 15 #include "SkFloatBits.h" 16 #include "SkMatrixPriv.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 struct SkBitmapProcState : public SkBitmapProcInfo { 57 SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy) 58 : SkBitmapProcInfo(prov, tmx, tmy) {} 59 60 bool setup(const SkMatrix& inv, const SkPaint& paint) { 61 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 SkMatrixPriv::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 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 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 static inline uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) { 171 SkASSERT((uint16_t)pri == pri); 172 SkASSERT((uint16_t)sec == sec); 173 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 ClampX_ClampY_filter_scale(const SkBitmapProcState& s, uint32_t xy[], 186 int count, int x, int y); 187 void ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[], 188 int count, int x, int y); 189 190 // Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space. 191 // Discussion: 192 // Overall, this code takes a point in destination space, and uses the center of the pixel 193 // at (x, y) to determine the sample point in source space. It then adjusts the pixel by different 194 // amounts based in filtering and tiling. 195 // This code can be broken into two main cases based on filtering: 196 // * no filtering (nearest neighbor) - when using nearest neighbor filtering all tile modes reduce 197 // the sampled by one ulp. If a simple point pt lies precisely on XXX.1/2 then it forced down 198 // when positive making 1/2 + 1/2 = .999999 instead of 1.0. 199 // * filtering - in the filtering case, the code calculates the -1/2 shift for starting the 200 // bilerp kernel. There is a twist; there is a big difference between clamp and the other tile 201 // modes. In tile and repeat the matrix has been reduced by an additional 1/width and 1/height 202 // factor. This maps from destination space to [0, 1) (instead of source space) to allow easy 203 // modulo arithmetic. This means that the -1/2 needed by bilerp is actually 1/2 * 1/width for x 204 // and 1/2 * 1/height for y. This is what happens when the poorly named fFilterOne{X|Y} is 205 // divided by two. 206 class SkBitmapProcStateAutoMapper { 207 public: 208 SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y, 209 SkPoint* scalarPoint = nullptr) { 210 SkPoint pt; 211 s.fInvProc(s.fInvMatrix, 212 SkIntToScalar(x) + SK_ScalarHalf, 213 SkIntToScalar(y) + SK_ScalarHalf, &pt); 214 215 SkFixed biasX, biasY; 216 if (s.fFilterQuality == kNone_SkFilterQuality) { 217 // SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded 218 // consistently WRT geometry. Note that we only need the bias for positive scales: 219 // for negative scales, the rounding is intrinsically correct. 220 // We scale it to persist SkFractionalInt -> SkFixed conversions. 221 biasX = (s.fInvMatrix.getScaleX() > 0); 222 biasY = (s.fInvMatrix.getScaleY() > 0); 223 } else { 224 biasX = s.fFilterOneX >> 1; 225 biasY = s.fFilterOneY >> 1; 226 } 227 228 // punt to unsigned for defined underflow behavior 229 fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) - 230 (uint64_t)SkFixedToFractionalInt(biasX)); 231 fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) - 232 (uint64_t)SkFixedToFractionalInt(biasY)); 233 234 if (scalarPoint) { 235 scalarPoint->set(pt.x() - SkFixedToScalar(biasX), 236 pt.y() - SkFixedToScalar(biasY)); 237 } 238 } 239 240 SkFractionalInt fractionalIntX() const { return fX; } 241 SkFractionalInt fractionalIntY() const { return fY; } 242 243 SkFixed fixedX() const { return SkFractionalIntToFixed(fX); } 244 SkFixed fixedY() const { return SkFractionalIntToFixed(fY); } 245 246 int intX() const { return SkFractionalIntToInt(fX); } 247 int intY() const { return SkFractionalIntToInt(fY); } 248 249 private: 250 SkFractionalInt fX, fY; 251 }; 252 253 #endif 254