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