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/SkColor.h" 12 #include "include/core/SkMatrix.h" 13 #include "include/core/SkPixmap.h" 14 #include "include/core/SkPoint.h" 15 #include "include/core/SkSamplingOptions.h" 16 #include "include/core/SkScalar.h" 17 #include "include/private/base/SkAssert.h" 18 #include "include/private/base/SkCPUTypes.h" 19 #include "include/private/base/SkDebug.h" 20 #include "include/private/base/SkFixed.h" 21 #include "src/base/SkArenaAlloc.h" 22 #include "src/core/SkMatrixPriv.h" 23 24 #include <cstddef> 25 #include <cstdint> 26 27 class SkImage_Base; 28 enum class SkTileMode; 29 30 typedef SkFixed3232 SkFractionalInt; 31 #define SkScalarToFractionalInt(x) SkScalarToFixed3232(x) 32 #define SkFractionalIntToFixed(x) SkFixed3232ToFixed(x) 33 #define SkFixedToFractionalInt(x) SkFixedToFixed3232(x) 34 #define SkFractionalIntToInt(x) SkFixed3232ToInt(x) 35 36 struct SkBitmapProcState { 37 SkBitmapProcState(const SkImage_Base* image, SkTileMode tmx, SkTileMode tmy); 38 setupSkBitmapProcState39 bool setup(const SkMatrix& inv, SkColor color, const SkSamplingOptions& sampling) { 40 return this->init(inv, color, sampling) 41 && this->chooseProcs(); 42 } 43 44 typedef void (*ShaderProc32)(const void* ctx, int x, int y, SkPMColor[], int count); 45 46 typedef void (*MatrixProc)(const SkBitmapProcState&, 47 uint32_t bitmapXY[], 48 int count, 49 int x, int y); 50 51 typedef void (*SampleProc32)(const SkBitmapProcState&, 52 const uint32_t[], 53 int count, 54 SkPMColor colors[]); 55 56 const SkImage_Base* fImage; 57 58 SkPixmap fPixmap; 59 SkMatrix fInvMatrix; // This changes based on tile mode. 60 SkAlpha fPaintAlpha; 61 SkTileMode fTileModeX; 62 SkTileMode fTileModeY; 63 bool fBilerp; 64 65 SkMatrixPriv::MapXYProc fInvProc; // chooseProcs 66 SkFractionalInt fInvSxFractionalInt; 67 SkFractionalInt fInvKyFractionalInt; 68 69 SkFixed fFilterOneX; 70 SkFixed fFilterOneY; 71 72 uint16_t fAlphaScale; // chooseProcs 73 74 /** Given the byte size of the index buffer to be passed to the matrix proc, 75 return the maximum number of resulting pixels that can be computed 76 (i.e. the number of SkPMColor values to be written by the sample proc). 77 This routine takes into account that filtering and scale-vs-affine 78 affect the amount of buffer space needed. 79 80 Only valid to call after chooseProcs (setContext) has been called. It is 81 safe to call this inside the shader's shadeSpan() method. 82 */ 83 int maxCountForBufferSize(size_t bufferSize) const; 84 85 // If a shader proc is present, then the corresponding matrix/sample procs 86 // are ignored getShaderProc32SkBitmapProcState87 ShaderProc32 getShaderProc32() const { return fShaderProc32; } 88 89 #ifdef SK_DEBUG 90 MatrixProc getMatrixProc() const; 91 #else getMatrixProcSkBitmapProcState92 MatrixProc getMatrixProc() const { return fMatrixProc; } 93 #endif getSampleProc32SkBitmapProcState94 SampleProc32 getSampleProc32() const { return fSampleProc32; } 95 96 private: 97 enum { 98 kBMStateSize = 136 // found by inspection. if too small, we will call new/delete 99 }; 100 SkSTArenaAlloc<kBMStateSize> fAlloc; 101 102 ShaderProc32 fShaderProc32; // chooseProcs 103 // These are used if the shaderproc is nullptr 104 MatrixProc fMatrixProc; // chooseProcs 105 SampleProc32 fSampleProc32; // chooseProcs 106 107 bool init(const SkMatrix& inverse, SkAlpha, const SkSamplingOptions&); 108 bool chooseProcs(); 109 MatrixProc chooseMatrixProc(bool trivial_matrix); 110 ShaderProc32 chooseShaderProc32(); 111 112 // Return false if we failed to setup for fast translate (e.g. overflow) 113 bool setupForTranslate(); 114 115 #ifdef SK_DEBUG 116 static void DebugMatrixProc(const SkBitmapProcState&, 117 uint32_t[], int count, int x, int y); 118 #endif 119 }; 120 121 /* Macros for packing and unpacking pairs of 16bit values in a 32bit uint. 122 Used to allow access to a stream of uint16_t either one at a time, or 123 2 at a time by unpacking a uint32_t 124 */ 125 #ifdef SK_CPU_BENDIAN 126 #define PACK_TWO_SHORTS(pri, sec) ((pri) << 16 | (sec)) 127 #define UNPACK_PRIMARY_SHORT(packed) ((uint32_t)(packed) >> 16) 128 #define UNPACK_SECONDARY_SHORT(packed) ((packed) & 0xFFFF) 129 #else 130 #define PACK_TWO_SHORTS(pri, sec) ((pri) | ((sec) << 16)) 131 #define UNPACK_PRIMARY_SHORT(packed) ((packed) & 0xFFFF) 132 #define UNPACK_SECONDARY_SHORT(packed) ((uint32_t)(packed) >> 16) 133 #endif 134 135 #ifdef SK_DEBUG pack_two_shorts(U16CPU pri,U16CPU sec)136 static inline uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) { 137 SkASSERT((uint16_t)pri == pri); 138 SkASSERT((uint16_t)sec == sec); 139 return PACK_TWO_SHORTS(pri, sec); 140 } 141 #else 142 #define pack_two_shorts(pri, sec) PACK_TWO_SHORTS(pri, sec) 143 #endif 144 145 // Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space. 146 // Discussion: 147 // Overall, this code takes a point in destination space, and uses the center of the pixel 148 // at (x, y) to determine the sample point in source space. It then adjusts the pixel by different 149 // amounts based in filtering and tiling. 150 // This code can be broken into two main cases based on filtering: 151 // * no filtering (nearest neighbor) - when using nearest neighbor filtering all tile modes reduce 152 // the sampled by one ulp. If a simple point pt lies precisely on XXX.1/2 then it forced down 153 // when positive making 1/2 + 1/2 = .999999 instead of 1.0. 154 // * filtering - in the filtering case, the code calculates the -1/2 shift for starting the 155 // bilerp kernel. There is a twist; there is a big difference between clamp and the other tile 156 // modes. In tile and repeat the matrix has been reduced by an additional 1/width and 1/height 157 // factor. This maps from destination space to [0, 1) (instead of source space) to allow easy 158 // modulo arithmetic. This means that the -1/2 needed by bilerp is actually 1/2 * 1/width for x 159 // and 1/2 * 1/height for y. This is what happens when the poorly named fFilterOne{X|Y} is 160 // divided by two. 161 class SkBitmapProcStateAutoMapper { 162 public: 163 SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y, 164 SkPoint* scalarPoint = nullptr) { 165 SkPoint pt; 166 s.fInvProc(s.fInvMatrix, 167 SkIntToScalar(x) + SK_ScalarHalf, 168 SkIntToScalar(y) + SK_ScalarHalf, &pt); 169 170 SkFixed biasX = 0, biasY = 0; 171 if (s.fBilerp) { 172 biasX = s.fFilterOneX >> 1; 173 biasY = s.fFilterOneY >> 1; 174 } else { 175 // Our rasterizer biases upward. That is a rect from 0.5...1.5 fills pixel 1 and not 176 // pixel 0. To make an image that is mapped 1:1 with device pixels but at a half pixel 177 // offset select every pixel from the src image once we make exact integer pixel sample 178 // values round down not up. Note that a mirror mapping will not have this property. 179 biasX = 1; 180 biasY = 1; 181 } 182 183 // punt to unsigned for defined underflow behavior 184 fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) - 185 (uint64_t)SkFixedToFractionalInt(biasX)); 186 fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) - 187 (uint64_t)SkFixedToFractionalInt(biasY)); 188 189 if (scalarPoint) { 190 scalarPoint->set(pt.x() - SkFixedToScalar(biasX), 191 pt.y() - SkFixedToScalar(biasY)); 192 } 193 } 194 fractionalIntX()195 SkFractionalInt fractionalIntX() const { return fX; } fractionalIntY()196 SkFractionalInt fractionalIntY() const { return fY; } 197 fixedX()198 SkFixed fixedX() const { return SkFractionalIntToFixed(fX); } fixedY()199 SkFixed fixedY() const { return SkFractionalIntToFixed(fY); } 200 intX()201 int intX() const { return SkFractionalIntToInt(fX); } intY()202 int intY() const { return SkFractionalIntToInt(fY); } 203 204 private: 205 SkFractionalInt fX, fY; 206 }; 207 208 namespace sktests { 209 // f is the value to pack, max is the largest the value can be. 210 uint32_t pack_clamp(SkFixed f, unsigned max); 211 // As above, but width is the width of the pretend bitmap. 212 uint32_t pack_repeat(SkFixed f, unsigned max, size_t width); 213 uint32_t pack_mirror(SkFixed f, unsigned max, size_t width); 214 } 215 216 namespace SkOpts { 217 // SkBitmapProcState optimized Shader, Sample, or Matrix procs. 218 extern void (*S32_alpha_D32_filter_DX)(const SkBitmapProcState&, 219 const uint32_t* xy, int count, SkPMColor*); 220 extern void (*S32_alpha_D32_filter_DXDY)(const SkBitmapProcState&, 221 const uint32_t* xy, int count, SkPMColor*); 222 223 void Init_BitmapProcState(); 224 } // namespace SkOpts 225 226 #endif 227