blob: 00d938be2729c4559da807437f52b12d1dc82045 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00009#include "SkReadBuffer.h"
10#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkPixelRef.h"
humper@google.comb86add12013-07-25 18:49:07 +000012#include "SkErrorInternals.h"
humper@google.com3aad3b02013-09-04 19:23:53 +000013#include "SkBitmapProcShader.h"
14
humper@google.com30df03c2013-09-04 19:57:11 +000015#if SK_SUPPORT_GPU
humper@google.com3aad3b02013-09-04 19:23:53 +000016#include "effects/GrSimpleTextureEffect.h"
17#include "effects/GrBicubicEffect.h"
humper@google.com30df03c2013-09-04 19:57:11 +000018#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
20bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
reed@google.com900ecf22014-02-20 20:55:37 +000021 switch (bm.colorType()) {
22 case kAlpha_8_SkColorType:
23 case kRGB_565_SkColorType:
24 case kIndex_8_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000025 case kN32_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
27 return true;
28 default:
29 break;
30 }
31 return false;
32}
33
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +000034SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
35 const SkMatrix* localMatrix)
36 : INHERITED(localMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 fRawBitmap = src;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000038 fTileModeX = (uint8_t)tmx;
39 fTileModeY = (uint8_t)tmy;
reed@android.com8a1c16f2008-12-17 15:59:43 +000040}
41
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000042SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 : INHERITED(buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000044 buffer.readBitmap(&fRawBitmap);
reed@google.com84239fb2012-12-10 16:10:33 +000045 fRawBitmap.setImmutable();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000046 fTileModeX = buffer.readUInt();
47 fTileModeY = buffer.readUInt();
reed@android.com8a1c16f2008-12-17 15:59:43 +000048}
49
reed@google.com7c2f27d2011-03-07 19:29:00 +000050SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
51 SkMatrix* texM,
rileya@google.com91f319c2012-07-25 17:18:31 +000052 TileMode xy[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 if (texture) {
54 *texture = fRawBitmap;
55 }
56 if (texM) {
57 texM->reset();
58 }
59 if (xy) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000060 xy[0] = (TileMode)fTileModeX;
61 xy[1] = (TileMode)fTileModeY;
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 }
reed@android.comf2b98d62010-12-20 18:26:13 +000063 return kDefault_BitmapType;
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000066void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 this->INHERITED::flatten(buffer);
68
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000069 buffer.writeBitmap(fRawBitmap);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000070 buffer.writeUInt(fTileModeX);
71 buffer.writeUInt(fTileModeY);
reed@android.com8a1c16f2008-12-17 15:59:43 +000072}
73
reed@android.com5119bdb2009-06-12 21:27:03 +000074static bool only_scale_and_translate(const SkMatrix& matrix) {
75 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
76 return (matrix.getType() & ~mask) == 0;
77}
78
junov@chromium.orgb6e16192011-12-09 15:48:03 +000079bool SkBitmapProcShader::isOpaque() const {
80 return fRawBitmap.isOpaque();
81}
82
reed@google.comcee9dcb2013-09-13 16:04:49 +000083static bool valid_for_drawing(const SkBitmap& bm) {
84 if (0 == bm.width() || 0 == bm.height()) {
85 return false; // nothing to draw
86 }
87 if (NULL == bm.pixelRef()) {
88 return false; // no pixels to read
89 }
reed@google.com900ecf22014-02-20 20:55:37 +000090 if (kIndex_8_SkColorType == bm.colorType()) {
reed@google.comcee9dcb2013-09-13 16:04:49 +000091 // ugh, I have to lock-pixels to inspect the colortable
92 SkAutoLockPixels alp(bm);
93 if (!bm.getColorTable()) {
94 return false;
95 }
96 }
97 return true;
98}
99
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000100SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
reed@google.comcee9dcb2013-09-13 16:04:49 +0000101 if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000102 return NULL;
reed@google.comcee9dcb2013-09-13 16:04:49 +0000103 }
skia.committer@gmail.comedda70e2014-05-06 03:06:53 +0000104
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000105 SkMatrix totalInverse;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000106 // Do this first, so we know the matrix can be inverted.
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000107 if (!this->computeTotalInverse(rec, &totalInverse)) {
108 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 }
skia.committer@gmail.comedda70e2014-05-06 03:06:53 +0000110
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000111 void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
112 SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000114 SkASSERT(state);
115 state->fTileModeX = fTileModeX;
116 state->fTileModeY = fTileModeY;
117 state->fOrigBitmap = fRawBitmap;
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000118 if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000119 state->~SkBitmapProcState();
120 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 }
122
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000123 return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, (*this, rec, state));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000124}
125
126size_t SkBitmapProcShader::contextSize() const {
127 // The SkBitmapProcState is stored outside of the context object, with the context holding
128 // a pointer to it.
129 return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
130}
131
132SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000133 const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state)
134 : INHERITED(shader, rec)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000135 , fState(state)
136{
137 const SkBitmap& bitmap = *fState->fBitmap;
reed@android.com7f6e1e92009-10-14 21:06:29 +0000138 bool bitmapIsOpaque = bitmap.isOpaque();
reed@google.com7c2f27d2011-03-07 19:29:00 +0000139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 // update fFlags
reed@android.comcafc9f92009-08-22 03:44:57 +0000141 uint32_t flags = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
reed@android.comcafc9f92009-08-22 03:44:57 +0000143 flags |= kOpaqueAlpha_Flag;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 }
145
reed@google.com900ecf22014-02-20 20:55:37 +0000146 switch (bitmap.colorType()) {
147 case kRGB_565_SkColorType:
reed@android.comcafc9f92009-08-22 03:44:57 +0000148 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 break;
reed@google.com900ecf22014-02-20 20:55:37 +0000150 case kIndex_8_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000151 case kN32_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 if (bitmapIsOpaque) {
reed@android.comcafc9f92009-08-22 03:44:57 +0000153 flags |= kHasSpan16_Flag;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 }
155 break;
reed@google.com900ecf22014-02-20 20:55:37 +0000156 case kAlpha_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 break; // never set kHasSpan16_Flag
158 default:
159 break;
160 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000161
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000162 if (rec.fPaint->isDither() && bitmap.colorType() != kRGB_565_SkColorType) {
reed@android.comcafc9f92009-08-22 03:44:57 +0000163 // gradients can auto-dither in their 16bit sampler, but we don't so
reed@android.com7f6e1e92009-10-14 21:06:29 +0000164 // we clear the flag here.
reed@android.comcafc9f92009-08-22 03:44:57 +0000165 flags &= ~kHasSpan16_Flag;
166 }
167
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000168 // if we're only 1-pixel high, and we don't rotate, then we can claim this
reed@android.com7f6e1e92009-10-14 21:06:29 +0000169 if (1 == bitmap.height() &&
reed@android.com5119bdb2009-06-12 21:27:03 +0000170 only_scale_and_translate(this->getTotalInverse())) {
reed@android.com3c9b2a42009-08-27 19:28:37 +0000171 flags |= kConstInY32_Flag;
172 if (flags & kHasSpan16_Flag) {
173 flags |= kConstInY16_Flag;
174 }
reed@android.com5119bdb2009-06-12 21:27:03 +0000175 }
reed@android.comcafc9f92009-08-22 03:44:57 +0000176
177 fFlags = flags;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178}
179
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000180SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
181 // The bitmap proc state has been created outside of the context on memory that will be freed
182 // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
183 fState->~SkBitmapProcState();
reed@google.coma641f3f2012-12-13 22:16:30 +0000184}
185
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186#define BUF_MAX 128
187
reed@android.com258cb222010-04-14 13:36:33 +0000188#define TEST_BUFFER_OVERRITEx
189
190#ifdef TEST_BUFFER_OVERRITE
191 #define TEST_BUFFER_EXTRA 32
192 #define TEST_PATTERN 0x88888888
193#else
194 #define TEST_BUFFER_EXTRA 0
195#endif
196
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000197void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
198 int count) {
199 const SkBitmapProcState& state = *fState;
reed@google.com9fe287b2012-03-27 15:54:28 +0000200 if (state.getShaderProc32()) {
201 state.getShaderProc32()(state, x, y, dstC, count);
reed@android.com7a99eb12009-07-16 01:13:14 +0000202 return;
203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
reed@android.com258cb222010-04-14 13:36:33 +0000205 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
reed@google.com9fe287b2012-03-27 15:54:28 +0000206 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
207 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000208 int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
210 SkASSERT(state.fBitmap->getPixels());
211 SkASSERT(state.fBitmap->pixelRef() == NULL ||
reed@google.comff0da4f2012-05-17 13:14:52 +0000212 state.fBitmap->pixelRef()->isLocked());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
214 for (;;) {
215 int n = count;
216 if (n > max) {
217 n = max;
218 }
reed@android.com258cb222010-04-14 13:36:33 +0000219 SkASSERT(n > 0 && n < BUF_MAX*2);
220#ifdef TEST_BUFFER_OVERRITE
221 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
222 buffer[BUF_MAX + i] = TEST_PATTERN;
223 }
224#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 mproc(state, buffer, n, x, y);
reed@android.com258cb222010-04-14 13:36:33 +0000226#ifdef TEST_BUFFER_OVERRITE
227 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
228 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
229 }
230#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 sproc(state, buffer, n, dstC);
reed@google.com7c2f27d2011-03-07 19:29:00 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 if ((count -= n) == 0) {
234 break;
235 }
reed@android.com258cb222010-04-14 13:36:33 +0000236 SkASSERT(count > 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 x += n;
238 dstC += n;
239 }
240}
241
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000242SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
243 if (fState->getShaderProc32()) {
244 *ctx = fState;
245 return (ShadeProc)fState->getShaderProc32();
reed@google.com3bafe742012-10-12 18:56:18 +0000246 }
247 return NULL;
248}
249
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000250void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
251 int count) {
252 const SkBitmapProcState& state = *fState;
reed@google.com9fe287b2012-03-27 15:54:28 +0000253 if (state.getShaderProc16()) {
254 state.getShaderProc16()(state, x, y, dstC, count);
reed@android.com7a99eb12009-07-16 01:13:14 +0000255 return;
256 }
reed@google.com7c2f27d2011-03-07 19:29:00 +0000257
reed@android.com7a99eb12009-07-16 01:13:14 +0000258 uint32_t buffer[BUF_MAX];
reed@google.com9fe287b2012-03-27 15:54:28 +0000259 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
260 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000261 int max = state.maxCountForBufferSize(sizeof(buffer));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262
263 SkASSERT(state.fBitmap->getPixels());
264 SkASSERT(state.fBitmap->pixelRef() == NULL ||
reed@google.comff0da4f2012-05-17 13:14:52 +0000265 state.fBitmap->pixelRef()->isLocked());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266
267 for (;;) {
268 int n = count;
269 if (n > max) {
270 n = max;
271 }
272 mproc(state, buffer, n, x, y);
273 sproc(state, buffer, n, dstC);
reed@google.com7c2f27d2011-03-07 19:29:00 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 if ((count -= n) == 0) {
276 break;
277 }
278 x += n;
279 dstC += n;
280 }
281}
282
283///////////////////////////////////////////////////////////////////////////////
284
reed@android.comc6459962009-08-25 19:15:31 +0000285#include "SkUnPreMultiply.h"
286#include "SkColorShader.h"
reed@google.com37a20122011-07-05 18:54:12 +0000287#include "SkEmptyShader.h"
reed@android.comc6459962009-08-25 19:15:31 +0000288
289// returns true and set color if the bitmap can be drawn as a single color
290// (for efficiency)
291static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
292 if (1 != bm.width() || 1 != bm.height()) {
293 return false;
294 }
295
296 SkAutoLockPixels alp(bm);
297 if (!bm.readyToDraw()) {
298 return false;
299 }
300
reed@google.com900ecf22014-02-20 20:55:37 +0000301 switch (bm.colorType()) {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000302 case kN32_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000303 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
304 return true;
reed@google.com900ecf22014-02-20 20:55:37 +0000305 case kRGB_565_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000306 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
307 return true;
reed@google.com900ecf22014-02-20 20:55:37 +0000308 case kIndex_8_SkColorType:
reed@android.comc6459962009-08-25 19:15:31 +0000309 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
310 return true;
311 default: // just skip the other configs for now
312 break;
313 }
314 return false;
315}
316
reed@google.com99c114e2012-05-03 20:14:26 +0000317static bool bitmapIsTooBig(const SkBitmap& bm) {
318 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
319 // communicates between its matrix-proc and its sampler-proc. Until we can
320 // widen that, we have to reject bitmaps that are larger.
321 //
322 const int maxSize = 65535;
323
324 return bm.width() > maxSize || bm.height() > maxSize;
325}
326
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000327SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000328 SkShader::TileMode tmy, const SkMatrix* localMatrix, SkTBlitterAllocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 SkShader* shader;
reed@android.comc6459962009-08-25 19:15:31 +0000330 SkColor color;
reed@google.com99c114e2012-05-03 20:14:26 +0000331 if (src.isNull() || bitmapIsTooBig(src)) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000332 if (NULL == allocator) {
333 shader = SkNEW(SkEmptyShader);
334 } else {
335 shader = allocator->createT<SkEmptyShader>();
336 }
reed@google.com37a20122011-07-05 18:54:12 +0000337 }
338 else if (canUseColorShader(src, &color)) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000339 if (NULL == allocator) {
340 shader = SkNEW_ARGS(SkColorShader, (color));
341 } else {
342 shader = allocator->createT<SkColorShader>(color);
343 }
reed@android.comc6459962009-08-25 19:15:31 +0000344 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000345 if (NULL == allocator) {
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000346 shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix));
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000347 } else {
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000348 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000349 }
reed@android.comc6459962009-08-25 19:15:31 +0000350 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 return shader;
352}
353
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354///////////////////////////////////////////////////////////////////////////////
355
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000356#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000357void SkBitmapProcShader::toString(SkString* str) const {
358 static const char* gTileModeName[SkShader::kTileModeCount] = {
359 "clamp", "repeat", "mirror"
360 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000362 str->append("BitmapShader: (");
reed@google.com7c2f27d2011-03-07 19:29:00 +0000363
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000364 str->appendf("(%s, %s)",
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000365 gTileModeName[fTileModeX],
366 gTileModeName[fTileModeY]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000367
368 str->append(" ");
369 fRawBitmap.toString(str);
370
371 this->INHERITED::toString(str);
372
373 str->append(")");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374}
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000375#endif
376
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000377///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000379#if SK_SUPPORT_GPU
380
381#include "GrTextureAccess.h"
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000382#include "effects/GrSimpleTextureEffect.h"
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000383#include "SkGr.h"
384
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000385// Note that this will return -1 if either matrix is perspective.
386static SkScalar get_combined_min_stretch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) {
387 if (localMatrix.isIdentity()) {
388 return viewMatrix.getMinStretch();
389 } else {
390 SkMatrix combined;
391 combined.setConcat(viewMatrix, localMatrix);
392 return combined.getMinStretch();
393 }
394}
395
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000396GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000397 SkMatrix matrix;
398 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
399
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000400 SkMatrix lmInverse;
401 if (!this->getLocalMatrix().invert(&lmInverse)) {
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000402 return NULL;
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000403 }
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000404 matrix.preConcat(lmInverse);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000405
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000406 SkShader::TileMode tm[] = {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000407 (TileMode)fTileModeX,
408 (TileMode)fTileModeY,
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000409 };
410
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000411 // Must set wrap and filter on the sampler before requesting a texture. In two places below
412 // we check the matrix scale factors to determine how to interpret the filter quality setting.
413 // This completely ignores the complexity of the drawVertices case where explicit local coords
414 // are provided by the caller.
humper@google.comb86add12013-07-25 18:49:07 +0000415 SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
416 GrTextureParams::FilterMode textureFilterMode;
417 switch(paintFilterLevel) {
418 case SkPaint::kNone_FilterLevel:
419 textureFilterMode = GrTextureParams::kNone_FilterMode;
420 break;
421 case SkPaint::kLow_FilterLevel:
422 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
423 break;
424 case SkPaint::kMedium_FilterLevel:
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000425 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) <
426 SK_Scalar1) {
427 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
428 } else {
429 // Don't trigger MIP level generation unnecessarily.
430 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
431 }
humper@google.comb86add12013-07-25 18:49:07 +0000432 break;
433 case SkPaint::kHigh_FilterLevel:
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000434 // Minification can look bad with bicubic filtering.
435 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) >=
436 SK_Scalar1) {
437 // fall back to no filtering here; we will install another shader that will do the
438 // HQ filtering.
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000439 textureFilterMode = GrTextureParams::kNone_FilterMode;
440 } else {
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +0000441 // Fall back to MIP-mapping.
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000442 paintFilterLevel = SkPaint::kMedium_FilterLevel;
443 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
444 }
humper@google.comb86add12013-07-25 18:49:07 +0000445 break;
humper@google.comf9ed6fe2013-07-25 19:09:47 +0000446 default:
447 SkErrorInternals::SetError( kInvalidPaint_SkError,
448 "Sorry, I don't understand the filtering "
449 "mode you asked for. Falling back to "
450 "MIPMaps.");
451 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
452 break;
skia.committer@gmail.com956b3102013-07-26 07:00:58 +0000453
humper@google.comb86add12013-07-25 18:49:07 +0000454 }
455 GrTextureParams params(tm, textureFilterMode);
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000456 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000457
458 if (NULL == texture) {
humper@google.com3aad3b02013-09-04 19:23:53 +0000459 SkErrorInternals::SetError( kInternalError_SkError,
460 "Couldn't convert bitmap to texture.");
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000461 return NULL;
462 }
463
humper@google.com3aad3b02013-09-04 19:23:53 +0000464 GrEffectRef* effect = NULL;
465 if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
commit-bot@chromium.orgbc91fd72013-12-10 12:53:39 +0000466 effect = GrBicubicEffect::Create(texture, matrix, tm);
humper@google.com3aad3b02013-09-04 19:23:53 +0000467 } else {
468 effect = GrSimpleTextureEffect::Create(texture, matrix, params);
469 }
bsalomon@google.com95ed55a2013-01-24 14:46:47 +0000470 GrUnlockAndUnrefCachedBitmapTexture(texture);
bsalomon@google.come197cbf2013-01-14 16:46:26 +0000471 return effect;
472}
473#endif