blob: a41b2009d909977a7d261d286c5d00aef9c2ca99 [file] [log] [blame]
reed856e9d92015-09-30 12:21:45 -07001/*
2 * Copyright 2015 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 */
7
8#include "SkBitmapProcShader.h"
9#include "SkBitmapProvider.h"
reed320a40d2016-08-02 06:12:06 -070010#include "SkColorShader.h"
11#include "SkColorTable.h"
12#include "SkEmptyShader.h"
Mike Klein06a65e22016-11-17 12:39:09 -050013#include "SkFixedAlloc.h"
reed856e9d92015-09-30 12:21:45 -070014#include "SkImage_Base.h"
15#include "SkImageShader.h"
Mike Klein06a65e22016-11-17 12:39:09 -050016#include "SkPM4fPriv.h"
reed856e9d92015-09-30 12:21:45 -070017#include "SkReadBuffer.h"
18#include "SkWriteBuffer.h"
19
reed6b2d7ac2016-08-11 06:42:26 -070020SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
reed856e9d92015-09-30 12:21:45 -070021 : INHERITED(matrix)
reed6b2d7ac2016-08-11 06:42:26 -070022 , fImage(std::move(img))
reed856e9d92015-09-30 12:21:45 -070023 , fTileModeX(tmx)
24 , fTileModeY(tmy)
25{}
26
reed60c9b582016-04-03 09:11:13 -070027sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
reed856e9d92015-09-30 12:21:45 -070028 const TileMode tx = (TileMode)buffer.readUInt();
29 const TileMode ty = (TileMode)buffer.readUInt();
30 SkMatrix matrix;
31 buffer.readMatrix(&matrix);
reeda9ca05c2016-08-11 03:55:15 -070032 sk_sp<SkImage> img = buffer.readImage();
reed856e9d92015-09-30 12:21:45 -070033 if (!img) {
34 return nullptr;
35 }
reed6b2d7ac2016-08-11 06:42:26 -070036 return SkImageShader::Make(std::move(img), tx, ty, &matrix);
reed856e9d92015-09-30 12:21:45 -070037}
38
39void SkImageShader::flatten(SkWriteBuffer& buffer) const {
40 buffer.writeUInt(fTileModeX);
41 buffer.writeUInt(fTileModeY);
42 buffer.writeMatrix(this->getLocalMatrix());
reed6b2d7ac2016-08-11 06:42:26 -070043 buffer.writeImage(fImage.get());
reed856e9d92015-09-30 12:21:45 -070044}
45
46bool SkImageShader::isOpaque() const {
47 return fImage->isOpaque();
48}
49
reed773ceda2016-03-03 18:18:25 -080050size_t SkImageShader::onContextSize(const ContextRec& rec) const {
fmalitadc87a7d2016-10-17 06:09:26 -070051 return SkBitmapProcLegacyShader::ContextSize(rec, as_IB(fImage)->onImageInfo());
reed856e9d92015-09-30 12:21:45 -070052}
53
54SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
reed320a40d2016-08-02 06:12:06 -070055 return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
Brian Osman57ae6cf2016-11-15 18:07:26 +000056 SkBitmapProvider(fImage.get()), rec, storage);
reed856e9d92015-09-30 12:21:45 -070057}
58
reedf1ac1822016-08-01 11:24:14 -070059SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
60 if (texM) {
61 *texM = this->getLocalMatrix();
62 }
63 if (xy) {
64 xy[0] = (TileMode)fTileModeX;
65 xy[1] = (TileMode)fTileModeY;
66 }
67 return const_cast<SkImage*>(fImage.get());
68}
69
Mike Reed627778d2016-09-28 17:13:38 -040070#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
reedf1ac1822016-08-01 11:24:14 -070071bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
72 const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
73 if (!bm) {
74 return false;
75 }
76
77 if (texture) {
78 *texture = *bm;
79 }
80 if (texM) {
81 *texM = this->getLocalMatrix();
82 }
83 if (xy) {
84 xy[0] = (TileMode)fTileModeX;
85 xy[1] = (TileMode)fTileModeY;
86 }
87 return true;
88}
Mike Reed627778d2016-09-28 17:13:38 -040089#endif
reedf1ac1822016-08-01 11:24:14 -070090
reed320a40d2016-08-02 06:12:06 -070091static bool bitmap_is_too_big(int w, int h) {
92 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
93 // communicates between its matrix-proc and its sampler-proc. Until we can
94 // widen that, we have to reject bitmaps that are larger.
95 //
96 static const int kMaxSize = 65535;
Mike Klein06a65e22016-11-17 12:39:09 -050097
reed320a40d2016-08-02 06:12:06 -070098 return w > kMaxSize || h > kMaxSize;
99}
100
101// returns true and set color if the bitmap can be drawn as a single color
102// (for efficiency)
103static bool can_use_color_shader(const SkImage* image, SkColor* color) {
104#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
105 // HWUI does not support color shaders (see b/22390304)
106 return false;
107#endif
Mike Klein06a65e22016-11-17 12:39:09 -0500108
reed320a40d2016-08-02 06:12:06 -0700109 if (1 != image->width() || 1 != image->height()) {
110 return false;
reed856e9d92015-09-30 12:21:45 -0700111 }
Mike Klein06a65e22016-11-17 12:39:09 -0500112
reed320a40d2016-08-02 06:12:06 -0700113 SkPixmap pmap;
114 if (!image->peekPixels(&pmap)) {
115 return false;
116 }
Mike Klein06a65e22016-11-17 12:39:09 -0500117
reed320a40d2016-08-02 06:12:06 -0700118 switch (pmap.colorType()) {
119 case kN32_SkColorType:
120 *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0));
121 return true;
122 case kRGB_565_SkColorType:
123 *color = SkPixel16ToColor(*pmap.addr16(0, 0));
124 return true;
125 case kIndex_8_SkColorType: {
126 const SkColorTable& ctable = *pmap.ctable();
127 *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]);
128 return true;
129 }
130 default: // just skip the other configs for now
131 break;
132 }
133 return false;
134}
135
reed6b2d7ac2016-08-11 06:42:26 -0700136sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
reed320a40d2016-08-02 06:12:06 -0700137 const SkMatrix* localMatrix,
138 SkTBlitterAllocator* allocator) {
139 SkShader* shader;
140 SkColor color;
141 if (!image || bitmap_is_too_big(image->width(), image->height())) {
142 if (nullptr == allocator) {
143 shader = new SkEmptyShader;
144 } else {
145 shader = allocator->createT<SkEmptyShader>();
146 }
reed6b2d7ac2016-08-11 06:42:26 -0700147 } else if (can_use_color_shader(image.get(), &color)) {
reed320a40d2016-08-02 06:12:06 -0700148 if (nullptr == allocator) {
149 shader = new SkColorShader(color);
150 } else {
151 shader = allocator->createT<SkColorShader>(color);
152 }
153 } else {
154 if (nullptr == allocator) {
155 shader = new SkImageShader(image, tx, ty, localMatrix);
156 } else {
157 shader = allocator->createT<SkImageShader>(image, tx, ty, localMatrix);
158 }
159 }
160 return sk_sp<SkShader>(shader);
reed856e9d92015-09-30 12:21:45 -0700161}
162
163#ifndef SK_IGNORE_TO_STRING
164void SkImageShader::toString(SkString* str) const {
165 const char* gTileModeName[SkShader::kTileModeCount] = {
166 "clamp", "repeat", "mirror"
167 };
168
169 str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
170 fImage->toString(str);
171 this->INHERITED::toString(str);
172 str->append(")");
173}
174#endif
175
176///////////////////////////////////////////////////////////////////////////////////////////////////
177
178#if SK_SUPPORT_GPU
179
reed856e9d92015-09-30 12:21:45 -0700180#include "SkGr.h"
bsalomonf276ac52015-10-09 13:36:42 -0700181#include "SkGrPriv.h"
reed856e9d92015-09-30 12:21:45 -0700182#include "effects/GrSimpleTextureEffect.h"
183#include "effects/GrBicubicEffect.h"
184#include "effects/GrSimpleTextureEffect.h"
185
brianosman839345d2016-07-22 11:04:53 -0700186sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
reed856e9d92015-09-30 12:21:45 -0700187 SkMatrix matrix;
188 matrix.setIDiv(fImage->width(), fImage->height());
189
190 SkMatrix lmInverse;
191 if (!this->getLocalMatrix().invert(&lmInverse)) {
192 return nullptr;
193 }
brianosman839345d2016-07-22 11:04:53 -0700194 if (args.fLocalMatrix) {
reed856e9d92015-09-30 12:21:45 -0700195 SkMatrix inv;
brianosman839345d2016-07-22 11:04:53 -0700196 if (!args.fLocalMatrix->invert(&inv)) {
reed856e9d92015-09-30 12:21:45 -0700197 return nullptr;
198 }
199 lmInverse.postConcat(inv);
200 }
201 matrix.preConcat(lmInverse);
202
203 SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
204
205 // Must set wrap and filter on the sampler before requesting a texture. In two places below
206 // we check the matrix scale factors to determine how to interpret the filter quality setting.
207 // This completely ignores the complexity of the drawVertices case where explicit local coords
208 // are provided by the caller.
209 bool doBicubic;
Brian Salomon514baff2016-11-17 15:17:07 -0500210 GrSamplerParams::FilterMode textureFilterMode =
brianosman839345d2016-07-22 11:04:53 -0700211 GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
212 &doBicubic);
Brian Salomon514baff2016-11-17 15:17:07 -0500213 GrSamplerParams params(tm, textureFilterMode);
Brian Osman7b8400d2016-11-08 17:08:54 -0500214 sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params, args.fColorMode));
reed856e9d92015-09-30 12:21:45 -0700215 if (!texture) {
216 return nullptr;
217 }
218
brianosman77320db2016-09-07 08:09:10 -0700219 SkImageInfo info = as_IB(fImage)->onImageInfo();
220 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(info.colorSpace(),
brianosman51924752016-09-12 08:50:19 -0700221 args.fDstColorSpace);
bungeman06ca8ec2016-06-09 08:01:03 -0700222 sk_sp<GrFragmentProcessor> inner;
reed856e9d92015-09-30 12:21:45 -0700223 if (doBicubic) {
Hal Canary67b39de2016-11-07 11:47:44 -0500224 inner = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), matrix, tm);
reed856e9d92015-09-30 12:21:45 -0700225 } else {
Hal Canary67b39de2016-11-07 11:47:44 -0500226 inner = GrSimpleTextureEffect::Make(texture.get(), std::move(colorSpaceXform),
227 matrix, params);
reed856e9d92015-09-30 12:21:45 -0700228 }
229
230 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bungeman06ca8ec2016-06-09 08:01:03 -0700231 return inner;
reed856e9d92015-09-30 12:21:45 -0700232 }
bungeman06ca8ec2016-06-09 08:01:03 -0700233 return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
reed856e9d92015-09-30 12:21:45 -0700234}
235
236#endif
reed320a40d2016-08-02 06:12:06 -0700237
238///////////////////////////////////////////////////////////////////////////////////////////////////
239#include "SkImagePriv.h"
240
241sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
242 SkShader::TileMode tmy, const SkMatrix* localMatrix,
reed1ec04d92016-08-05 12:07:41 -0700243 SkCopyPixelsMode cpm, SkTBlitterAllocator* allocator) {
244 // Until we learn otherwise, it seems that any caller that is passing an allocator must be
245 // assuming that the returned shader will have a stack-frame lifetime, so we assert that
246 // they are also asking for kNever_SkCopyPixelsMode. If that proves otherwise, we can remove
247 // or modify this assert.
248 SkASSERT(!allocator || (kNever_SkCopyPixelsMode == cpm));
249
reed6b2d7ac2016-08-11 06:42:26 -0700250 return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm, allocator),
reed320a40d2016-08-02 06:12:06 -0700251 tmx, tmy, localMatrix, allocator);
252}
253
254static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
255 SkMatrix lm;
256 buffer.readMatrix(&lm);
reeda9ca05c2016-08-11 03:55:15 -0700257 sk_sp<SkImage> image = buffer.readBitmapAsImage();
reed320a40d2016-08-02 06:12:06 -0700258 SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
259 SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
reeda9ca05c2016-08-11 03:55:15 -0700260 return image ? image->makeShader(mx, my, &lm) : nullptr;
reed320a40d2016-08-02 06:12:06 -0700261}
262
263SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
264SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
265SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
266SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
267
Mike Klein06a65e22016-11-17 12:39:09 -0500268
269bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkFallbackAlloc* scratch,
270 const SkMatrix& ctm, SkFilterQuality quality) const {
271 SkPixmap pm;
272 if (!fImage->peekPixels(&pm)) {
273 return false;
274 }
275 auto info = pm.info();
276
277
278 auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
279 if (!matrix.invert(&matrix)) {
280 return false;
281 }
282
283 // TODO: perspective
284 if (!matrix.asAffine(nullptr)) {
285 return false;
286 }
287
288 // TODO: all formats
289 switch (info.colorType()) {
290 case kRGBA_8888_SkColorType:
291 case kBGRA_8888_SkColorType:
292// case kRGB_565_SkColorType:
293// case kRGBA_F16_SkColorType:
294 break;
295 default: return false;
296 }
297
298 // TODO: all tile modes
299 if (fTileModeX != kClamp_TileMode || fTileModeY != kClamp_TileMode) {
300 return false;
301 }
302
Mike Klein77760292016-11-17 14:04:22 -0500303 // When the matrix is just an integer translate, bilerp == nearest neighbor.
304 if (matrix.getType() <= SkMatrix::kTranslate_Mask &&
305 matrix.getTranslateX() == (int)matrix.getTranslateX() &&
306 matrix.getTranslateY() == (int)matrix.getTranslateY()) {
307 quality = kNone_SkFilterQuality;
308 }
309
Mike Klein06a65e22016-11-17 12:39:09 -0500310 // TODO: bilerp
311 if (quality != kNone_SkFilterQuality) {
312 return false;
313 }
314
315 // TODO: mtklein doesn't understand why we do this.
316 if (quality == kNone_SkFilterQuality) {
317 if (matrix.getScaleX() >= 0) {
318 matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
319 floorf(matrix.getTranslateX())));
320 }
321 if (matrix.getScaleY() >= 0) {
322 matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
323 floorf(matrix.getTranslateY())));
324 }
325 }
326
327 struct context {
328 const void* pixels;
329 int stride;
330 int width;
331 int height;
332 float matrix[6];
333 };
334 auto ctx = scratch->make<context>();
335
336 ctx->pixels = pm.addr();
337 ctx->stride = pm.rowBytesAsPixels();
338 ctx->width = pm.width();
339 ctx->height = pm.height();
340 SkAssertResult(matrix.asAffine(ctx->matrix));
341
342 p->append(SkRasterPipeline::matrix_2x3, &ctx->matrix);
343
344 switch (fTileModeX) {
345 case kClamp_TileMode: p->append(SkRasterPipeline::clamp_x, &ctx->width); break;
346 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, &ctx->width); break;
347 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, &ctx->width); break;
348 }
349 switch (fTileModeY) {
350 case kClamp_TileMode: p->append(SkRasterPipeline::clamp_y, &ctx->height); break;
351 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, &ctx->height); break;
352 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &ctx->height); break;
353 }
354
355 switch(info.colorType()) {
356 case kRGBA_8888_SkColorType:
357 case kBGRA_8888_SkColorType:
358 if (info.gammaCloseToSRGB() && dst) {
359 p->append(SkRasterPipeline::nearest_srgb, ctx);
360 } else {
361 p->append(SkRasterPipeline::nearest_8888, ctx);
362 }
363 break;
364 case kRGBA_F16_SkColorType:
365 p->append(SkRasterPipeline::nearest_f16, ctx);
366 break;
367 case kRGB_565_SkColorType:
368 p->append(SkRasterPipeline::nearest_565, ctx);
369 break;
370
371 default:
372 SkASSERT(false);
373 break;
374 }
375
376 if (info.colorType() == kBGRA_8888_SkColorType) {
377 p->append(SkRasterPipeline::swap_rb);
378 }
379 if (info.alphaType() == kUnpremul_SkAlphaType) {
380 p->append(SkRasterPipeline::premul);
381 }
382 return append_gamut_transform(p, scratch, info.colorSpace(), dst);
383}