blob: 00fb160aba2d758bd3c2ea23cb36e916b724e3c1 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#ifndef SkBitmapProcState_DEFINED
9#define SkBitmapProcState_DEFINED
10
11#include "SkBitmap.h"
reed64045422015-06-04 06:31:31 -070012#include "SkBitmapController.h"
reed013e9e32015-09-15 14:46:27 -070013#include "SkBitmapProvider.h"
Mike Reede32500f2017-07-19 17:20:37 -040014#include "SkFixed.h"
fmalitaaed4d322015-12-15 06:48:48 -080015#include "SkFloatBits.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkMatrix.h"
reed680fb9e2014-08-26 09:08:04 -070017#include "SkMipMap.h"
reed@google.comcee9dcb2013-09-13 16:04:49 +000018#include "SkPaint.h"
reed013e9e32015-09-15 14:46:27 -070019#include "SkShader.h"
bungemanf3c15b72015-08-19 11:56:48 -070020#include "SkTemplates.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
mtklein17946512014-11-21 12:10:33 -080022typedef 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)
reed@google.com4bc0a9d2012-03-07 21:47:41 +000027
reed@android.com8a1c16f2008-12-17 15:59:43 +000028class SkPaint;
29
reed05a56472016-03-02 09:49:02 -080030struct SkBitmapProcInfo {
Brian Osman13bf6222016-12-06 10:34:51 -050031 SkBitmapProcInfo(const SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy);
reed05a56472016-03-02 09:49:02 -080032 ~SkBitmapProcInfo();
33
Brian Osman7b8400d2016-11-08 17:08:54 -050034 const SkBitmapProvider fProvider;
reed05a56472016-03-02 09:49:02 -080035
Brian Osman7b8400d2016-11-08 17:08:54 -050036 SkPixmap fPixmap;
37 SkMatrix fInvMatrix; // This changes based on tile mode.
herb6eff52a2016-03-23 09:00:33 -070038 // TODO: combine fInvMatrix and fRealInvMatrix.
Brian Osman7b8400d2016-11-08 17:08:54 -050039 SkMatrix fRealInvMatrix; // The actual inverse matrix.
40 SkColor fPaintColor;
41 SkShader::TileMode fTileModeX;
42 SkShader::TileMode fTileModeY;
43 SkFilterQuality fFilterQuality;
44 SkMatrix::TypeMask fInvType;
reed05a56472016-03-02 09:49:02 -080045
46 bool init(const SkMatrix& inverse, const SkPaint&);
47
48private:
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
56struct SkBitmapProcState : public SkBitmapProcInfo {
Brian Osman13bf6222016-12-06 10:34:51 -050057 SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy)
58 : SkBitmapProcInfo(prov, tmx, tmy) {}
reed05a56472016-03-02 09:49:02 -080059
60 bool setup(const SkMatrix& inv, const SkPaint& paint) {
61 return this->init(inv, paint) && this->chooseProcs();
62 }
reed64045422015-06-04 06:31:31 -070063
herbc7a784c2015-12-18 09:52:15 -080064 typedef void (*ShaderProc32)(const void* ctx, int x, int y, SkPMColor[], int count);
reed@android.com7a99eb12009-07-16 01:13:14 +000065
herbc7a784c2015-12-18 09:52:15 -080066 typedef void (*ShaderProc16)(const void* ctx, int x, int y, uint16_t[], int count);
reed@android.com7a99eb12009-07-16 01:13:14 +000067
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 typedef void (*MatrixProc)(const SkBitmapProcState&,
69 uint32_t bitmapXY[],
70 int count,
71 int x, int y);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 typedef void (*SampleProc32)(const SkBitmapProcState&,
74 const uint32_t[],
75 int count,
76 SkPMColor colors[]);
77
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF
reed@android.com07d1f002009-08-13 19:35:48 +000079 typedef U16CPU (*IntTileProc)(int value, int count); // returns 0..count-1
reed@android.com7a99eb12009-07-16 01:13:14 +000080
reed@android.comeef375b2009-08-03 14:45:45 +000081 SkMatrix::MapXYProc fInvProc; // chooseProcs
reed@google.com4bc0a9d2012-03-07 21:47:41 +000082 SkFractionalInt fInvSxFractionalInt;
reed@google.com411215a2012-03-08 20:13:46 +000083 SkFractionalInt fInvKyFractionalInt;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000084
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 FixedTileProc fTileProcX; // chooseProcs
86 FixedTileProc fTileProcY; // chooseProcs
reed@android.com07d1f002009-08-13 19:35:48 +000087 IntTileProc fIntTileProcY; // chooseProcs
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 SkFixed fFilterOneX;
89 SkFixed fFilterOneY;
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +000090
reed@android.comeef375b2009-08-03 14:45:45 +000091 SkFixed fInvSx; // chooseProcs
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 SkFixed fInvKy; // chooseProcs
reed05a56472016-03-02 09:49:02 -080093 SkPMColor fPaintPMColor; // chooseProcs - A8 config
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 uint16_t fAlphaScale; // chooseProcs
humper@google.com9c96d4b2013-07-14 01:44:59 +000095
reed@android.comc9a1d4b2009-08-03 15:05:55 +000096 /** 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();
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +0000110
reed@android.com258cb222010-04-14 13:36:33 +0000111 /** 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.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000116
reed@android.com4c128c42009-08-14 13:54:37 +0000117 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
reed@google.com9fe287b2012-03-27 15:54:28 +0000122 // If a shader proc is present, then the corresponding matrix/sample procs
123 // are ignored
124 ShaderProc32 getShaderProc32() const { return fShaderProc32; }
125 ShaderProc16 getShaderProc16() const { return fShaderProc16; }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000126
reed@google.com9fe287b2012-03-27 15:54:28 +0000127#ifdef SK_DEBUG
128 MatrixProc getMatrixProc() const;
129#else
130 MatrixProc getMatrixProc() const { return fMatrixProc; }
131#endif
132 SampleProc32 getSampleProc32() const { return fSampleProc32; }
reed@google.com9fe287b2012-03-27 15:54:28 +0000133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134private:
reed@google.com9fe287b2012-03-27 15:54:28 +0000135 ShaderProc32 fShaderProc32; // chooseProcs
136 ShaderProc16 fShaderProc16; // chooseProcs
halcanary96fcdcc2015-08-27 07:41:13 -0700137 // These are used if the shaderproc is nullptr
reed@google.com9fe287b2012-03-27 15:54:28 +0000138 MatrixProc fMatrixProc; // chooseProcs
139 SampleProc32 fSampleProc32; // chooseProcs
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000140
reed@android.com07d1f002009-08-13 19:35:48 +0000141 MatrixProc chooseMatrixProc(bool trivial_matrix);
reed05a56472016-03-02 09:49:02 -0800142 bool chooseProcs(); // caller must have called init() first (on our base-class)
143 bool chooseScanlineProcs(bool trivialMatrix, bool clampClamp);
reed@google.com9a4c7462012-10-12 18:21:37 +0000144 ShaderProc32 chooseShaderProc32();
skia.committer@gmail.comfa1bd5f2013-07-13 07:00:56 +0000145
reed@google.com6bb92bc2012-11-20 19:45:16 +0000146 // Return false if we failed to setup for fast translate (e.g. overflow)
147 bool setupForTranslate();
reed@google.com9fe287b2012-03-27 15:54:28 +0000148
149#ifdef SK_DEBUG
150 static void DebugMatrixProc(const SkBitmapProcState&,
151 uint32_t[], int count, int x, int y);
152#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153};
154
reed@android.com07d1f002009-08-13 19:35:48 +0000155/* 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
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
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000179// These functions are generated via macros, but are exposed here so that
180// platformProcs may test for them by name.
181void S32_opaque_D32_filter_DX(const SkBitmapProcState& s, const uint32_t xy[],
182 int count, SkPMColor colors[]);
senorblanco@chromium.orgf3f0bd72009-12-10 22:46:31 +0000183void S32_alpha_D32_filter_DX(const SkBitmapProcState& s, const uint32_t xy[],
184 int count, SkPMColor colors[]);
tomhudson@google.com06a73132012-02-22 18:30:43 +0000185void ClampX_ClampY_filter_scale(const SkBitmapProcState& s, uint32_t xy[],
186 int count, int x, int y);
187void ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[],
188 int count, int x, int y);
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000189
fmalitab3a83582016-01-04 10:28:11 -0800190// Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space.
herb5c473be2016-03-19 08:46:24 -0700191// Discussion:
192// Overall, this code takes a point in destination space, and uses the center of the pixel
193// at (x, y) to determine the sample point in source space. It then adjusts the pixel by different
194// amounts based in filtering and tiling.
195// This code can be broken into two main cases based on filtering:
196// * no filtering (nearest neighbor) - when using nearest neighbor filtering all tile modes reduce
197// the sampled by one ulp. If a simple point pt lies precisely on XXX.1/2 then it forced down
198// when positive making 1/2 + 1/2 = .999999 instead of 1.0.
199// * filtering - in the filtering case, the code calculates the -1/2 shift for starting the
200// bilerp kernel. There is a twist; there is a big difference between clamp and the other tile
201// modes. In tile and repeat the matrix has been reduced by an additional 1/width and 1/height
202// factor. This maps from destination space to [0, 1) (instead of source space) to allow easy
203// modulo arithmetic. This means that the -1/2 needed by bilerp is actually 1/2 * 1/width for x
204// and 1/2 * 1/height for y. This is what happens when the poorly named fFilterOne{X|Y} is
205// divided by two.
fmalitab3a83582016-01-04 10:28:11 -0800206class SkBitmapProcStateAutoMapper {
207public:
fmalita8a8eb522016-01-30 18:56:34 -0800208 SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y,
209 SkPoint* scalarPoint = nullptr) {
fmalitab3a83582016-01-04 10:28:11 -0800210 SkPoint pt;
211 s.fInvProc(s.fInvMatrix,
212 SkIntToScalar(x) + SK_ScalarHalf,
213 SkIntToScalar(y) + SK_ScalarHalf, &pt);
214
fmalita2404f032016-02-03 05:44:21 -0800215 SkFixed biasX, biasY;
reed05a56472016-03-02 09:49:02 -0800216 if (s.fFilterQuality == kNone_SkFilterQuality) {
fmalita2404f032016-02-03 05:44:21 -0800217 // SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded
218 // consistently WRT geometry. Note that we only need the bias for positive scales:
219 // for negative scales, the rounding is intrinsically correct.
220 // We scale it to persist SkFractionalInt -> SkFixed conversions.
221 biasX = (s.fInvMatrix.getScaleX() > 0);
222 biasY = (s.fInvMatrix.getScaleY() > 0);
223 } else {
224 biasX = s.fFilterOneX >> 1;
225 biasY = s.fFilterOneY >> 1;
226 }
227
Florin Malita9d1cc662016-12-12 15:43:51 -0500228 // punt to unsigned for defined underflow behavior
229 fX = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.x()) -
230 (uint64_t)SkFixedToFractionalInt(biasX));
231 fY = (SkFractionalInt)((uint64_t)SkScalarToFractionalInt(pt.y()) -
232 (uint64_t)SkFixedToFractionalInt(biasY));
fmalita653c12d2016-01-30 10:06:46 -0800233
fmalita8a8eb522016-01-30 18:56:34 -0800234 if (scalarPoint) {
235 scalarPoint->set(pt.x() - SkFixedToScalar(biasX),
236 pt.y() - SkFixedToScalar(biasY));
237 }
fmalitab3a83582016-01-04 10:28:11 -0800238 }
239
fmalitabe5cfa92016-02-03 10:21:33 -0800240 SkFractionalInt fractionalIntX() const { return fX; }
241 SkFractionalInt fractionalIntY() const { return fY; }
242
243 SkFixed fixedX() const { return SkFractionalIntToFixed(fX); }
244 SkFixed fixedY() const { return SkFractionalIntToFixed(fY); }
245
246 int intX() const { return SkFractionalIntToInt(fX); }
247 int intY() const { return SkFractionalIntToInt(fY); }
fmalitab3a83582016-01-04 10:28:11 -0800248
249private:
250 SkFractionalInt fX, fY;
251};
252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253#endif