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