blob: f958814ca18f5dec03736a5052e007dda4e40238 [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"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040027#include "GrContextPriv.h"
Mike Reed84dd8572017-03-08 22:21:00 -050028#include "GrFragmentProcessor.h"
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000029#endif
30
fmalita171e5b72014-10-22 11:20:40 -070031namespace {
32static unsigned gBitmapSkaderKeyNamespaceLabel;
33
fmalita23df2d62014-10-22 07:39:08 -070034struct BitmapShaderKey : public SkResourceCache::Key {
35public:
Matt Sarette71db442017-04-21 15:06:51 -040036 BitmapShaderKey(sk_sp<SkColorSpace> colorSpace,
Florin Malitab00a3602017-07-13 22:34:04 -040037 uint32_t shaderID,
fmalita23df2d62014-10-22 07:39:08 -070038 const SkRect& tile,
39 SkShader::TileMode tmx,
40 SkShader::TileMode tmy,
41 const SkSize& scale,
Matt Sarett28a7ad22017-04-21 15:12:34 -040042 SkTransferFunctionBehavior blendBehavior)
Matt Sarette71db442017-04-21 15:06:51 -040043 : fColorSpace(std::move(colorSpace))
fmalita23df2d62014-10-22 07:39:08 -070044 , fTile(tile)
45 , fTmx(tmx)
46 , fTmy(tmy)
Matt Sarett28a7ad22017-04-21 15:12:34 -040047 , fScale(scale)
48 , fBlendBehavior(blendBehavior) {
fmalita04b49c32014-12-10 13:01:43 -080049
Matt Sarette71db442017-04-21 15:06:51 -040050 static const size_t keySize = sizeof(fColorSpace) +
fmalita23df2d62014-10-22 07:39:08 -070051 sizeof(fTile) +
52 sizeof(fTmx) + sizeof(fTmy) +
53 sizeof(fScale) +
Matt Sarett28a7ad22017-04-21 15:12:34 -040054 sizeof(fBlendBehavior);
fmalita23df2d62014-10-22 07:39:08 -070055 // This better be packed.
Matt Sarette71db442017-04-21 15:06:51 -040056 SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - (uint32_t*)&fColorSpace) == keySize);
Florin Malitab00a3602017-07-13 22:34:04 -040057 this->init(&gBitmapSkaderKeyNamespaceLabel, MakeSharedID(shaderID), keySize);
58 }
59
60 static uint64_t MakeSharedID(uint32_t shaderID) {
61 uint64_t sharedID = SkSetFourByteTag('p', 's', 'd', 'r');
62 return (sharedID << 32) | shaderID;
fmalita23df2d62014-10-22 07:39:08 -070063 }
64
65private:
Florin Malitab00a3602017-07-13 22:34:04 -040066 // TODO: there are some fishy things about using CS sk_sps in the key:
67 // - false negatives: keys are memcmp'ed, so we don't detect equivalent CSs
68 // (SkColorspace::Equals)
69 // - we're keeping the CS alive, even when the client releases it
70 //
71 // Ideally we'd be using unique IDs or some other weak ref + purge mechanism
72 // when the CS is deleted.
Matt Sarett28a7ad22017-04-21 15:12:34 -040073 sk_sp<SkColorSpace> fColorSpace;
Matt Sarett28a7ad22017-04-21 15:12:34 -040074 SkRect fTile;
75 SkShader::TileMode fTmx, fTmy;
76 SkSize fScale;
Matt Sarett28a7ad22017-04-21 15:12:34 -040077 SkTransferFunctionBehavior fBlendBehavior;
fmalita23df2d62014-10-22 07:39:08 -070078
79 SkDEBUGCODE(uint32_t fEndOfStruct;)
80};
81
82struct BitmapShaderRec : public SkResourceCache::Rec {
fmalitac9a9ca92016-10-12 13:43:43 -070083 BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader)
fmalita23df2d62014-10-22 07:39:08 -070084 : fKey(key)
fmalitac9a9ca92016-10-12 13:43:43 -070085 , fShader(SkRef(tileShader)) {}
fmalita23df2d62014-10-22 07:39:08 -070086
Hal Canary704cd322016-11-07 14:13:52 -050087 BitmapShaderKey fKey;
88 sk_sp<SkShader> fShader;
fmalita23df2d62014-10-22 07:39:08 -070089
mtklein36352bf2015-03-25 18:17:31 -070090 const Key& getKey() const override { return fKey; }
91 size_t bytesUsed() const override {
fmalitac9a9ca92016-10-12 13:43:43 -070092 // Just the record overhead -- the actual pixels are accounted by SkImageCacherator.
93 return sizeof(fKey) + sizeof(SkImageShader);
fmalita23df2d62014-10-22 07:39:08 -070094 }
reed216b6432015-08-19 12:25:40 -070095 const char* getCategory() const override { return "bitmap-shader"; }
96 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
fmalita23df2d62014-10-22 07:39:08 -070097
98 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
99 const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
Hal Canary704cd322016-11-07 14:13:52 -0500100 sk_sp<SkShader>* result = reinterpret_cast<sk_sp<SkShader>*>(contextShader);
fmalita23df2d62014-10-22 07:39:08 -0700101
Hal Canary704cd322016-11-07 14:13:52 -0500102 *result = rec.fShader;
fmalita387a01a2014-12-10 12:17:58 -0800103
fmalitaddc4b462015-08-31 19:54:03 -0700104 // The bitmap shader is backed by an image generator, thus it can always re-generate its
105 // pixels if discarded.
106 return true;
fmalita23df2d62014-10-22 07:39:08 -0700107 }
108};
109
Florin Malitab00a3602017-07-13 22:34:04 -0400110static int32_t gNextID = 1;
111uint32_t next_id() {
112 int32_t id;
113 do {
114 id = sk_atomic_inc(&gNextID);
115 } while (id == SK_InvalidGenID);
116 return static_cast<uint32_t>(id);
117}
118
fmalita171e5b72014-10-22 11:20:40 -0700119} // namespace
120
reed7fb4f8b2016-03-11 04:33:52 -0800121SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
Matt Sarett28a7ad22017-04-21 15:12:34 -0400122 const SkMatrix* localMatrix, const SkRect* tile,
123 sk_sp<SkColorSpace> colorSpace)
commit-bot@chromium.org5aacfe92014-05-02 21:23:52 +0000124 : INHERITED(localMatrix)
reed8a21c9f2016-03-08 18:50:00 -0800125 , fPicture(std::move(picture))
126 , fTile(tile ? *tile : fPicture->cullRect())
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000127 , fTmx(tmx)
Matt Sarett28a7ad22017-04-21 15:12:34 -0400128 , fTmy(tmy)
129 , fColorSpace(std::move(colorSpace))
Florin Malitab00a3602017-07-13 22:34:04 -0400130 , fUniqueID(next_id())
131 , fAddedToCache(false) {}
132
133SkPictureShader::~SkPictureShader() {
134 if (fAddedToCache.load()) {
135 SkResourceCache::PostPurgeSharedID(BitmapShaderKey::MakeSharedID(fUniqueID));
136 }
137}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000138
reed7fb4f8b2016-03-11 04:33:52 -0800139sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, TileMode tmx, TileMode tmy,
reed8a21c9f2016-03-08 18:50:00 -0800140 const SkMatrix* localMatrix, const SkRect* tile) {
Robert Phillips54be5c92017-02-11 01:19:30 +0000141 if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
reed8a21c9f2016-03-08 18:50:00 -0800142 return SkShader::MakeEmptyShader();
commit-bot@chromium.org855e88e2014-04-21 19:33:12 +0000143 }
Matt Sarett28a7ad22017-04-21 15:12:34 -0400144 return sk_sp<SkShader>(new SkPictureShader(std::move(picture), tmx, tmy, localMatrix, tile,
145 nullptr));
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000146}
147
reed60c9b582016-04-03 09:11:13 -0700148sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700149 SkMatrix lm;
150 buffer.readMatrix(&lm);
151 TileMode mx = (TileMode)buffer.read32();
152 TileMode my = (TileMode)buffer.read32();
153 SkRect tile;
154 buffer.readRect(&tile);
mtklein76be9c82015-05-20 12:05:15 -0700155
reed8a21c9f2016-03-08 18:50:00 -0800156 sk_sp<SkPicture> picture;
hendrikw446ee672015-06-16 09:28:37 -0700157
Mike Reed5a0f3452018-01-19 08:25:11 -0500158 bool didSerialize = buffer.readBool();
159 if (didSerialize) {
160 picture = SkPicture::MakeFromBuffer(buffer);
mtklein76be9c82015-05-20 12:05:15 -0700161 }
reed60c9b582016-04-03 09:11:13 -0700162 return SkPictureShader::Make(picture, mx, my, &lm, &tile);
reed9fa60da2014-08-21 07:59:51 -0700163}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000164
reed9fa60da2014-08-21 07:59:51 -0700165void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
166 buffer.writeMatrix(this->getLocalMatrix());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000167 buffer.write32(fTmx);
168 buffer.write32(fTmy);
fmalitab5f78262014-08-06 13:07:15 -0700169 buffer.writeRect(fTile);
mtklein76be9c82015-05-20 12:05:15 -0700170
Mike Reed5a0f3452018-01-19 08:25:11 -0500171 buffer.writeBool(true);
Mike Klein88d90712018-01-27 17:30:04 +0000172 fPicture->flatten(buffer);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000173}
174
Florin Malita8f88d892018-04-19 21:07:19 -0400175// Returns a cached image shader, which wraps a single picture tile at the given
176// CTM/local matrix. Also adjusts the local matrix for tile scaling.
Florin Malita18f7e0a2018-02-06 16:49:40 -0500177sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix,
Florin Malita8f88d892018-04-19 21:07:19 -0400178 SkTCopyOnFirstWrite<SkMatrix>* localMatrix,
Brian Osman138ea972016-12-16 11:55:18 -0500179 SkColorSpace* dstColorSpace,
reed8a21c9f2016-03-08 18:50:00 -0800180 const int maxTextureSize) const {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700181 SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000182
Florin Malita8f88d892018-04-19 21:07:19 -0400183 const SkMatrix m = SkMatrix::Concat(viewMatrix, **localMatrix);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000184
185 // Use a rotation-invariant scale
186 SkPoint scale;
reedadf99902015-03-19 16:10:54 -0700187 //
188 // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines!
189 //
halcanary96fcdcc2015-08-27 07:41:13 -0700190 if (!SkDecomposeUpper2x2(m, nullptr, &scale, nullptr)) {
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000191 // Decomposition failed, use an approximation.
192 scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
193 SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
194 }
fmalitab0878792015-01-15 10:45:56 -0800195 SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * fTile.width()),
196 SkScalarAbs(scale.y() * fTile.height()));
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000197
fmalita511005b2015-03-13 06:50:44 -0700198 // Clamp the tile size to about 4M pixels
199 static const SkScalar kMaxTileArea = 2048 * 2048;
Mike Reeda99b6ce2017-02-04 11:04:26 -0500200 SkScalar tileArea = scaledSize.width() * scaledSize.height();
fmalitabb204f42014-08-07 08:39:24 -0700201 if (tileArea > kMaxTileArea) {
reed80ea19c2015-05-12 10:37:34 -0700202 SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
Mike Reeda99b6ce2017-02-04 11:04:26 -0500203 scaledSize.set(scaledSize.width() * clampScale,
204 scaledSize.height() * clampScale);
fmalitabb204f42014-08-07 08:39:24 -0700205 }
gen.kimb9ed8842015-05-03 22:36:30 -0700206#if SK_SUPPORT_GPU
207 // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture
208 if (maxTextureSize) {
209 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
ericrkf469fc02015-10-14 17:33:29 -0700210 SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height());
Mike Reeda99b6ce2017-02-04 11:04:26 -0500211 scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale),
212 SkScalarFloorToScalar(scaledSize.height() * downScale));
gen.kimb9ed8842015-05-03 22:36:30 -0700213 }
214 }
215#endif
fmalitabb204f42014-08-07 08:39:24 -0700216
fmalita85c6f982016-02-29 09:18:31 -0800217 const SkISize tileSize = scaledSize.toCeil();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000218 if (tileSize.isEmpty()) {
reed8a21c9f2016-03-08 18:50:00 -0800219 return SkShader::MakeEmptyShader();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000220 }
221
fmalitabb204f42014-08-07 08:39:24 -0700222 // The actual scale, compensating for rounding & clamping.
fmalita85c6f982016-02-29 09:18:31 -0800223 const SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
224 SkIntToScalar(tileSize.height()) / fTile.height());
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000225
Matt Sarett28a7ad22017-04-21 15:12:34 -0400226 // |fColorSpace| will only be set when using an SkColorSpaceXformCanvas to do pre-draw xforms.
227 // This canvas is strictly for legacy mode. A non-null |dstColorSpace| indicates that we
228 // should perform color correct rendering and xform at draw time.
229 SkASSERT(!fColorSpace || !dstColorSpace);
230 sk_sp<SkColorSpace> keyCS = dstColorSpace ? sk_ref_sp(dstColorSpace) : fColorSpace;
231 SkTransferFunctionBehavior blendBehavior = dstColorSpace ? SkTransferFunctionBehavior::kRespect
232 : SkTransferFunctionBehavior::kIgnore;
233
reed8a21c9f2016-03-08 18:50:00 -0800234 sk_sp<SkShader> tileShader;
Matt Sarett28a7ad22017-04-21 15:12:34 -0400235 BitmapShaderKey key(std::move(keyCS),
Florin Malitab00a3602017-07-13 22:34:04 -0400236 fUniqueID,
fmalita23df2d62014-10-22 07:39:08 -0700237 fTile,
238 fTmx,
239 fTmy,
240 tileScale,
Matt Sarett28a7ad22017-04-21 15:12:34 -0400241 blendBehavior);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000242
fmalita171e5b72014-10-22 11:20:40 -0700243 if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
robertphillips25a5b0d2015-09-28 09:32:50 -0700244 SkMatrix tileMatrix;
245 tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()),
fmalita1b46a572016-02-01 02:34:03 -0800246 SkMatrix::kFill_ScaleToFit);
247
Matt Sarett9df70bb2017-02-14 13:50:43 -0500248 sk_sp<SkImage> tileImage = SkImage::MakeFromGenerator(
Mike Reed185130c2017-02-15 15:14:16 -0500249 SkPictureImageGenerator::Make(tileSize, fPicture, &tileMatrix, nullptr,
250 SkImage::BitDepth::kU8, sk_ref_sp(dstColorSpace)));
fmalita1b46a572016-02-01 02:34:03 -0800251 if (!tileImage) {
fmalitaddc4b462015-08-31 19:54:03 -0700252 return nullptr;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000253 }
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000254
Matt Sarett28a7ad22017-04-21 15:12:34 -0400255 if (fColorSpace) {
256 tileImage = tileImage->makeColorSpace(fColorSpace, SkTransferFunctionBehavior::kIgnore);
257 }
258
Florin Malita18f7e0a2018-02-06 16:49:40 -0500259 tileShader = tileImage->makeShader(fTmx, fTmy);
fmalita23df2d62014-10-22 07:39:08 -0700260
fmalitac9a9ca92016-10-12 13:43:43 -0700261 SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
Florin Malitab00a3602017-07-13 22:34:04 -0400262 fAddedToCache.store(true);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000263 }
264
Florin Malita8f88d892018-04-19 21:07:19 -0400265 if (tileScale.width() != 1 || tileScale.height() != 1) {
266 localMatrix->writable()->preScale(1 / tileScale.width(), 1 / tileScale.height());
267 }
Florin Malita18f7e0a2018-02-06 16:49:40 -0500268
reed8a21c9f2016-03-08 18:50:00 -0800269 return tileShader;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000270}
271
Mike Reed1d8c42e2017-08-29 14:58:19 -0400272bool SkPictureShader::onAppendStages(const StageRec& rec) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -0400273 auto lm = this->totalLocalMatrix(rec.fLocalM);
Florin Malitac6c5ead2018-04-11 15:33:40 -0400274
Yuqian Li8d2fb472017-01-30 11:33:46 -0500275 // Keep bitmapShader alive by using alloc instead of stack memory
Mike Reed1d8c42e2017-08-29 14:58:19 -0400276 auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
Florin Malita8f88d892018-04-19 21:07:19 -0400277 bitmapShader = this->refBitmapShader(rec.fCTM, &lm, rec.fDstCS);
Florin Malitac6c5ead2018-04-11 15:33:40 -0400278
279 if (!bitmapShader) {
280 return false;
281 }
282
Florin Malita18f7e0a2018-02-06 16:49:40 -0500283 StageRec localRec = rec;
Florin Malitac6c5ead2018-04-11 15:33:40 -0400284 localRec.fLocalM = lm->isIdentity() ? nullptr : lm.get();
Florin Malita18f7e0a2018-02-06 16:49:40 -0500285
Florin Malitac6c5ead2018-04-11 15:33:40 -0400286 return as_SB(bitmapShader)->appendStages(localRec);
Yuqian Li8d2fb472017-01-30 11:33:46 -0500287}
288
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000289/////////////////////////////////////////////////////////////////////////////////////////
Florin Malita4aed1382017-05-25 10:38:07 -0400290SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
Herb Derby83e939b2017-02-07 14:25:11 -0500291const {
Florin Malitac6c5ead2018-04-11 15:33:40 -0400292 auto lm = this->totalLocalMatrix(rec.fLocalMatrix);
Florin Malita8f88d892018-04-19 21:07:19 -0400293 sk_sp<SkShader> bitmapShader = this->refBitmapShader(*rec.fMatrix, &lm, rec.fDstColorSpace);
Herb Derby83e939b2017-02-07 14:25:11 -0500294 if (!bitmapShader) {
295 return nullptr;
296 }
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000297
Florin Malita18f7e0a2018-02-06 16:49:40 -0500298 ContextRec localRec = rec;
Florin Malitac6c5ead2018-04-11 15:33:40 -0400299 localRec.fLocalMatrix = lm->isIdentity() ? nullptr : lm.get();
Florin Malita18f7e0a2018-02-06 16:49:40 -0500300
Herb Derby83e939b2017-02-07 14:25:11 -0500301 PictureShaderContext* ctx =
Florin Malita18f7e0a2018-02-06 16:49:40 -0500302 alloc->make<PictureShaderContext>(*this, localRec, std::move(bitmapShader), alloc);
halcanary96fcdcc2015-08-27 07:41:13 -0700303 if (nullptr == ctx->fBitmapShaderContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700304 ctx = nullptr;
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000305 }
306 return ctx;
307}
308
Matt Sarett28a7ad22017-04-21 15:12:34 -0400309sk_sp<SkShader> SkPictureShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Florin Malita604f0d52017-07-13 14:29:12 -0400310 sk_sp<SkColorSpace> dstCS = xformer->dst();
311 if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
312 return sk_ref_sp(const_cast<SkPictureShader*>(this));
313 }
314
Matt Sarett28a7ad22017-04-21 15:12:34 -0400315 return sk_sp<SkPictureShader>(new SkPictureShader(fPicture, fTmx, fTmy, &this->getLocalMatrix(),
Florin Malita604f0d52017-07-13 14:29:12 -0400316 &fTile, std::move(dstCS)));
Matt Sarett28a7ad22017-04-21 15:12:34 -0400317}
318
Herb Derby83e939b2017-02-07 14:25:11 -0500319/////////////////////////////////////////////////////////////////////////////////////////
320
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000321SkPictureShader::PictureShaderContext::PictureShaderContext(
Herb Derby83e939b2017-02-07 14:25:11 -0500322 const SkPictureShader& shader, const ContextRec& rec, sk_sp<SkShader> bitmapShader,
323 SkArenaAlloc* alloc)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000324 : INHERITED(shader, rec)
reed8a21c9f2016-03-08 18:50:00 -0800325 , fBitmapShader(std::move(bitmapShader))
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000326{
Florin Malita4aed1382017-05-25 10:38:07 -0400327 fBitmapShaderContext = as_SB(fBitmapShader)->makeContext(rec, alloc);
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000328 //if fBitmapShaderContext is null, we are invalid
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000329}
330
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000331uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000332 SkASSERT(fBitmapShaderContext);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000333 return fBitmapShaderContext->getFlags();
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000334}
335
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000336void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
337 SkASSERT(fBitmapShaderContext);
338 fBitmapShaderContext->shadeSpan(x, y, dstC, count);
339}
340
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000341void SkPictureShader::toString(SkString* str) const {
342 static const char* gTileModeName[SkShader::kTileModeCount] = {
343 "clamp", "repeat", "mirror"
344 };
345
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700346 str->appendf("PictureShader: [%f:%f:%f:%f] ",
fmalitaddc4b462015-08-31 19:54:03 -0700347 fPicture->cullRect().fLeft,
348 fPicture->cullRect().fTop,
349 fPicture->cullRect().fRight,
350 fPicture->cullRect().fBottom);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000351
352 str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
353
354 this->INHERITED::toString(str);
355}
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000356
357#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400358std::unique_ptr<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -0500359 const GrFPArgs& args) const {
gen.kimb9ed8842015-05-03 22:36:30 -0700360 int maxTextureSize = 0;
brianosman839345d2016-07-22 11:04:53 -0700361 if (args.fContext) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400362 maxTextureSize = args.fContext->contextPriv().caps()->maxTextureSize();
gen.kimb9ed8842015-05-03 22:36:30 -0700363 }
Florin Malitac6c5ead2018-04-11 15:33:40 -0400364
365 auto lm = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
Florin Malita8f88d892018-04-19 21:07:19 -0400366 sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, &lm,
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400367 args.fDstColorSpaceInfo->colorSpace(),
Florin Malita8f88d892018-04-19 21:07:19 -0400368 maxTextureSize));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000369 if (!bitmapShader) {
bsalomonc21b09e2015-08-28 18:46:56 -0700370 return nullptr;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000371 }
Florin Malita18f7e0a2018-02-06 16:49:40 -0500372
Florin Malitac6c5ead2018-04-11 15:33:40 -0400373 // We want to *reset* args.fPreLocalMatrix, not compose it.
374 GrFPArgs newArgs(args.fContext, args.fViewMatrix, args.fFilterQuality, args.fDstColorSpaceInfo);
375 newArgs.fPreLocalMatrix = lm.get();
376
377 return as_SB(bitmapShader)->asFragmentProcessor(newArgs);
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000378}
379#endif