blob: 3727bbca864993bb537b5f607119cb945f66c059 [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#include "SkColorPriv.h"
bungemanf3c15b72015-08-19 11:56:48 -070012#include "SkErrorInternals.h"
13#include "SkPixelRef.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
15#include "SkWriteBuffer.h"
humper@google.com3aad3b02013-09-04 19:23:53 +000016
humper@google.com30df03c2013-09-04 19:57:11 +000017#if SK_SUPPORT_GPU
bsalomonf276ac52015-10-09 13:36:42 -070018#include "SkGrPriv.h"
humper@google.com3aad3b02013-09-04 19:23:53 +000019#include "effects/GrBicubicEffect.h"
bungemanf3c15b72015-08-19 11:56:48 -070020#include "effects/GrSimpleTextureEffect.h"
humper@google.com30df03c2013-09-04 19:57:11 +000021#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
reed05a56472016-03-02 09:49:02 -080023static bool only_scale_and_translate(const SkMatrix& matrix) {
24 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
25 return (matrix.getType() & ~mask) == 0;
26}
27
28class BitmapProcInfoContext : public SkShader::Context {
29public:
reedd8829012016-03-04 11:07:43 -080030 // The info has been allocated elsewhere, but we are responsible for calling its destructor.
reed05a56472016-03-02 09:49:02 -080031 BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec,
32 SkBitmapProcInfo* info)
33 : INHERITED(shader, rec)
34 , fInfo(info)
35 {
36 fFlags = 0;
37 if (fInfo->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
38 fFlags |= SkShader::kOpaqueAlpha_Flag;
39 }
40
41 if (1 == fInfo->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
42 fFlags |= SkShader::kConstInY32_Flag;
43 }
44 }
45
46 ~BitmapProcInfoContext() override {
reed05a56472016-03-02 09:49:02 -080047 fInfo->~SkBitmapProcInfo();
48 }
herb6eff52a2016-03-23 09:00:33 -070049
reed05a56472016-03-02 09:49:02 -080050 uint32_t getFlags() const override { return fFlags; }
51
52private:
53 SkBitmapProcInfo* fInfo;
54 uint32_t fFlags;
55
56 typedef SkShader::Context INHERITED;
57};
58
59///////////////////////////////////////////////////////////////////////////////////////////////////
60
61class BitmapProcShaderContext : public BitmapProcInfoContext {
62public:
reed05a56472016-03-02 09:49:02 -080063 BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec,
64 SkBitmapProcState* state)
65 : INHERITED(shader, rec, state)
66 , fState(state)
67 {}
68
69 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
70 const SkBitmapProcState& state = *fState;
71 if (state.getShaderProc32()) {
72 state.getShaderProc32()(&state, x, y, dstC, count);
73 return;
74 }
75
76 const int BUF_MAX = 128;
77 uint32_t buffer[BUF_MAX];
78 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
79 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
80 const int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
81
82 SkASSERT(state.fPixmap.addr());
83
84 for (;;) {
85 int n = SkTMin(count, max);
86 SkASSERT(n > 0 && n < BUF_MAX*2);
87 mproc(state, buffer, n, x, y);
88 sproc(state, buffer, n, dstC);
89
90 if ((count -= n) == 0) {
91 break;
92 }
93 SkASSERT(count > 0);
94 x += n;
95 dstC += n;
96 }
97 }
98
99 ShadeProc asAShadeProc(void** ctx) override {
100 if (fState->getShaderProc32()) {
101 *ctx = fState;
102 return (ShadeProc)fState->getShaderProc32();
103 }
104 return nullptr;
105 }
106
107private:
108 SkBitmapProcState* fState;
109
110 typedef BitmapProcInfoContext INHERITED;
111};
112
113///////////////////////////////////////////////////////////////////////////////////////////////////
reedd8829012016-03-04 11:07:43 -0800114#include "SkLinearBitmapPipeline.h"
115#include "SkPM4f.h"
116#include "SkXfermode.h"
reed05a56472016-03-02 09:49:02 -0800117
reedd8829012016-03-04 11:07:43 -0800118class LinearPipelineContext : public BitmapProcInfoContext {
119public:
120 LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec,
121 SkBitmapProcInfo* info)
122 : INHERITED(shader, rec, info)
123 {
herb69076fe2016-04-12 14:07:59 -0700124 // Save things off in case we need to build a blitter pipeline.
125 fSrcPixmap = info->fPixmap;
126 fAlpha = SkColorGetA(info->fPaintColor) / 255.0f;
127 fXMode = info->fTileModeX;
128 fYMode = info->fTileModeY;
129 fFilterQuality = info->fFilterQuality;
130 fMatrixTypeMask = info->fRealInvMatrix.getType();
131
reedd8829012016-03-04 11:07:43 -0800132 // Need to ensure that our pipeline is created at a 16byte aligned address
herb69076fe2016-04-12 14:07:59 -0700133 fShaderPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fShaderStorage);
134 new (fShaderPipeline) SkLinearBitmapPipeline(info->fRealInvMatrix, info->fFilterQuality,
reedd8829012016-03-04 11:07:43 -0800135 info->fTileModeX, info->fTileModeY,
herb69076fe2016-04-12 14:07:59 -0700136 fAlpha,
reedd8829012016-03-04 11:07:43 -0800137 info->fPixmap);
138
139 // To implement the old shadeSpan entry-point, we need to efficiently convert our native
140 // floats into SkPMColor. The SkXfermode::D32Procs do exactly that.
141 //
reedcfb6bdf2016-03-29 11:32:50 -0700142 sk_sp<SkXfermode> xfer(SkXfermode::Make(SkXfermode::kSrc_Mode));
reedd8829012016-03-04 11:07:43 -0800143 fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0);
144 }
145
146 ~LinearPipelineContext() override {
147 // since we did a manual new, we need to manually destroy as well.
herb69076fe2016-04-12 14:07:59 -0700148 fShaderPipeline->~SkLinearBitmapPipeline();
149 if (fBlitterPipeline != nullptr) {
150 fBlitterPipeline->~SkLinearBitmapPipeline();
151 }
reedd8829012016-03-04 11:07:43 -0800152 }
153
154 void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override {
herb69076fe2016-04-12 14:07:59 -0700155 fShaderPipeline->shadeSpan4f(x, y, dstC, count);
reedd8829012016-03-04 11:07:43 -0800156 }
157
158 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
159 const int N = 128;
160 SkPM4f tmp[N];
161
162 while (count > 0) {
163 const int n = SkTMin(count, N);
herb69076fe2016-04-12 14:07:59 -0700164 fShaderPipeline->shadeSpan4f(x, y, tmp, n);
reedd8829012016-03-04 11:07:43 -0800165 fXferProc(nullptr, dstC, tmp, n, nullptr);
166 dstC += n;
167 x += n;
168 count -= n;
169 }
170 }
171
herb69076fe2016-04-12 14:07:59 -0700172 bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override {
173 SkXfermode::Mode mode;
174 if (!SkXfermode::AsMode(state->fXfer, &mode)) { return false; }
175
176 // Need to ensure that our pipeline is created at a 16byte aligned address
177 fBlitterPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fBlitterStorage);
178 if (SkLinearBitmapPipeline::ClonePipelineForBlitting(
179 fBlitterPipeline, *fShaderPipeline,
180 fMatrixTypeMask,
181 fXMode, fYMode,
182 fFilterQuality, fSrcPixmap,
herb9f666a12016-04-25 09:05:14 -0700183 fAlpha, mode, dstInfo))
184 {
herb69076fe2016-04-12 14:07:59 -0700185 state->fStorage[0] = fBlitterPipeline;
186 state->fBlitBW = &LinearPipelineContext::ForwardToPipeline;
187
188 return true;
189 }
190
191 // Did not successfully create a pipeline so don't destruct it.
192 fBlitterPipeline = nullptr;
193 return false;
194 }
195
196 static void ForwardToPipeline(BlitState* state, int x, int y, const SkPixmap& dst, int count) {
197 SkLinearBitmapPipeline* pipeline = static_cast<SkLinearBitmapPipeline*>(state->fStorage[0]);
198 void* addr = dst.writable_addr32(x, y);
199 pipeline->blitSpan(x, y, addr, count);
200 }
201
202
reedd8829012016-03-04 11:07:43 -0800203private:
204 enum {
205 kActualSize = sizeof(SkLinearBitmapPipeline),
206 kPaddedSize = SkAlignPtr(kActualSize + 12),
207 };
herb69076fe2016-04-12 14:07:59 -0700208 void* fShaderStorage[kPaddedSize / sizeof(void*)];
209 SkLinearBitmapPipeline* fShaderPipeline;
210 void* fBlitterStorage[kPaddedSize / sizeof(void*)];
211 SkLinearBitmapPipeline* fBlitterPipeline{nullptr};
reedd8829012016-03-04 11:07:43 -0800212 SkXfermode::D32Proc fXferProc;
herb69076fe2016-04-12 14:07:59 -0700213 SkPixmap fSrcPixmap;
214 float fAlpha;
215 SkShader::TileMode fXMode;
216 SkShader::TileMode fYMode;
217 SkMatrix::TypeMask fMatrixTypeMask;
218 SkFilterQuality fFilterQuality;
reedd8829012016-03-04 11:07:43 -0800219
220 typedef BitmapProcInfoContext INHERITED;
221};
222
223///////////////////////////////////////////////////////////////////////////////////////////////////
224
225static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) {
226 // These src attributes are not supported in the new 4f context (yet)
227 //
herb222f8ff2016-03-23 15:14:23 -0700228 if (srcInfo.colorType() != kRGBA_8888_SkColorType
229 && srcInfo.colorType() != kBGRA_8888_SkColorType
herbd5f2e2e2016-04-14 11:16:44 -0700230 && srcInfo.colorType() != kIndex_8_SkColorType
231 && srcInfo.colorType() != kRGBA_F16_SkColorType) {
reedd8829012016-03-04 11:07:43 -0800232 return false;
233 }
234
reedd8829012016-03-04 11:07:43 -0800235 // If we get here, we can reasonably use either context, respect the caller's preference
236 //
237 return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType;
238}
239
240size_t SkBitmapProcShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) {
241 size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
242 size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo);
243 return SkTMax(size0, size1);
reed7a4d8472015-09-15 13:33:58 -0700244}
245
reed05a56472016-03-02 09:49:02 -0800246SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
247 TileMode tmx, TileMode tmy,
248 const SkBitmapProvider& provider,
249 const ContextRec& rec, void* storage) {
250 SkMatrix totalInverse;
251 // Do this first, so we know the matrix can be inverted.
252 if (!shader.computeTotalInverse(rec, &totalInverse)) {
253 return nullptr;
254 }
255
herb6eff52a2016-03-23 09:00:33 -0700256 // Decide if we can/want to use the new linear pipeline
reedd8829012016-03-04 11:07:43 -0800257 bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());
reedcd660e12016-03-03 09:36:50 -0800258
reedd8829012016-03-04 11:07:43 -0800259 if (useLinearPipeline) {
260 void* infoStorage = (char*)storage + sizeof(LinearPipelineContext);
261 SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy);
262 if (!info->init(totalInverse, *rec.fPaint)) {
263 info->~SkBitmapProcInfo();
264 return nullptr;
265 }
herb6eff52a2016-03-23 09:00:33 -0700266 if (info->fPixmap.colorType() != kRGBA_8888_SkColorType
herb222f8ff2016-03-23 15:14:23 -0700267 && info->fPixmap.colorType() != kBGRA_8888_SkColorType
herbd5f2e2e2016-04-14 11:16:44 -0700268 && info->fPixmap.colorType() != kIndex_8_SkColorType
269 && info->fPixmap.colorType() != kRGBA_F16_SkColorType) {
herb6eff52a2016-03-23 09:00:33 -0700270 return nullptr;
271 }
reedd8829012016-03-04 11:07:43 -0800272 return new (storage) LinearPipelineContext(shader, rec, info);
273 } else {
274 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
275 SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
276 if (!state->setup(totalInverse, *rec.fPaint)) {
277 state->~SkBitmapProcState();
278 return nullptr;
279 }
280 return new (storage) BitmapProcShaderContext(shader, rec, state);
281 }
reed05a56472016-03-02 09:49:02 -0800282}
283
284SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
285 return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
286 SkBitmapProvider(fRawBitmap), rec, storage);
287}
288
289///////////////////////////////////////////////////////////////////////////////////////////////////
290
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000291SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
292 const SkMatrix* localMatrix)
293 : INHERITED(localMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 fRawBitmap = src;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000295 fTileModeX = (uint8_t)tmx;
296 fTileModeY = (uint8_t)tmy;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297}
298
reed0f0af232015-09-08 11:02:04 -0700299bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 if (texture) {
301 *texture = fRawBitmap;
302 }
303 if (texM) {
304 texM->reset();
305 }
306 if (xy) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000307 xy[0] = (TileMode)fTileModeX;
308 xy[1] = (TileMode)fTileModeY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309 }
reed0f0af232015-09-08 11:02:04 -0700310 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311}
312
reed60c9b582016-04-03 09:11:13 -0700313sk_sp<SkFlattenable> SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700314 SkMatrix lm;
315 buffer.readMatrix(&lm);
316 SkBitmap bm;
317 if (!buffer.readBitmap(&bm)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700318 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700319 }
320 bm.setImmutable();
321 TileMode mx = (TileMode)buffer.readUInt();
322 TileMode my = (TileMode)buffer.readUInt();
reed60c9b582016-04-03 09:11:13 -0700323 return SkShader::MakeBitmapShader(bm, mx, my, &lm);
reed9fa60da2014-08-21 07:59:51 -0700324}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325
reed9fa60da2014-08-21 07:59:51 -0700326void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
327 buffer.writeMatrix(this->getLocalMatrix());
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000328 buffer.writeBitmap(fRawBitmap);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000329 buffer.writeUInt(fTileModeX);
330 buffer.writeUInt(fTileModeY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331}
332
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000333bool SkBitmapProcShader::isOpaque() const {
334 return fRawBitmap.isOpaque();
335}
336
reed05a56472016-03-02 09:49:02 -0800337///////////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338
reed@android.comc6459962009-08-25 19:15:31 +0000339#include "SkUnPreMultiply.h"
340#include "SkColorShader.h"
reed@google.com37a20122011-07-05 18:54:12 +0000341#include "SkEmptyShader.h"
reed@android.comc6459962009-08-25 19:15:31 +0000342
343// returns true and set color if the bitmap can be drawn as a single color
344// (for efficiency)
robertphillips5f865b92015-07-29 12:28:04 -0700345static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
djsollenab51cbd2015-07-14 10:59:28 -0700346#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
347 // HWUI does not support color shaders (see b/22390304)
348 return false;
349#endif
350
reed@android.comc6459962009-08-25 19:15:31 +0000351 if (1 != bm.width() || 1 != bm.height()) {
352 return false;
353 }
354
355 SkAutoLockPixels alp(bm);
356 if (!bm.readyToDraw()) {
357 return false;
358 }
359
reed@google.com900ecf22014-02-20 20:55:37 +0000360 switch (bm.colorType()) {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000361 case kN32_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000362 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
363 return true;
reed@google.com900ecf22014-02-20 20:55:37 +0000364 case kRGB_565_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000365 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
366 return true;
reed@google.com900ecf22014-02-20 20:55:37 +0000367 case kIndex_8_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000368 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
369 return true;
370 default: // just skip the other configs for now
371 break;
372 }
373 return false;
374}
375
robertphillips5f865b92015-07-29 12:28:04 -0700376static bool bitmap_is_too_big(const SkBitmap& bm) {
reed@google.com99c114e2012-05-03 20:14:26 +0000377 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
378 // communicates between its matrix-proc and its sampler-proc. Until we can
379 // widen that, we have to reject bitmaps that are larger.
380 //
robertphillips5f865b92015-07-29 12:28:04 -0700381 static const int kMaxSize = 65535;
reed@google.com99c114e2012-05-03 20:14:26 +0000382
robertphillips5f865b92015-07-29 12:28:04 -0700383 return bm.width() > kMaxSize || bm.height() > kMaxSize;
reed@google.com99c114e2012-05-03 20:14:26 +0000384}
385
reed8a21c9f2016-03-08 18:50:00 -0800386sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
387 SkShader::TileMode tmy, const SkMatrix* localMatrix,
388 SkTBlitterAllocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 SkShader* shader;
reed@android.comc6459962009-08-25 19:15:31 +0000390 SkColor color;
robertphillips5f865b92015-07-29 12:28:04 -0700391 if (src.isNull() || bitmap_is_too_big(src)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700392 if (nullptr == allocator) {
halcanary385fe4d2015-08-26 13:07:48 -0700393 shader = new SkEmptyShader;
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000394 } else {
395 shader = allocator->createT<SkEmptyShader>();
396 }
robertphillips5f865b92015-07-29 12:28:04 -0700397 } else if (can_use_color_shader(src, &color)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 if (nullptr == allocator) {
halcanary385fe4d2015-08-26 13:07:48 -0700399 shader = new SkColorShader(color);
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000400 } else {
401 shader = allocator->createT<SkColorShader>(color);
402 }
reed@android.comc6459962009-08-25 19:15:31 +0000403 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700404 if (nullptr == allocator) {
halcanary385fe4d2015-08-26 13:07:48 -0700405 shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000406 } else {
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000407 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000408 }
reed@android.comc6459962009-08-25 19:15:31 +0000409 }
reed8a21c9f2016-03-08 18:50:00 -0800410 return sk_sp<SkShader>(shader);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411}
412
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413///////////////////////////////////////////////////////////////////////////////
414
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000415#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000416void SkBitmapProcShader::toString(SkString* str) const {
417 static const char* gTileModeName[SkShader::kTileModeCount] = {
418 "clamp", "repeat", "mirror"
419 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000421 str->append("BitmapShader: (");
reed@google.com7c2f27d2011-03-07 19:29:00 +0000422
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000423 str->appendf("(%s, %s)",
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000424 gTileModeName[fTileModeX],
425 gTileModeName[fTileModeY]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000426
427 str->append(" ");
428 fRawBitmap.toString(str);
429
430 this->INHERITED::toString(str);
431
432 str->append(")");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433}
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000434#endif
435
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000436///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000438#if SK_SUPPORT_GPU
439
440#include "GrTextureAccess.h"
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000441#include "SkGr.h"
joshualitt9bc39542015-08-12 12:57:54 -0700442#include "effects/GrSimpleTextureEffect.h"
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000443
bsalomonc21b09e2015-08-28 18:46:56 -0700444const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
445 const SkMatrix& viewM, const SkMatrix* localMatrix,
bsalomon4a339522015-10-06 08:40:50 -0700446 SkFilterQuality filterQuality) const {
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000447 SkMatrix matrix;
448 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
449
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000450 SkMatrix lmInverse;
451 if (!this->getLocalMatrix().invert(&lmInverse)) {
bsalomonc21b09e2015-08-28 18:46:56 -0700452 return nullptr;
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000453 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +0000454 if (localMatrix) {
455 SkMatrix inv;
456 if (!localMatrix->invert(&inv)) {
bsalomonc21b09e2015-08-28 18:46:56 -0700457 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +0000458 }
459 lmInverse.postConcat(inv);
460 }
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000461 matrix.preConcat(lmInverse);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000462
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000463 SkShader::TileMode tm[] = {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000464 (TileMode)fTileModeX,
465 (TileMode)fTileModeY,
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000466 };
467
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000468 // Must set wrap and filter on the sampler before requesting a texture. In two places below
469 // we check the matrix scale factors to determine how to interpret the filter quality setting.
470 // This completely ignores the complexity of the drawVertices case where explicit local coords
471 // are provided by the caller.
joshualitt9bc39542015-08-12 12:57:54 -0700472 bool doBicubic;
473 GrTextureParams::FilterMode textureFilterMode =
bsalomonc21b09e2015-08-28 18:46:56 -0700474 GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
joshualitt9bc39542015-08-12 12:57:54 -0700475 &doBicubic);
humper@google.comb86add12013-07-25 18:49:07 +0000476 GrTextureParams params(tm, textureFilterMode);
bsalomonafa95e22015-10-12 10:39:46 -0700477 SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000478
bsalomonbcf0a522014-10-08 08:40:09 -0700479 if (!texture) {
humper@google.com3aad3b02013-09-04 19:23:53 +0000480 SkErrorInternals::SetError( kInternalError_SkError,
481 "Couldn't convert bitmap to texture.");
bsalomonc21b09e2015-08-28 18:46:56 -0700482 return nullptr;
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000483 }
mtklein7ef849d2014-11-24 09:11:45 -0800484
bsalomon85153772015-11-05 09:35:01 -0800485 SkAutoTUnref<const GrFragmentProcessor> inner;
joshualitt9bc39542015-08-12 12:57:54 -0700486 if (doBicubic) {
bsalomon4a339522015-10-06 08:40:50 -0700487 inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
humper@google.com3aad3b02013-09-04 19:23:53 +0000488 } else {
bsalomon4a339522015-10-06 08:40:50 -0700489 inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
humper@google.com3aad3b02013-09-04 19:23:53 +0000490 }
dandov9de5b512014-06-10 14:38:28 -0700491
bsalomonc21b09e2015-08-28 18:46:56 -0700492 if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700493 return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
bsalomonc21b09e2015-08-28 18:46:56 -0700494 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700495 return GrFragmentProcessor::MulOutputByInputAlpha(inner);
dandov9de5b512014-06-10 14:38:28 -0700496}
497
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000498#endif