blob: 42f5c3e497e597d36f561944a798c96a72296636 [file] [log] [blame]
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +00001/*
2 * Copyright 2014 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 "SkPictureShader.h"
9
Yuqian Li8d2fb472017-01-30 11:33:46 -050010#include "SkArenaAlloc.h"
robertphillips25a5b0d2015-09-28 09:32:50 -070011#include "SkBitmap.h"
12#include "SkBitmapProcShader.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000013#include "SkCanvas.h"
Matt Sarett28a7ad22017-04-21 15:12:34 -040014#include "SkColorSpaceXformCanvas.h"
fmalita1b46a572016-02-01 02:34:03 -080015#include "SkImage.h"
fmalitac9a9ca92016-10-12 13:43:43 -070016#include "SkImageShader.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000017#include "SkMatrixUtils.h"
Mike Klein88d90712018-01-27 17:30:04 +000018#include "SkPicture.h"
Matt Sarett9df70bb2017-02-14 13:50:43 -050019#include "SkPictureImageGenerator.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000020#include "SkReadBuffer.h"
fmalita23df2d62014-10-22 07:39:08 -070021#include "SkResourceCache.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000022
23#if SK_SUPPORT_GPU
bsalomon76228632015-05-29 08:02:10 -070024#include "GrCaps.h"
Brian Salomon4cbb6e62017-10-25 15:12:19 -040025#include "GrColorSpaceInfo.h"
26#include "GrContext.h"
Mike Reed84dd8572017-03-08 22:21:00 -050027#include "GrFragmentProcessor.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000028#endif
29
fmalita171e5b72014-10-22 11:20:40 -070030namespace {
31static unsigned gBitmapSkaderKeyNamespaceLabel;
32
fmalita23df2d62014-10-22 07:39:08 -070033struct BitmapShaderKey : public SkResourceCache::Key {
34public:
Matt Sarette71db442017-04-21 15:06:51 -040035 BitmapShaderKey(sk_sp<SkColorSpace> colorSpace,
Florin Malitab00a3602017-07-13 22:34:04 -040036 uint32_t shaderID,
fmalita23df2d62014-10-22 07:39:08 -070037 const SkRect& tile,
38 SkShader::TileMode tmx,
39 SkShader::TileMode tmy,
40 const SkSize& scale,
Matt Sarett28a7ad22017-04-21 15:12:34 -040041 SkTransferFunctionBehavior blendBehavior)
Matt Sarette71db442017-04-21 15:06:51 -040042 : fColorSpace(std::move(colorSpace))
fmalita23df2d62014-10-22 07:39:08 -070043 , fTile(tile)
44 , fTmx(tmx)
45 , fTmy(tmy)
Matt Sarett28a7ad22017-04-21 15:12:34 -040046 , fScale(scale)
47 , fBlendBehavior(blendBehavior) {
fmalita04b49c32014-12-10 13:01:43 -080048
Matt Sarette71db442017-04-21 15:06:51 -040049 static const size_t keySize = sizeof(fColorSpace) +
fmalita23df2d62014-10-22 07:39:08 -070050 sizeof(fTile) +
51 sizeof(fTmx) + sizeof(fTmy) +
52 sizeof(fScale) +
Matt Sarett28a7ad22017-04-21 15:12:34 -040053 sizeof(fBlendBehavior);
fmalita23df2d62014-10-22 07:39:08 -070054 // This better be packed.
Matt Sarette71db442017-04-21 15:06:51 -040055 SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - (uint32_t*)&fColorSpace) == keySize);
Florin Malitab00a3602017-07-13 22:34:04 -040056 this->init(&gBitmapSkaderKeyNamespaceLabel, MakeSharedID(shaderID), keySize);
57 }
58
59 static uint64_t MakeSharedID(uint32_t shaderID) {
60 uint64_t sharedID = SkSetFourByteTag('p', 's', 'd', 'r');
61 return (sharedID << 32) | shaderID;
fmalita23df2d62014-10-22 07:39:08 -070062 }
63
64private:
Florin Malitab00a3602017-07-13 22:34:04 -040065 // TODO: there are some fishy things about using CS sk_sps in the key:
66 // - false negatives: keys are memcmp'ed, so we don't detect equivalent CSs
67 // (SkColorspace::Equals)
68 // - we're keeping the CS alive, even when the client releases it
69 //
70 // Ideally we'd be using unique IDs or some other weak ref + purge mechanism
71 // when the CS is deleted.
Matt Sarett28a7ad22017-04-21 15:12:34 -040072 sk_sp<SkColorSpace> fColorSpace;
Matt Sarett28a7ad22017-04-21 15:12:34 -040073 SkRect fTile;
74 SkShader::TileMode fTmx, fTmy;
75 SkSize fScale;
Matt Sarett28a7ad22017-04-21 15:12:34 -040076 SkTransferFunctionBehavior fBlendBehavior;
fmalita23df2d62014-10-22 07:39:08 -070077
78 SkDEBUGCODE(uint32_t fEndOfStruct;)
79};
80
81struct BitmapShaderRec : public SkResourceCache::Rec {
fmalitac9a9ca92016-10-12 13:43:43 -070082 BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader)
fmalita23df2d62014-10-22 07:39:08 -070083 : fKey(key)
fmalitac9a9ca92016-10-12 13:43:43 -070084 , fShader(SkRef(tileShader)) {}
fmalita23df2d62014-10-22 07:39:08 -070085
Hal Canary704cd322016-11-07 14:13:52 -050086 BitmapShaderKey fKey;
87 sk_sp<SkShader> fShader;
fmalita23df2d62014-10-22 07:39:08 -070088
mtklein36352bf2015-03-25 18:17:31 -070089 const Key& getKey() const override { return fKey; }
90 size_t bytesUsed() const override {
fmalitac9a9ca92016-10-12 13:43:43 -070091 // Just the record overhead -- the actual pixels are accounted by SkImageCacherator.
92 return sizeof(fKey) + sizeof(SkImageShader);
fmalita23df2d62014-10-22 07:39:08 -070093 }
reed216b6432015-08-19 12:25:40 -070094 const char* getCategory() const override { return "bitmap-shader"; }
95 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
fmalita23df2d62014-10-22 07:39:08 -070096
97 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
98 const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
Hal Canary704cd322016-11-07 14:13:52 -050099 sk_sp<SkShader>* result = reinterpret_cast<sk_sp<SkShader>*>(contextShader);
fmalita23df2d62014-10-22 07:39:08 -0700100
Hal Canary704cd322016-11-07 14:13:52 -0500101 *result = rec.fShader;
fmalita387a01a2014-12-10 12:17:58 -0800102
fmalitaddc4b462015-08-31 19:54:03 -0700103 // The bitmap shader is backed by an image generator, thus it can always re-generate its
104 // pixels if discarded.
105 return true;
fmalita23df2d62014-10-22 07:39:08 -0700106 }
107};
108
Florin Malitab00a3602017-07-13 22:34:04 -0400109static int32_t gNextID = 1;
110uint32_t next_id() {
111 int32_t id;
112 do {
113 id = sk_atomic_inc(&gNextID);
114 } while (id == SK_InvalidGenID);
115 return static_cast<uint32_t>(id);
116}
117
fmalita171e5b72014-10-22 11:20:40 -0700118} // namespace
119
reed7fb4f8b2016-03-11 04:33:52 -0800120SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
Matt Sarett28a7ad22017-04-21 15:12:34 -0400121 const SkMatrix* localMatrix, const SkRect* tile,
122 sk_sp<SkColorSpace> colorSpace)
commit-bot@chromium.org5aacfe92014-05-02 21:23:52 +0000123 : INHERITED(localMatrix)
reed8a21c9f2016-03-08 18:50:00 -0800124 , fPicture(std::move(picture))
125 , fTile(tile ? *tile : fPicture->cullRect())
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000126 , fTmx(tmx)
Matt Sarett28a7ad22017-04-21 15:12:34 -0400127 , fTmy(tmy)
128 , fColorSpace(std::move(colorSpace))
Florin Malitab00a3602017-07-13 22:34:04 -0400129 , fUniqueID(next_id())
130 , fAddedToCache(false) {}
131
132SkPictureShader::~SkPictureShader() {
133 if (fAddedToCache.load()) {
134 SkResourceCache::PostPurgeSharedID(BitmapShaderKey::MakeSharedID(fUniqueID));
135 }
136}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000137
reed7fb4f8b2016-03-11 04:33:52 -0800138sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
reed8a21c9f2016-03-08 18:50:00 -0800139 const SkMatrix* localMatrix, const SkRect* tile) {
Robert Phillips54be5c92017-02-11 01:19:30 +0000140 if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
reed8a21c9f2016-03-08 18:50:00 -0800141 return SkShader::MakeEmptyShader();
commit-bot@chromium.org855e88e2014-04-21 19:33:12 +0000142 }
Matt Sarett28a7ad22017-04-21 15:12:34 -0400143 return sk_sp<SkShader>(new SkPictureShader(std::move(picture), tmx, tmy, localMatrix, tile,
144 nullptr));
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000145}
146
reed60c9b582016-04-03 09:11:13 -0700147sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700148 SkMatrix lm;
149 buffer.readMatrix(&lm);
150 TileMode mx = (TileMode)buffer.read32();
151 TileMode my = (TileMode)buffer.read32();
152 SkRect tile;
153 buffer.readRect(&tile);
mtklein76be9c82015-05-20 12:05:15 -0700154
reed8a21c9f2016-03-08 18:50:00 -0800155 sk_sp<SkPicture> picture;
hendrikw446ee672015-06-16 09:28:37 -0700156
Mike Reed5a0f3452018-01-19 08:25:11 -0500157 bool didSerialize = buffer.readBool();
158 if (didSerialize) {
159 picture = SkPicture::MakeFromBuffer(buffer);
mtklein76be9c82015-05-20 12:05:15 -0700160 }
reed60c9b582016-04-03 09:11:13 -0700161 return SkPictureShader::Make(picture, mx, my, &lm, &tile);
reed9fa60da2014-08-21 07:59:51 -0700162}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000163
reed9fa60da2014-08-21 07:59:51 -0700164void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
165 buffer.writeMatrix(this->getLocalMatrix());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000166 buffer.write32(fTmx);
167 buffer.write32(fTmy);
fmalitab5f78262014-08-06 13:07:15 -0700168 buffer.writeRect(fTile);
mtklein76be9c82015-05-20 12:05:15 -0700169
Mike Reed5a0f3452018-01-19 08:25:11 -0500170 buffer.writeBool(true);
Mike Klein88d90712018-01-27 17:30:04 +0000171 fPicture->flatten(buffer);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000172}
173
Florin Malita8f88d892018-04-19 21:07:19 -0400174// Returns a cached image shader, which wraps a single picture tile at the given
175// CTM/local matrix. Also adjusts the local matrix for tile scaling.
Florin Malita18f7e0a2018-02-06 16:49:40 -0500176sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix,
Florin Malita8f88d892018-04-19 21:07:19 -0400177 SkTCopyOnFirstWrite<SkMatrix>* localMatrix,
Brian Osman138ea972016-12-16 11:55:18 -0500178 SkColorSpace* dstColorSpace,
reed8a21c9f2016-03-08 18:50:00 -0800179 const int maxTextureSize) const {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700180 SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000181
Florin Malita8f88d892018-04-19 21:07:19 -0400182 const SkMatrix m = SkMatrix::Concat(viewMatrix, **localMatrix);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000183
184 // Use a rotation-invariant scale
185 SkPoint scale;
reedadf99902015-03-19 16:10:54 -0700186 //
187 // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines!
188 //
halcanary96fcdcc2015-08-27 07:41:13 -0700189 if (!SkDecomposeUpper2x2(m, nullptr, &scale, nullptr)) {
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000190 // Decomposition failed, use an approximation.
191 scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
192 SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
193 }
fmalitab0878792015-01-15 10:45:56 -0800194 SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * fTile.width()),
195 SkScalarAbs(scale.y() * fTile.height()));
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000196
fmalita511005b2015-03-13 06:50:44 -0700197 // Clamp the tile size to about 4M pixels
198 static const SkScalar kMaxTileArea = 2048 * 2048;
Mike Reeda99b6ce2017-02-04 11:04:26 -0500199 SkScalar tileArea = scaledSize.width() * scaledSize.height();
fmalitabb204f42014-08-07 08:39:24 -0700200 if (tileArea > kMaxTileArea) {
reed80ea19c2015-05-12 10:37:34 -0700201 SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
Mike Reeda99b6ce2017-02-04 11:04:26 -0500202 scaledSize.set(scaledSize.width() * clampScale,
203 scaledSize.height() * clampScale);
fmalitabb204f42014-08-07 08:39:24 -0700204 }
gen.kimb9ed8842015-05-03 22:36:30 -0700205#if SK_SUPPORT_GPU
206 // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture
207 if (maxTextureSize) {
208 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
ericrkf469fc02015-10-14 17:33:29 -0700209 SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height());
Mike Reeda99b6ce2017-02-04 11:04:26 -0500210 scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale),
211 SkScalarFloorToScalar(scaledSize.height() * downScale));
gen.kimb9ed8842015-05-03 22:36:30 -0700212 }
213 }
214#endif
fmalitabb204f42014-08-07 08:39:24 -0700215
fmalita85c6f982016-02-29 09:18:31 -0800216 const SkISize tileSize = scaledSize.toCeil();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000217 if (tileSize.isEmpty()) {
reed8a21c9f2016-03-08 18:50:00 -0800218 return SkShader::MakeEmptyShader();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000219 }
220
fmalitabb204f42014-08-07 08:39:24 -0700221 // The actual scale, compensating for rounding & clamping.
fmalita85c6f982016-02-29 09:18:31 -0800222 const SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
223 SkIntToScalar(tileSize.height()) / fTile.height());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000224
Matt Sarett28a7ad22017-04-21 15:12:34 -0400225 // |fColorSpace| will only be set when using an SkColorSpaceXformCanvas to do pre-draw xforms.
226 // This canvas is strictly for legacy mode. A non-null |dstColorSpace| indicates that we
227 // should perform color correct rendering and xform at draw time.
228 SkASSERT(!fColorSpace || !dstColorSpace);
229 sk_sp<SkColorSpace> keyCS = dstColorSpace ? sk_ref_sp(dstColorSpace) : fColorSpace;
230 SkTransferFunctionBehavior blendBehavior = dstColorSpace ? SkTransferFunctionBehavior::kRespect
231 : SkTransferFunctionBehavior::kIgnore;
232
reed8a21c9f2016-03-08 18:50:00 -0800233 sk_sp<SkShader> tileShader;
Matt Sarett28a7ad22017-04-21 15:12:34 -0400234 BitmapShaderKey key(std::move(keyCS),
Florin Malitab00a3602017-07-13 22:34:04 -0400235 fUniqueID,
fmalita23df2d62014-10-22 07:39:08 -0700236 fTile,
237 fTmx,
238 fTmy,
239 tileScale,
Matt Sarett28a7ad22017-04-21 15:12:34 -0400240 blendBehavior);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000241
fmalita171e5b72014-10-22 11:20:40 -0700242 if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
robertphillips25a5b0d2015-09-28 09:32:50 -0700243 SkMatrix tileMatrix;
244 tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()),
fmalita1b46a572016-02-01 02:34:03 -0800245 SkMatrix::kFill_ScaleToFit);
246
Matt Sarett9df70bb2017-02-14 13:50:43 -0500247 sk_sp<SkImage> tileImage = SkImage::MakeFromGenerator(
Mike Reed185130c2017-02-15 15:14:16 -0500248 SkPictureImageGenerator::Make(tileSize, fPicture, &tileMatrix, nullptr,
249 SkImage::BitDepth::kU8, sk_ref_sp(dstColorSpace)));
fmalita1b46a572016-02-01 02:34:03 -0800250 if (!tileImage) {
fmalitaddc4b462015-08-31 19:54:03 -0700251 return nullptr;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000252 }
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000253
Matt Sarett28a7ad22017-04-21 15:12:34 -0400254 if (fColorSpace) {
255 tileImage = tileImage->makeColorSpace(fColorSpace, SkTransferFunctionBehavior::kIgnore);
256 }
257
Florin Malita18f7e0a2018-02-06 16:49:40 -0500258 tileShader = tileImage->makeShader(fTmx, fTmy);
fmalita23df2d62014-10-22 07:39:08 -0700259
fmalitac9a9ca92016-10-12 13:43:43 -0700260 SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
Florin Malitab00a3602017-07-13 22:34:04 -0400261 fAddedToCache.store(true);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000262 }
263
Florin Malita8f88d892018-04-19 21:07:19 -0400264 if (tileScale.width() != 1 || tileScale.height() != 1) {
265 localMatrix->writable()->preScale(1 / tileScale.width(), 1 / tileScale.height());
266 }
Florin Malita18f7e0a2018-02-06 16:49:40 -0500267
reed8a21c9f2016-03-08 18:50:00 -0800268 return tileShader;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000269}
270
Mike Reed1d8c42e2017-08-29 14:58:19 -0400271bool SkPictureShader::onAppendStages(const StageRec& rec) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -0400272 auto lm = this->totalLocalMatrix(rec.fLocalM);
Florin Malitac6c5ead2018-04-11 15:33:40 -0400273
Yuqian Li8d2fb472017-01-30 11:33:46 -0500274 // Keep bitmapShader alive by using alloc instead of stack memory
Mike Reed1d8c42e2017-08-29 14:58:19 -0400275 auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
Florin Malita8f88d892018-04-19 21:07:19 -0400276 bitmapShader = this->refBitmapShader(rec.fCTM, &lm, rec.fDstCS);
Florin Malitac6c5ead2018-04-11 15:33:40 -0400277
278 if (!bitmapShader) {
279 return false;
280 }
281
Florin Malita18f7e0a2018-02-06 16:49:40 -0500282 StageRec localRec = rec;
Florin Malitac6c5ead2018-04-11 15:33:40 -0400283 localRec.fLocalM = lm->isIdentity() ? nullptr : lm.get();
Florin Malita18f7e0a2018-02-06 16:49:40 -0500284
Florin Malitac6c5ead2018-04-11 15:33:40 -0400285 return as_SB(bitmapShader)->appendStages(localRec);
Yuqian Li8d2fb472017-01-30 11:33:46 -0500286}
287
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000288/////////////////////////////////////////////////////////////////////////////////////////
Florin Malita4aed1382017-05-25 10:38:07 -0400289SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
Herb Derby83e939b2017-02-07 14:25:11 -0500290const {
Florin Malitac6c5ead2018-04-11 15:33:40 -0400291 auto lm = this->totalLocalMatrix(rec.fLocalMatrix);
Florin Malita8f88d892018-04-19 21:07:19 -0400292 sk_sp<SkShader> bitmapShader = this->refBitmapShader(*rec.fMatrix, &lm, rec.fDstColorSpace);
Herb Derby83e939b2017-02-07 14:25:11 -0500293 if (!bitmapShader) {
294 return nullptr;
295 }
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000296
Florin Malita18f7e0a2018-02-06 16:49:40 -0500297 ContextRec localRec = rec;
Florin Malitac6c5ead2018-04-11 15:33:40 -0400298 localRec.fLocalMatrix = lm->isIdentity() ? nullptr : lm.get();
Florin Malita18f7e0a2018-02-06 16:49:40 -0500299
Herb Derby83e939b2017-02-07 14:25:11 -0500300 PictureShaderContext* ctx =
Florin Malita18f7e0a2018-02-06 16:49:40 -0500301 alloc->make<PictureShaderContext>(*this, localRec, std::move(bitmapShader), alloc);
halcanary96fcdcc2015-08-27 07:41:13 -0700302 if (nullptr == ctx->fBitmapShaderContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700303 ctx = nullptr;
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000304 }
305 return ctx;
306}
307
Matt Sarett28a7ad22017-04-21 15:12:34 -0400308sk_sp<SkShader> SkPictureShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Florin Malita604f0d52017-07-13 14:29:12 -0400309 sk_sp<SkColorSpace> dstCS = xformer->dst();
310 if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
311 return sk_ref_sp(const_cast<SkPictureShader*>(this));
312 }
313
Matt Sarett28a7ad22017-04-21 15:12:34 -0400314 return sk_sp<SkPictureShader>(new SkPictureShader(fPicture, fTmx, fTmy, &this->getLocalMatrix(),
Florin Malita604f0d52017-07-13 14:29:12 -0400315 &fTile, std::move(dstCS)));
Matt Sarett28a7ad22017-04-21 15:12:34 -0400316}
317
Herb Derby83e939b2017-02-07 14:25:11 -0500318/////////////////////////////////////////////////////////////////////////////////////////
319
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000320SkPictureShader::PictureShaderContext::PictureShaderContext(
Herb Derby83e939b2017-02-07 14:25:11 -0500321 const SkPictureShader& shader, const ContextRec& rec, sk_sp<SkShader> bitmapShader,
322 SkArenaAlloc* alloc)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000323 : INHERITED(shader, rec)
reed8a21c9f2016-03-08 18:50:00 -0800324 , fBitmapShader(std::move(bitmapShader))
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000325{
Florin Malita4aed1382017-05-25 10:38:07 -0400326 fBitmapShaderContext = as_SB(fBitmapShader)->makeContext(rec, alloc);
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000327 //if fBitmapShaderContext is null, we are invalid
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000328}
329
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000330uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000331 SkASSERT(fBitmapShaderContext);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000332 return fBitmapShaderContext->getFlags();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000333}
334
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000335void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
336 SkASSERT(fBitmapShaderContext);
337 fBitmapShaderContext->shadeSpan(x, y, dstC, count);
338}
339
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000340void SkPictureShader::toString(SkString* str) const {
341 static const char* gTileModeName[SkShader::kTileModeCount] = {
342 "clamp", "repeat", "mirror"
343 };
344
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700345 str->appendf("PictureShader: [%f:%f:%f:%f] ",
fmalitaddc4b462015-08-31 19:54:03 -0700346 fPicture->cullRect().fLeft,
347 fPicture->cullRect().fTop,
348 fPicture->cullRect().fRight,
349 fPicture->cullRect().fBottom);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000350
351 str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
352
353 this->INHERITED::toString(str);
354}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000355
356#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400357std::unique_ptr<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -0500358 const GrFPArgs& args) const {
gen.kimb9ed8842015-05-03 22:36:30 -0700359 int maxTextureSize = 0;
brianosman839345d2016-07-22 11:04:53 -0700360 if (args.fContext) {
361 maxTextureSize = args.fContext->caps()->maxTextureSize();
gen.kimb9ed8842015-05-03 22:36:30 -0700362 }
Florin Malitac6c5ead2018-04-11 15:33:40 -0400363
364 auto lm = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
Florin Malita8f88d892018-04-19 21:07:19 -0400365 sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, &lm,
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400366 args.fDstColorSpaceInfo->colorSpace(),
Florin Malita8f88d892018-04-19 21:07:19 -0400367 maxTextureSize));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000368 if (!bitmapShader) {
bsalomonc21b09e2015-08-28 18:46:56 -0700369 return nullptr;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000370 }
Florin Malita18f7e0a2018-02-06 16:49:40 -0500371
Florin Malitac6c5ead2018-04-11 15:33:40 -0400372 // We want to *reset* args.fPreLocalMatrix, not compose it.
373 GrFPArgs newArgs(args.fContext, args.fViewMatrix, args.fFilterQuality, args.fDstColorSpaceInfo);
374 newArgs.fPreLocalMatrix = lm.get();
375
376 return as_SB(bitmapShader)->asFragmentProcessor(newArgs);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000377}
378#endif