blob: e0d281b026fae38118acdaf958fff7f61f930a2c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
bungemanf3c15b72015-08-19 11:56:48 -07007
8#include "SkBitmapProcShader.h"
9#include "SkBitmapProcState.h"
reed013e9e32015-09-15 14:46:27 -070010#include "SkBitmapProvider.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011
reed05a56472016-03-02 09:49:02 -080012static bool only_scale_and_translate(const SkMatrix& matrix) {
13 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
14 return (matrix.getType() & ~mask) == 0;
15}
16
17class BitmapProcInfoContext : public SkShader::Context {
18public:
reedd8829012016-03-04 11:07:43 -080019 // The info has been allocated elsewhere, but we are responsible for calling its destructor.
reed05a56472016-03-02 09:49:02 -080020 BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec,
21 SkBitmapProcInfo* info)
22 : INHERITED(shader, rec)
23 , fInfo(info)
24 {
25 fFlags = 0;
26 if (fInfo->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
27 fFlags |= SkShader::kOpaqueAlpha_Flag;
28 }
29
30 if (1 == fInfo->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
31 fFlags |= SkShader::kConstInY32_Flag;
32 }
33 }
34
35 ~BitmapProcInfoContext() override {
reed05a56472016-03-02 09:49:02 -080036 fInfo->~SkBitmapProcInfo();
37 }
herb6eff52a2016-03-23 09:00:33 -070038
reed05a56472016-03-02 09:49:02 -080039 uint32_t getFlags() const override { return fFlags; }
40
41private:
42 SkBitmapProcInfo* fInfo;
43 uint32_t fFlags;
44
45 typedef SkShader::Context INHERITED;
46};
47
48///////////////////////////////////////////////////////////////////////////////////////////////////
49
50class BitmapProcShaderContext : public BitmapProcInfoContext {
51public:
reed05a56472016-03-02 09:49:02 -080052 BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec,
53 SkBitmapProcState* state)
54 : INHERITED(shader, rec, state)
55 , fState(state)
56 {}
57
58 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
59 const SkBitmapProcState& state = *fState;
60 if (state.getShaderProc32()) {
61 state.getShaderProc32()(&state, x, y, dstC, count);
62 return;
63 }
64
65 const int BUF_MAX = 128;
66 uint32_t buffer[BUF_MAX];
67 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
68 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
69 const int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
70
71 SkASSERT(state.fPixmap.addr());
72
73 for (;;) {
74 int n = SkTMin(count, max);
75 SkASSERT(n > 0 && n < BUF_MAX*2);
76 mproc(state, buffer, n, x, y);
77 sproc(state, buffer, n, dstC);
78
79 if ((count -= n) == 0) {
80 break;
81 }
82 SkASSERT(count > 0);
83 x += n;
84 dstC += n;
85 }
86 }
87
88 ShadeProc asAShadeProc(void** ctx) override {
89 if (fState->getShaderProc32()) {
90 *ctx = fState;
91 return (ShadeProc)fState->getShaderProc32();
92 }
93 return nullptr;
94 }
95
96private:
97 SkBitmapProcState* fState;
98
99 typedef BitmapProcInfoContext INHERITED;
100};
101
102///////////////////////////////////////////////////////////////////////////////////////////////////
reedd8829012016-03-04 11:07:43 -0800103#include "SkLinearBitmapPipeline.h"
104#include "SkPM4f.h"
105#include "SkXfermode.h"
reed05a56472016-03-02 09:49:02 -0800106
reedd8829012016-03-04 11:07:43 -0800107class LinearPipelineContext : public BitmapProcInfoContext {
108public:
109 LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec,
110 SkBitmapProcInfo* info)
111 : INHERITED(shader, rec, info)
112 {
herb69076fe2016-04-12 14:07:59 -0700113 // Save things off in case we need to build a blitter pipeline.
114 fSrcPixmap = info->fPixmap;
115 fAlpha = SkColorGetA(info->fPaintColor) / 255.0f;
116 fXMode = info->fTileModeX;
117 fYMode = info->fTileModeY;
118 fFilterQuality = info->fFilterQuality;
119 fMatrixTypeMask = info->fRealInvMatrix.getType();
120
herb57a69dc2016-05-19 14:19:23 -0700121 fShaderPipeline.init(
122 info->fRealInvMatrix, info->fFilterQuality,
123 info->fTileModeX, info->fTileModeY,
124 info->fPaintColor,
125 info->fPixmap);
reedd8829012016-03-04 11:07:43 -0800126
127 // To implement the old shadeSpan entry-point, we need to efficiently convert our native
128 // floats into SkPMColor. The SkXfermode::D32Procs do exactly that.
129 //
reedcfb6bdf2016-03-29 11:32:50 -0700130 sk_sp<SkXfermode> xfer(SkXfermode::Make(SkXfermode::kSrc_Mode));
reedd8829012016-03-04 11:07:43 -0800131 fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0);
132 }
133
reedd8829012016-03-04 11:07:43 -0800134 void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override {
herb69076fe2016-04-12 14:07:59 -0700135 fShaderPipeline->shadeSpan4f(x, y, dstC, count);
reedd8829012016-03-04 11:07:43 -0800136 }
137
138 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
139 const int N = 128;
140 SkPM4f tmp[N];
141
142 while (count > 0) {
143 const int n = SkTMin(count, N);
herb69076fe2016-04-12 14:07:59 -0700144 fShaderPipeline->shadeSpan4f(x, y, tmp, n);
reedd8829012016-03-04 11:07:43 -0800145 fXferProc(nullptr, dstC, tmp, n, nullptr);
146 dstC += n;
147 x += n;
148 count -= n;
149 }
150 }
151
herb69076fe2016-04-12 14:07:59 -0700152 bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override {
153 SkXfermode::Mode mode;
154 if (!SkXfermode::AsMode(state->fXfer, &mode)) { return false; }
155
herb69076fe2016-04-12 14:07:59 -0700156 if (SkLinearBitmapPipeline::ClonePipelineForBlitting(
herb57a69dc2016-05-19 14:19:23 -0700157 &fBlitterPipeline, *fShaderPipeline,
herb69076fe2016-04-12 14:07:59 -0700158 fMatrixTypeMask,
159 fXMode, fYMode,
160 fFilterQuality, fSrcPixmap,
herb9f666a12016-04-25 09:05:14 -0700161 fAlpha, mode, dstInfo))
162 {
herb57a69dc2016-05-19 14:19:23 -0700163 state->fStorage[0] = fBlitterPipeline.get();
herb69076fe2016-04-12 14:07:59 -0700164 state->fBlitBW = &LinearPipelineContext::ForwardToPipeline;
165
166 return true;
167 }
168
herb69076fe2016-04-12 14:07:59 -0700169 return false;
170 }
171
172 static void ForwardToPipeline(BlitState* state, int x, int y, const SkPixmap& dst, int count) {
173 SkLinearBitmapPipeline* pipeline = static_cast<SkLinearBitmapPipeline*>(state->fStorage[0]);
174 void* addr = dst.writable_addr32(x, y);
175 pipeline->blitSpan(x, y, addr, count);
176 }
177
reedd8829012016-03-04 11:07:43 -0800178private:
herb57a69dc2016-05-19 14:19:23 -0700179 SkEmbeddableLinearPipeline fShaderPipeline;
180 SkEmbeddableLinearPipeline fBlitterPipeline;
181 SkXfermode::D32Proc fXferProc;
182 SkPixmap fSrcPixmap;
183 float fAlpha;
184 SkShader::TileMode fXMode;
185 SkShader::TileMode fYMode;
186 SkMatrix::TypeMask fMatrixTypeMask;
187 SkFilterQuality fFilterQuality;
reedd8829012016-03-04 11:07:43 -0800188
189 typedef BitmapProcInfoContext INHERITED;
190};
191
192///////////////////////////////////////////////////////////////////////////////////////////////////
193
194static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) {
reedd8829012016-03-04 11:07:43 -0800195 // If we get here, we can reasonably use either context, respect the caller's preference
196 //
herba4e4b792016-06-04 13:27:10 -0700197 bool needsPremul = srcInfo.alphaType() == kUnpremul_SkAlphaType;
198 bool needsSwizzle = srcInfo.bytesPerPixel() == 4 && srcInfo.colorType() != kN32_SkColorType;
199 return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType
200 || needsPremul || needsSwizzle;
reedd8829012016-03-04 11:07:43 -0800201}
202
reed320a40d2016-08-02 06:12:06 -0700203size_t SkBitmapProcLegacyShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) {
reedd8829012016-03-04 11:07:43 -0800204 size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
205 size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo);
reed320a40d2016-08-02 06:12:06 -0700206 size_t s = SkTMax(size0, size1);
207 return s;
reedd8829012016-03-04 11:07:43 -0800208 return SkTMax(size0, size1);
reed7a4d8472015-09-15 13:33:58 -0700209}
210
reed320a40d2016-08-02 06:12:06 -0700211SkShader::Context* SkBitmapProcLegacyShader::MakeContext(const SkShader& shader,
reed05a56472016-03-02 09:49:02 -0800212 TileMode tmx, TileMode tmy,
213 const SkBitmapProvider& provider,
214 const ContextRec& rec, void* storage) {
215 SkMatrix totalInverse;
216 // Do this first, so we know the matrix can be inverted.
217 if (!shader.computeTotalInverse(rec, &totalInverse)) {
218 return nullptr;
219 }
220
herb6eff52a2016-03-23 09:00:33 -0700221 // Decide if we can/want to use the new linear pipeline
reedd8829012016-03-04 11:07:43 -0800222 bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());
reed6644d932016-06-10 11:41:47 -0700223 SkSourceGammaTreatment treatment = SkMipMap::DeduceTreatment(rec);
reedcd660e12016-03-03 09:36:50 -0800224
reedd8829012016-03-04 11:07:43 -0800225 if (useLinearPipeline) {
226 void* infoStorage = (char*)storage + sizeof(LinearPipelineContext);
reed6644d932016-06-10 11:41:47 -0700227 SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy, treatment);
reedd8829012016-03-04 11:07:43 -0800228 if (!info->init(totalInverse, *rec.fPaint)) {
229 info->~SkBitmapProcInfo();
230 return nullptr;
231 }
herb670f01f2016-05-13 10:04:46 -0700232
reedd8829012016-03-04 11:07:43 -0800233 return new (storage) LinearPipelineContext(shader, rec, info);
234 } else {
235 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
reed6644d932016-06-10 11:41:47 -0700236 SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy,
237 treatment);
reedd8829012016-03-04 11:07:43 -0800238 if (!state->setup(totalInverse, *rec.fPaint)) {
239 state->~SkBitmapProcState();
240 return nullptr;
241 }
242 return new (storage) BitmapProcShaderContext(shader, rec, state);
243 }
reed05a56472016-03-02 09:49:02 -0800244}