blob: 528c5729d80f4244187953bdd68b936b6763b709 [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
Mike Kleinf447dee2016-11-29 16:37:12 -05008#include "SkBitmapController.h"
reed856e9d92015-09-30 12:21:45 -07009#include "SkBitmapProcShader.h"
10#include "SkBitmapProvider.h"
reed320a40d2016-08-02 06:12:06 -070011#include "SkColorShader.h"
12#include "SkColorTable.h"
13#include "SkEmptyShader.h"
Mike Klein06a65e22016-11-17 12:39:09 -050014#include "SkFixedAlloc.h"
reed856e9d92015-09-30 12:21:45 -070015#include "SkImage_Base.h"
16#include "SkImageShader.h"
Mike Klein46e66a22016-11-21 16:19:34 -050017#include "SkImageShaderContext.h"
Mike Klein06a65e22016-11-17 12:39:09 -050018#include "SkPM4fPriv.h"
reed856e9d92015-09-30 12:21:45 -070019#include "SkReadBuffer.h"
20#include "SkWriteBuffer.h"
21
reed6b2d7ac2016-08-11 06:42:26 -070022SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
reed856e9d92015-09-30 12:21:45 -070023 : INHERITED(matrix)
reed6b2d7ac2016-08-11 06:42:26 -070024 , fImage(std::move(img))
reed856e9d92015-09-30 12:21:45 -070025 , fTileModeX(tmx)
26 , fTileModeY(tmy)
27{}
28
reed60c9b582016-04-03 09:11:13 -070029sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
reed856e9d92015-09-30 12:21:45 -070030 const TileMode tx = (TileMode)buffer.readUInt();
31 const TileMode ty = (TileMode)buffer.readUInt();
32 SkMatrix matrix;
33 buffer.readMatrix(&matrix);
reeda9ca05c2016-08-11 03:55:15 -070034 sk_sp<SkImage> img = buffer.readImage();
reed856e9d92015-09-30 12:21:45 -070035 if (!img) {
36 return nullptr;
37 }
reed6b2d7ac2016-08-11 06:42:26 -070038 return SkImageShader::Make(std::move(img), tx, ty, &matrix);
reed856e9d92015-09-30 12:21:45 -070039}
40
41void SkImageShader::flatten(SkWriteBuffer& buffer) const {
42 buffer.writeUInt(fTileModeX);
43 buffer.writeUInt(fTileModeY);
44 buffer.writeMatrix(this->getLocalMatrix());
reed6b2d7ac2016-08-11 06:42:26 -070045 buffer.writeImage(fImage.get());
reed856e9d92015-09-30 12:21:45 -070046}
47
48bool SkImageShader::isOpaque() const {
49 return fImage->isOpaque();
50}
51
reed773ceda2016-03-03 18:18:25 -080052size_t SkImageShader::onContextSize(const ContextRec& rec) const {
fmalitadc87a7d2016-10-17 06:09:26 -070053 return SkBitmapProcLegacyShader::ContextSize(rec, as_IB(fImage)->onImageInfo());
reed856e9d92015-09-30 12:21:45 -070054}
55
56SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
reed320a40d2016-08-02 06:12:06 -070057 return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
Brian Osman61624f02016-12-09 14:51:59 -050058 SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
Brian Osman7992da32016-11-18 11:28:24 -050059 rec, storage);
reed856e9d92015-09-30 12:21:45 -070060}
61
reedf1ac1822016-08-01 11:24:14 -070062SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
63 if (texM) {
64 *texM = this->getLocalMatrix();
65 }
66 if (xy) {
67 xy[0] = (TileMode)fTileModeX;
68 xy[1] = (TileMode)fTileModeY;
69 }
70 return const_cast<SkImage*>(fImage.get());
71}
72
Mike Reed627778d2016-09-28 17:13:38 -040073#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
reedf1ac1822016-08-01 11:24:14 -070074bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
75 const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
76 if (!bm) {
77 return false;
78 }
79
80 if (texture) {
81 *texture = *bm;
82 }
83 if (texM) {
84 *texM = this->getLocalMatrix();
85 }
86 if (xy) {
87 xy[0] = (TileMode)fTileModeX;
88 xy[1] = (TileMode)fTileModeY;
89 }
90 return true;
91}
Mike Reed627778d2016-09-28 17:13:38 -040092#endif
reedf1ac1822016-08-01 11:24:14 -070093
reed320a40d2016-08-02 06:12:06 -070094static bool bitmap_is_too_big(int w, int h) {
95 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
96 // communicates between its matrix-proc and its sampler-proc. Until we can
97 // widen that, we have to reject bitmaps that are larger.
98 //
99 static const int kMaxSize = 65535;
Mike Klein06a65e22016-11-17 12:39:09 -0500100
reed320a40d2016-08-02 06:12:06 -0700101 return w > kMaxSize || h > kMaxSize;
102}
103
104// returns true and set color if the bitmap can be drawn as a single color
105// (for efficiency)
106static bool can_use_color_shader(const SkImage* image, SkColor* color) {
107#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
108 // HWUI does not support color shaders (see b/22390304)
109 return false;
110#endif
Mike Klein06a65e22016-11-17 12:39:09 -0500111
reed320a40d2016-08-02 06:12:06 -0700112 if (1 != image->width() || 1 != image->height()) {
113 return false;
reed856e9d92015-09-30 12:21:45 -0700114 }
Mike Klein06a65e22016-11-17 12:39:09 -0500115
reed320a40d2016-08-02 06:12:06 -0700116 SkPixmap pmap;
117 if (!image->peekPixels(&pmap)) {
118 return false;
119 }
Mike Klein06a65e22016-11-17 12:39:09 -0500120
reed320a40d2016-08-02 06:12:06 -0700121 switch (pmap.colorType()) {
122 case kN32_SkColorType:
123 *color = SkUnPreMultiply::PMColorToColor(*pmap.addr32(0, 0));
124 return true;
125 case kRGB_565_SkColorType:
126 *color = SkPixel16ToColor(*pmap.addr16(0, 0));
127 return true;
128 case kIndex_8_SkColorType: {
129 const SkColorTable& ctable = *pmap.ctable();
130 *color = SkUnPreMultiply::PMColorToColor(ctable[*pmap.addr8(0, 0)]);
131 return true;
132 }
133 default: // just skip the other configs for now
134 break;
135 }
136 return false;
137}
138
reed6b2d7ac2016-08-11 06:42:26 -0700139sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
reed320a40d2016-08-02 06:12:06 -0700140 const SkMatrix* localMatrix,
141 SkTBlitterAllocator* allocator) {
142 SkShader* shader;
143 SkColor color;
144 if (!image || bitmap_is_too_big(image->width(), image->height())) {
145 if (nullptr == allocator) {
146 shader = new SkEmptyShader;
147 } else {
148 shader = allocator->createT<SkEmptyShader>();
149 }
reed6b2d7ac2016-08-11 06:42:26 -0700150 } else if (can_use_color_shader(image.get(), &color)) {
reed320a40d2016-08-02 06:12:06 -0700151 if (nullptr == allocator) {
152 shader = new SkColorShader(color);
153 } else {
154 shader = allocator->createT<SkColorShader>(color);
155 }
156 } else {
157 if (nullptr == allocator) {
158 shader = new SkImageShader(image, tx, ty, localMatrix);
159 } else {
160 shader = allocator->createT<SkImageShader>(image, tx, ty, localMatrix);
161 }
162 }
163 return sk_sp<SkShader>(shader);
reed856e9d92015-09-30 12:21:45 -0700164}
165
166#ifndef SK_IGNORE_TO_STRING
167void SkImageShader::toString(SkString* str) const {
168 const char* gTileModeName[SkShader::kTileModeCount] = {
169 "clamp", "repeat", "mirror"
170 };
171
172 str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
173 fImage->toString(str);
174 this->INHERITED::toString(str);
175 str->append(")");
176}
177#endif
178
179///////////////////////////////////////////////////////////////////////////////////////////////////
180
181#if SK_SUPPORT_GPU
182
reed856e9d92015-09-30 12:21:45 -0700183#include "SkGr.h"
bsalomonf276ac52015-10-09 13:36:42 -0700184#include "SkGrPriv.h"
reed856e9d92015-09-30 12:21:45 -0700185#include "effects/GrSimpleTextureEffect.h"
186#include "effects/GrBicubicEffect.h"
187#include "effects/GrSimpleTextureEffect.h"
188
brianosman839345d2016-07-22 11:04:53 -0700189sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
reed856e9d92015-09-30 12:21:45 -0700190 SkMatrix matrix;
191 matrix.setIDiv(fImage->width(), fImage->height());
192
193 SkMatrix lmInverse;
194 if (!this->getLocalMatrix().invert(&lmInverse)) {
195 return nullptr;
196 }
brianosman839345d2016-07-22 11:04:53 -0700197 if (args.fLocalMatrix) {
reed856e9d92015-09-30 12:21:45 -0700198 SkMatrix inv;
brianosman839345d2016-07-22 11:04:53 -0700199 if (!args.fLocalMatrix->invert(&inv)) {
reed856e9d92015-09-30 12:21:45 -0700200 return nullptr;
201 }
202 lmInverse.postConcat(inv);
203 }
204 matrix.preConcat(lmInverse);
205
206 SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
207
208 // Must set wrap and filter on the sampler before requesting a texture. In two places below
209 // we check the matrix scale factors to determine how to interpret the filter quality setting.
210 // This completely ignores the complexity of the drawVertices case where explicit local coords
211 // are provided by the caller.
212 bool doBicubic;
Brian Salomon514baff2016-11-17 15:17:07 -0500213 GrSamplerParams::FilterMode textureFilterMode =
brianosman839345d2016-07-22 11:04:53 -0700214 GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
215 &doBicubic);
Brian Salomon514baff2016-11-17 15:17:07 -0500216 GrSamplerParams params(tm, textureFilterMode);
Brian Osman7992da32016-11-18 11:28:24 -0500217 sk_sp<SkColorSpace> texColorSpace;
Brian Osman61624f02016-12-09 14:51:59 -0500218 sk_sp<GrTexture> texture(as_IB(fImage)->asTextureRef(args.fContext, params, args.fDstColorSpace,
Brian Osman7992da32016-11-18 11:28:24 -0500219 &texColorSpace));
reed856e9d92015-09-30 12:21:45 -0700220 if (!texture) {
221 return nullptr;
222 }
223
Brian Osman7992da32016-11-18 11:28:24 -0500224 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
brianosman51924752016-09-12 08:50:19 -0700225 args.fDstColorSpace);
bungeman06ca8ec2016-06-09 08:01:03 -0700226 sk_sp<GrFragmentProcessor> inner;
reed856e9d92015-09-30 12:21:45 -0700227 if (doBicubic) {
Hal Canary67b39de2016-11-07 11:47:44 -0500228 inner = GrBicubicEffect::Make(texture.get(), std::move(colorSpaceXform), matrix, tm);
reed856e9d92015-09-30 12:21:45 -0700229 } else {
Hal Canary67b39de2016-11-07 11:47:44 -0500230 inner = GrSimpleTextureEffect::Make(texture.get(), std::move(colorSpaceXform),
231 matrix, params);
reed856e9d92015-09-30 12:21:45 -0700232 }
233
234 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bungeman06ca8ec2016-06-09 08:01:03 -0700235 return inner;
reed856e9d92015-09-30 12:21:45 -0700236 }
bungeman06ca8ec2016-06-09 08:01:03 -0700237 return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
reed856e9d92015-09-30 12:21:45 -0700238}
239
240#endif
reed320a40d2016-08-02 06:12:06 -0700241
242///////////////////////////////////////////////////////////////////////////////////////////////////
243#include "SkImagePriv.h"
244
245sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
246 SkShader::TileMode tmy, const SkMatrix* localMatrix,
reed1ec04d92016-08-05 12:07:41 -0700247 SkCopyPixelsMode cpm, SkTBlitterAllocator* allocator) {
248 // Until we learn otherwise, it seems that any caller that is passing an allocator must be
249 // assuming that the returned shader will have a stack-frame lifetime, so we assert that
250 // they are also asking for kNever_SkCopyPixelsMode. If that proves otherwise, we can remove
251 // or modify this assert.
252 SkASSERT(!allocator || (kNever_SkCopyPixelsMode == cpm));
253
reed6b2d7ac2016-08-11 06:42:26 -0700254 return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm, allocator),
reed320a40d2016-08-02 06:12:06 -0700255 tmx, tmy, localMatrix, allocator);
256}
257
258static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
259 SkMatrix lm;
260 buffer.readMatrix(&lm);
reeda9ca05c2016-08-11 03:55:15 -0700261 sk_sp<SkImage> image = buffer.readBitmapAsImage();
reed320a40d2016-08-02 06:12:06 -0700262 SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
263 SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
reeda9ca05c2016-08-11 03:55:15 -0700264 return image ? image->makeShader(mx, my, &lm) : nullptr;
reed320a40d2016-08-02 06:12:06 -0700265}
266
267SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
268SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
269SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
270SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
271
Mike Klein06a65e22016-11-17 12:39:09 -0500272
273bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkFallbackAlloc* scratch,
Mike Klein7a14734d2016-11-29 15:33:39 -0500274 const SkMatrix& ctm, const SkPaint& paint) const {
Mike Klein06a65e22016-11-17 12:39:09 -0500275 auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
276 if (!matrix.invert(&matrix)) {
277 return false;
278 }
Mike Klein7a14734d2016-11-29 15:33:39 -0500279 auto quality = paint.getFilterQuality();
Mike Klein06a65e22016-11-17 12:39:09 -0500280
Brian Osman61624f02016-12-09 14:51:59 -0500281 SkBitmapProvider provider(fImage.get(), dst);
Brian Osman13bf6222016-12-06 10:34:51 -0500282 SkDefaultBitmapController controller;
Mike Kleinf447dee2016-11-29 16:37:12 -0500283 std::unique_ptr<SkBitmapController::State> state {
284 controller.requestBitmap(provider, matrix, quality)
285 };
286 if (!state) {
287 return false;
288 }
289
290 const SkPixmap& pm = state->pixmap();
291 matrix = state->invMatrix();
292 quality = state->quality();
293 auto info = pm.info();
294
Mike Klein77760292016-11-17 14:04:22 -0500295 // When the matrix is just an integer translate, bilerp == nearest neighbor.
296 if (matrix.getType() <= SkMatrix::kTranslate_Mask &&
297 matrix.getTranslateX() == (int)matrix.getTranslateX() &&
298 matrix.getTranslateY() == (int)matrix.getTranslateY()) {
299 quality = kNone_SkFilterQuality;
300 }
301
Mike Kleinbf178a72016-11-17 15:56:24 -0500302 // See skia:4649 and the GM image_scale_aligned.
Mike Klein06a65e22016-11-17 12:39:09 -0500303 if (quality == kNone_SkFilterQuality) {
304 if (matrix.getScaleX() >= 0) {
305 matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
306 floorf(matrix.getTranslateX())));
307 }
308 if (matrix.getScaleY() >= 0) {
309 matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
310 floorf(matrix.getTranslateY())));
311 }
312 }
313
Mike Klein46e66a22016-11-21 16:19:34 -0500314 auto ctx = scratch->make<SkImageShaderContext>();
Mike Kleinf447dee2016-11-29 16:37:12 -0500315 ctx->state = std::move(state); // Extend lifetime to match the pipeline's.
Mike Klein7a14734d2016-11-29 15:33:39 -0500316 ctx->pixels = pm.addr();
317 ctx->ctable = pm.ctable();
318 ctx->color4f = SkColor4f_from_SkColor(paint.getColor(), dst);
319 ctx->stride = pm.rowBytesAsPixels();
320 ctx->width = pm.width();
321 ctx->height = pm.height();
Mike Kleinc01e7df2016-11-17 16:27:10 -0500322 if (matrix.asAffine(ctx->matrix)) {
323 p->append(SkRasterPipeline::matrix_2x3, ctx->matrix);
324 } else {
325 matrix.get9(ctx->matrix);
326 p->append(SkRasterPipeline::matrix_perspective, ctx->matrix);
327 }
Mike Klein06a65e22016-11-17 12:39:09 -0500328
Mike Kleinb04c3522016-11-28 11:55:58 -0500329 auto append_tiling_and_gather = [&] {
Mike Kleinf7f883b2016-11-21 15:09:45 -0500330 switch (fTileModeX) {
331 case kClamp_TileMode: p->append(SkRasterPipeline::clamp_x, &ctx->width); break;
332 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, &ctx->width); break;
333 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, &ctx->width); break;
334 }
335 switch (fTileModeY) {
336 case kClamp_TileMode: p->append(SkRasterPipeline::clamp_y, &ctx->height); break;
337 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, &ctx->height); break;
338 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &ctx->height); break;
339 }
Mike Kleinf7f883b2016-11-21 15:09:45 -0500340 switch (info.colorType()) {
Mike Klein7a14734d2016-11-29 15:33:39 -0500341 case kAlpha_8_SkColorType: p->append(SkRasterPipeline::gather_a8, ctx); break;
Mike Kleinf7657e92016-11-29 12:57:22 -0500342 case kIndex_8_SkColorType: p->append(SkRasterPipeline::gather_i8, ctx); break;
Mike Kleinb04c3522016-11-28 11:55:58 -0500343 case kGray_8_SkColorType: p->append(SkRasterPipeline::gather_g8, ctx); break;
344 case kRGB_565_SkColorType: p->append(SkRasterPipeline::gather_565, ctx); break;
345 case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, ctx); break;
Mike Kleinf7f883b2016-11-21 15:09:45 -0500346 case kRGBA_8888_SkColorType:
Mike Kleinb04c3522016-11-28 11:55:58 -0500347 case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx); break;
348 case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::gather_f16, ctx); break;
349 default: SkASSERT(false);
350 }
351 if (info.gammaCloseToSRGB() && dst != nullptr) {
Mike Klein729b5822016-11-28 18:23:23 -0500352 p->append(SkRasterPipeline::from_srgb);
Mike Kleinf7f883b2016-11-21 15:09:45 -0500353 }
354 };
355
Mike Klein886cf532016-12-06 11:31:25 -0500356 auto sample = [&](SkRasterPipeline::StockStage sampler) {
357 p->append(sampler, ctx);
358 append_tiling_and_gather();
359 p->append(SkRasterPipeline::accumulate, ctx);
360 };
361
Mike Kleinf7f883b2016-11-21 15:09:45 -0500362 if (quality == kNone_SkFilterQuality) {
Mike Kleinb04c3522016-11-28 11:55:58 -0500363 append_tiling_and_gather();
Mike Klein46e66a22016-11-21 16:19:34 -0500364 } else {
Mike Klein886cf532016-12-06 11:31:25 -0500365 p->append(SkRasterPipeline::save_xy, ctx);
366 sample(SkRasterPipeline::bilinear_nn);
367 sample(SkRasterPipeline::bilinear_np);
368 sample(SkRasterPipeline::bilinear_pn);
369 sample(SkRasterPipeline::bilinear_pp);
Mike Kleinb04c3522016-11-28 11:55:58 -0500370 p->append(SkRasterPipeline::move_dst_src);
Mike Klein06a65e22016-11-17 12:39:09 -0500371 }
372
Mike Kleinf7657e92016-11-29 12:57:22 -0500373 auto effective_color_type = [](SkColorType ct) {
374 return ct == kIndex_8_SkColorType ? kN32_SkColorType : ct;
375 };
376
377 if (effective_color_type(info.colorType()) == kBGRA_8888_SkColorType) {
Mike Klein06a65e22016-11-17 12:39:09 -0500378 p->append(SkRasterPipeline::swap_rb);
379 }
Mike Klein7a14734d2016-11-29 15:33:39 -0500380 if (info.colorType() == kAlpha_8_SkColorType) {
381 p->append(SkRasterPipeline::set_rgb, &ctx->color4f);
382 }
383 if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) {
Mike Klein06a65e22016-11-17 12:39:09 -0500384 p->append(SkRasterPipeline::premul);
385 }
386 return append_gamut_transform(p, scratch, info.colorSpace(), dst);
387}