| 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 |  | 
|---|