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 struct SkBitmapProcState : public SkBitmapProcInfo { SkBitmapProcStateSkBitmapProcState57 SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy) 58 : SkBitmapProcInfo(prov, tmx, tmy) {} 59 setupSkBitmapProcState60 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 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 getShaderProc32SkBitmapProcState124 ShaderProc32 getShaderProc32() const { return fShaderProc32; } getShaderProc16SkBitmapProcState125 ShaderProc16 getShaderProc16() const { return fShaderProc16; } 126 127 #ifdef SK_DEBUG 128 MatrixProc getMatrixProc() const; 129 #else getMatrixProcSkBitmapProcState130 MatrixProc getMatrixProc() const { return fMatrixProc; } 131 #endif getSampleProc32SkBitmapProcState132 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 pack_two_shorts(U16CPU pri,U16CPU sec)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 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 SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y, 217 SkPoint* scalarPoint = nullptr) { 218 SkPoint pt; 219 s.fInvProc(s.fInvMatrix, 220 SkIntToScalar(x) + SK_ScalarHalf, 221 SkIntToScalar(y) + SK_ScalarHalf, &pt); 222 223 SkFixed biasX, biasY; 224 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 biasX = (s.fInvMatrix.getScaleX() > 0); 230 biasY = (s.fInvMatrix.getScaleY() > 0); 231 } else { 232 biasX = s.fFilterOneX >> 1; 233 biasY = s.fFilterOneY >> 1; 234 } 235 236 // punt to unsigned for defined underflow behavior 237 fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) - 238 (uint64_t)SkFixedToFractionalInt(biasX)); 239 fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) - 240 (uint64_t)SkFixedToFractionalInt(biasY)); 241 242 if (scalarPoint) { 243 scalarPoint->set(pt.x() - SkFixedToScalar(biasX), 244 pt.y() - SkFixedToScalar(biasY)); 245 } 246 } 247 fractionalIntX()248 SkFractionalInt fractionalIntX() const { return fX; } fractionalIntY()249 SkFractionalInt fractionalIntY() const { return fY; } 250 fixedX()251 SkFixed fixedX() const { return SkFractionalIntToFixed(fX); } fixedY()252 SkFixed fixedY() const { return SkFractionalIntToFixed(fY); } 253 intX()254 int intX() const { return SkFractionalIntToInt(fX); } intY()255 int intY() const { return SkFractionalIntToInt(fY); } 256 257 private: 258 SkFractionalInt fX, fY; 259 }; 260 261 #endif 262