1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2014 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkPictureShader.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkEffectPriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImageInfoPriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPicturePriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkResourceCache.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkLocalMatrixShader.h"
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
34*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
35*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
36*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
37*c8dee2aaSAndroid Build Coastguard Worker class SkDiscardableMemory;
38*c8dee2aaSAndroid Build Coastguard Worker
makeShader(SkTileMode tmx,SkTileMode tmy,SkFilterMode filter,const SkMatrix * localMatrix,const SkRect * tile) const39*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> SkPicture::makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode filter,
40*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix* localMatrix, const SkRect* tile) const {
41*c8dee2aaSAndroid Build Coastguard Worker if (localMatrix && !localMatrix->invert(nullptr)) {
42*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker return SkPictureShader::Make(sk_ref_sp(this), tmx, tmy, filter, localMatrix, tile);
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker namespace {
48*c8dee2aaSAndroid Build Coastguard Worker static unsigned gImageFromPictureKeyNamespaceLabel;
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker struct ImageFromPictureKey : public SkResourceCache::Key {
51*c8dee2aaSAndroid Build Coastguard Worker public:
ImageFromPictureKey__anon12cf26d00111::ImageFromPictureKey52*c8dee2aaSAndroid Build Coastguard Worker ImageFromPictureKey(SkColorSpace* colorSpace, SkColorType colorType,
53*c8dee2aaSAndroid Build Coastguard Worker uint32_t pictureID, const SkRect& subset,
54*c8dee2aaSAndroid Build Coastguard Worker SkSize scale, const SkSurfaceProps& surfaceProps)
55*c8dee2aaSAndroid Build Coastguard Worker : fColorSpaceXYZHash(colorSpace->toXYZD50Hash())
56*c8dee2aaSAndroid Build Coastguard Worker , fColorSpaceTransferFnHash(colorSpace->transferFnHash())
57*c8dee2aaSAndroid Build Coastguard Worker , fColorType(static_cast<uint32_t>(colorType))
58*c8dee2aaSAndroid Build Coastguard Worker , fSubset(subset)
59*c8dee2aaSAndroid Build Coastguard Worker , fScale(scale)
60*c8dee2aaSAndroid Build Coastguard Worker , fSurfaceProps(surfaceProps)
61*c8dee2aaSAndroid Build Coastguard Worker {
62*c8dee2aaSAndroid Build Coastguard Worker static const size_t keySize = sizeof(fColorSpaceXYZHash) +
63*c8dee2aaSAndroid Build Coastguard Worker sizeof(fColorSpaceTransferFnHash) +
64*c8dee2aaSAndroid Build Coastguard Worker sizeof(fColorType) +
65*c8dee2aaSAndroid Build Coastguard Worker sizeof(fSubset) +
66*c8dee2aaSAndroid Build Coastguard Worker sizeof(fScale) +
67*c8dee2aaSAndroid Build Coastguard Worker sizeof(fSurfaceProps);
68*c8dee2aaSAndroid Build Coastguard Worker // This better be packed.
69*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fColorSpaceXYZHash) == keySize);
70*c8dee2aaSAndroid Build Coastguard Worker this->init(&gImageFromPictureKeyNamespaceLabel,
71*c8dee2aaSAndroid Build Coastguard Worker SkPicturePriv::MakeSharedID(pictureID),
72*c8dee2aaSAndroid Build Coastguard Worker keySize);
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker private:
76*c8dee2aaSAndroid Build Coastguard Worker uint32_t fColorSpaceXYZHash;
77*c8dee2aaSAndroid Build Coastguard Worker uint32_t fColorSpaceTransferFnHash;
78*c8dee2aaSAndroid Build Coastguard Worker uint32_t fColorType;
79*c8dee2aaSAndroid Build Coastguard Worker SkRect fSubset;
80*c8dee2aaSAndroid Build Coastguard Worker SkSize fScale;
81*c8dee2aaSAndroid Build Coastguard Worker SkSurfaceProps fSurfaceProps;
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(uint32_t fEndOfStruct;)
84*c8dee2aaSAndroid Build Coastguard Worker };
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker struct ImageFromPictureRec : public SkResourceCache::Rec {
ImageFromPictureRec__anon12cf26d00111::ImageFromPictureRec87*c8dee2aaSAndroid Build Coastguard Worker ImageFromPictureRec(const ImageFromPictureKey& key, sk_sp<SkImage> image)
88*c8dee2aaSAndroid Build Coastguard Worker : fKey(key)
89*c8dee2aaSAndroid Build Coastguard Worker , fImage(std::move(image)) {}
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker ImageFromPictureKey fKey;
92*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage;
93*c8dee2aaSAndroid Build Coastguard Worker
getKey__anon12cf26d00111::ImageFromPictureRec94*c8dee2aaSAndroid Build Coastguard Worker const Key& getKey() const override { return fKey; }
bytesUsed__anon12cf26d00111::ImageFromPictureRec95*c8dee2aaSAndroid Build Coastguard Worker size_t bytesUsed() const override {
96*c8dee2aaSAndroid Build Coastguard Worker // Just the record overhead -- the actual pixels are accounted by SkImage_Lazy.
97*c8dee2aaSAndroid Build Coastguard Worker return sizeof(fKey) + (size_t)fImage->width() * fImage->height() * 4;
98*c8dee2aaSAndroid Build Coastguard Worker }
getCategory__anon12cf26d00111::ImageFromPictureRec99*c8dee2aaSAndroid Build Coastguard Worker const char* getCategory() const override { return "bitmap-shader"; }
diagnostic_only_getDiscardable__anon12cf26d00111::ImageFromPictureRec100*c8dee2aaSAndroid Build Coastguard Worker SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
101*c8dee2aaSAndroid Build Coastguard Worker
Visitor__anon12cf26d00111::ImageFromPictureRec102*c8dee2aaSAndroid Build Coastguard Worker static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
103*c8dee2aaSAndroid Build Coastguard Worker const ImageFromPictureRec& rec = static_cast<const ImageFromPictureRec&>(baseRec);
104*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage>* result = reinterpret_cast<sk_sp<SkImage>*>(contextShader);
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker *result = rec.fImage;
107*c8dee2aaSAndroid Build Coastguard Worker return true;
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker };
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker } // namespace
112*c8dee2aaSAndroid Build Coastguard Worker
SkPictureShader(sk_sp<SkPicture> picture,SkTileMode tmx,SkTileMode tmy,SkFilterMode filter,const SkRect * tile)113*c8dee2aaSAndroid Build Coastguard Worker SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture,
114*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tmx,
115*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tmy,
116*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode filter,
117*c8dee2aaSAndroid Build Coastguard Worker const SkRect* tile)
118*c8dee2aaSAndroid Build Coastguard Worker : fPicture(std::move(picture))
119*c8dee2aaSAndroid Build Coastguard Worker , fTile(tile ? *tile : fPicture->cullRect())
120*c8dee2aaSAndroid Build Coastguard Worker , fTmx(tmx)
121*c8dee2aaSAndroid Build Coastguard Worker , fTmy(tmy)
122*c8dee2aaSAndroid Build Coastguard Worker , fFilter(filter) {}
123*c8dee2aaSAndroid Build Coastguard Worker
Make(sk_sp<SkPicture> picture,SkTileMode tmx,SkTileMode tmy,SkFilterMode filter,const SkMatrix * lm,const SkRect * tile)124*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, SkTileMode tmx, SkTileMode tmy,
125*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode filter, const SkMatrix* lm, const SkRect* tile) {
126*c8dee2aaSAndroid Build Coastguard Worker if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
127*c8dee2aaSAndroid Build Coastguard Worker return SkShaders::Empty();
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker return SkLocalMatrixShader::MakeWrapped<SkPictureShader>(lm,
130*c8dee2aaSAndroid Build Coastguard Worker std::move(picture),
131*c8dee2aaSAndroid Build Coastguard Worker tmx, tmy,
132*c8dee2aaSAndroid Build Coastguard Worker filter,
133*c8dee2aaSAndroid Build Coastguard Worker tile);
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
CreateProc(SkReadBuffer & buffer)136*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
137*c8dee2aaSAndroid Build Coastguard Worker SkMatrix lm;
138*c8dee2aaSAndroid Build Coastguard Worker if (buffer.isVersionLT(SkPicturePriv::Version::kNoShaderLocalMatrix)) {
139*c8dee2aaSAndroid Build Coastguard Worker buffer.readMatrix(&lm);
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker auto tmx = buffer.read32LE(SkTileMode::kLastTileMode);
142*c8dee2aaSAndroid Build Coastguard Worker auto tmy = buffer.read32LE(SkTileMode::kLastTileMode);
143*c8dee2aaSAndroid Build Coastguard Worker SkRect tile = buffer.readRect();
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> picture;
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode filter = SkFilterMode::kNearest;
148*c8dee2aaSAndroid Build Coastguard Worker if (buffer.isVersionLT(SkPicturePriv::kNoFilterQualityShaders_Version)) {
149*c8dee2aaSAndroid Build Coastguard Worker if (buffer.isVersionLT(SkPicturePriv::kPictureShaderFilterParam_Version)) {
150*c8dee2aaSAndroid Build Coastguard Worker bool didSerialize = buffer.readBool();
151*c8dee2aaSAndroid Build Coastguard Worker if (didSerialize) {
152*c8dee2aaSAndroid Build Coastguard Worker picture = SkPicturePriv::MakeFromBuffer(buffer);
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker } else {
155*c8dee2aaSAndroid Build Coastguard Worker unsigned legacyFilter = buffer.read32();
156*c8dee2aaSAndroid Build Coastguard Worker if (legacyFilter <= (unsigned)SkFilterMode::kLast) {
157*c8dee2aaSAndroid Build Coastguard Worker filter = (SkFilterMode)legacyFilter;
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker picture = SkPicturePriv::MakeFromBuffer(buffer);
160*c8dee2aaSAndroid Build Coastguard Worker }
161*c8dee2aaSAndroid Build Coastguard Worker } else {
162*c8dee2aaSAndroid Build Coastguard Worker filter = buffer.read32LE(SkFilterMode::kLast);
163*c8dee2aaSAndroid Build Coastguard Worker picture = SkPicturePriv::MakeFromBuffer(buffer);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker return SkPictureShader::Make(picture, tmx, tmy, filter, &lm, &tile);
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const168*c8dee2aaSAndroid Build Coastguard Worker void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
169*c8dee2aaSAndroid Build Coastguard Worker buffer.write32((unsigned)fTmx);
170*c8dee2aaSAndroid Build Coastguard Worker buffer.write32((unsigned)fTmy);
171*c8dee2aaSAndroid Build Coastguard Worker buffer.writeRect(fTile);
172*c8dee2aaSAndroid Build Coastguard Worker buffer.write32((unsigned)fFilter);
173*c8dee2aaSAndroid Build Coastguard Worker SkPicturePriv::Flatten(fPicture, buffer);
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker
ref_or_srgb(SkColorSpace * cs)176*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkColorSpace> ref_or_srgb(SkColorSpace* cs) {
177*c8dee2aaSAndroid Build Coastguard Worker return cs ? sk_ref_sp(cs) : SkColorSpace::MakeSRGB();
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker
Make(const SkRect & bounds,const SkMatrix & totalM,SkColorType dstColorType,SkColorSpace * dstColorSpace,const int maxTextureSize,const SkSurfaceProps & propsIn)180*c8dee2aaSAndroid Build Coastguard Worker SkPictureShader::CachedImageInfo SkPictureShader::CachedImageInfo::Make(
181*c8dee2aaSAndroid Build Coastguard Worker const SkRect& bounds,
182*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& totalM,
183*c8dee2aaSAndroid Build Coastguard Worker SkColorType dstColorType,
184*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace* dstColorSpace,
185*c8dee2aaSAndroid Build Coastguard Worker const int maxTextureSize,
186*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps& propsIn) {
187*c8dee2aaSAndroid Build Coastguard Worker SkSurfaceProps props = propsIn.cloneWithPixelGeometry(kUnknown_SkPixelGeometry);
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker const SkSize scaledSize = [&]() {
190*c8dee2aaSAndroid Build Coastguard Worker SkSize size;
191*c8dee2aaSAndroid Build Coastguard Worker // Use a rotation-invariant scale
192*c8dee2aaSAndroid Build Coastguard Worker if (!totalM.decomposeScale(&size, nullptr)) {
193*c8dee2aaSAndroid Build Coastguard Worker SkPoint center = {bounds.centerX(), bounds.centerY()};
194*c8dee2aaSAndroid Build Coastguard Worker SkScalar area = SkMatrixPriv::DifferentialAreaScale(totalM, center);
195*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(area) || SkScalarNearlyZero(area)) {
196*c8dee2aaSAndroid Build Coastguard Worker size = {1, 1}; // ill-conditioned matrix
197*c8dee2aaSAndroid Build Coastguard Worker } else {
198*c8dee2aaSAndroid Build Coastguard Worker size.fWidth = size.fHeight = SkScalarSqrt(area);
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker size.fWidth *= bounds.width();
202*c8dee2aaSAndroid Build Coastguard Worker size.fHeight *= bounds.height();
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker // Clamp the tile size to about 4M pixels
205*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kMaxTileArea = 2048 * 2048;
206*c8dee2aaSAndroid Build Coastguard Worker SkScalar tileArea = size.width() * size.height();
207*c8dee2aaSAndroid Build Coastguard Worker if (tileArea > kMaxTileArea) {
208*c8dee2aaSAndroid Build Coastguard Worker SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
209*c8dee2aaSAndroid Build Coastguard Worker size.set(size.width() * clampScale, size.height() * clampScale);
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker // Scale down the tile size if larger than maxTextureSize for GPU path
213*c8dee2aaSAndroid Build Coastguard Worker // or it should fail on create texture
214*c8dee2aaSAndroid Build Coastguard Worker if (maxTextureSize) {
215*c8dee2aaSAndroid Build Coastguard Worker if (size.width() > maxTextureSize || size.height() > maxTextureSize) {
216*c8dee2aaSAndroid Build Coastguard Worker SkScalar downScale = maxTextureSize / std::max(size.width(), size.height());
217*c8dee2aaSAndroid Build Coastguard Worker size.set(SkScalarFloorToScalar(size.width() * downScale),
218*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(size.height() * downScale));
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker return size;
222*c8dee2aaSAndroid Build Coastguard Worker }();
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker const SkISize tileSize = scaledSize.toCeil();
225*c8dee2aaSAndroid Build Coastguard Worker if (tileSize.isEmpty()) {
226*c8dee2aaSAndroid Build Coastguard Worker return {false, {}, {}, {}, {}};
227*c8dee2aaSAndroid Build Coastguard Worker }
228*c8dee2aaSAndroid Build Coastguard Worker
229*c8dee2aaSAndroid Build Coastguard Worker const SkSize tileScale = {tileSize.width() / bounds.width(),
230*c8dee2aaSAndroid Build Coastguard Worker tileSize.height() / bounds.height()};
231*c8dee2aaSAndroid Build Coastguard Worker auto imgCS = ref_or_srgb(dstColorSpace);
232*c8dee2aaSAndroid Build Coastguard Worker const SkColorType imgCT = SkColorTypeMaxBitsPerChannel(dstColorType) <= 8
233*c8dee2aaSAndroid Build Coastguard Worker ? kRGBA_8888_SkColorType
234*c8dee2aaSAndroid Build Coastguard Worker : kRGBA_F16Norm_SkColorType;
235*c8dee2aaSAndroid Build Coastguard Worker
236*c8dee2aaSAndroid Build Coastguard Worker return {true,
237*c8dee2aaSAndroid Build Coastguard Worker tileScale,
238*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::RectToRect(bounds, SkRect::MakeIWH(tileSize.width(), tileSize.height())),
239*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo::Make(tileSize, imgCT, kPremul_SkAlphaType, imgCS),
240*c8dee2aaSAndroid Build Coastguard Worker props};
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
makeImage(sk_sp<SkSurface> surf,const SkPicture * pict) const243*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> SkPictureShader::CachedImageInfo::makeImage(sk_sp<SkSurface> surf,
244*c8dee2aaSAndroid Build Coastguard Worker const SkPicture* pict) const {
245*c8dee2aaSAndroid Build Coastguard Worker if (!surf) {
246*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
247*c8dee2aaSAndroid Build Coastguard Worker }
248*c8dee2aaSAndroid Build Coastguard Worker auto canvas = surf->getCanvas();
249*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(matrixForDraw);
250*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPicture(pict);
251*c8dee2aaSAndroid Build Coastguard Worker return surf->makeImageSnapshot();
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker
254*c8dee2aaSAndroid Build Coastguard Worker // Returns a cached image shader, which wraps a single picture tile at the given
255*c8dee2aaSAndroid Build Coastguard Worker // CTM/local matrix. Also adjusts the local matrix for tile scaling.
rasterShader(const SkMatrix & totalM,SkColorType dstColorType,SkColorSpace * dstColorSpace,const SkSurfaceProps & propsIn) const256*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> SkPictureShader::rasterShader(const SkMatrix& totalM,
257*c8dee2aaSAndroid Build Coastguard Worker SkColorType dstColorType,
258*c8dee2aaSAndroid Build Coastguard Worker SkColorSpace* dstColorSpace,
259*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps& propsIn) const {
260*c8dee2aaSAndroid Build Coastguard Worker const int maxTextureSize_NotUsedForCPU = 0;
261*c8dee2aaSAndroid Build Coastguard Worker CachedImageInfo info = CachedImageInfo::Make(fTile,
262*c8dee2aaSAndroid Build Coastguard Worker totalM,
263*c8dee2aaSAndroid Build Coastguard Worker dstColorType, dstColorSpace,
264*c8dee2aaSAndroid Build Coastguard Worker maxTextureSize_NotUsedForCPU,
265*c8dee2aaSAndroid Build Coastguard Worker propsIn);
266*c8dee2aaSAndroid Build Coastguard Worker if (!info.success) {
267*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
268*c8dee2aaSAndroid Build Coastguard Worker }
269*c8dee2aaSAndroid Build Coastguard Worker
270*c8dee2aaSAndroid Build Coastguard Worker ImageFromPictureKey key(info.imageInfo.colorSpace(), info.imageInfo.colorType(),
271*c8dee2aaSAndroid Build Coastguard Worker fPicture->uniqueID(), fTile, info.tileScale, info.props);
272*c8dee2aaSAndroid Build Coastguard Worker
273*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image;
274*c8dee2aaSAndroid Build Coastguard Worker if (!SkResourceCache::Find(key, ImageFromPictureRec::Visitor, &image)) {
275*c8dee2aaSAndroid Build Coastguard Worker image = info.makeImage(SkSurfaces::Raster(info.imageInfo, &info.props), fPicture.get());
276*c8dee2aaSAndroid Build Coastguard Worker if (!image) {
277*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
278*c8dee2aaSAndroid Build Coastguard Worker }
279*c8dee2aaSAndroid Build Coastguard Worker
280*c8dee2aaSAndroid Build Coastguard Worker SkResourceCache::Add(new ImageFromPictureRec(key, image));
281*c8dee2aaSAndroid Build Coastguard Worker SkPicturePriv::AddedToCache(fPicture.get());
282*c8dee2aaSAndroid Build Coastguard Worker }
283*c8dee2aaSAndroid Build Coastguard Worker // Scale the image to the original picture size.
284*c8dee2aaSAndroid Build Coastguard Worker auto lm = SkMatrix::Scale(1.f/info.tileScale.width(), 1.f/info.tileScale.height());
285*c8dee2aaSAndroid Build Coastguard Worker return image->makeShader(fTmx, fTmy, SkSamplingOptions(fFilter), &lm);
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker
appendStages(const SkStageRec & rec,const SkShaders::MatrixRec & mRec) const288*c8dee2aaSAndroid Build Coastguard Worker bool SkPictureShader::appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const {
289*c8dee2aaSAndroid Build Coastguard Worker // Keep bitmapShader alive by using alloc instead of stack memory
290*c8dee2aaSAndroid Build Coastguard Worker auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
291*c8dee2aaSAndroid Build Coastguard Worker // We don't check whether the total local matrix is valid here because we have to assume *some*
292*c8dee2aaSAndroid Build Coastguard Worker // mapping to make an image. It could be wildly wrong if there is a runtime shader transforming
293*c8dee2aaSAndroid Build Coastguard Worker // the coordinates in a manner we don't know about here. However, that is a fundamental problem
294*c8dee2aaSAndroid Build Coastguard Worker // with the technique of converting a picture to an image to implement this shader.
295*c8dee2aaSAndroid Build Coastguard Worker bitmapShader = this->rasterShader(mRec.totalMatrix(),
296*c8dee2aaSAndroid Build Coastguard Worker rec.fDstColorType,
297*c8dee2aaSAndroid Build Coastguard Worker rec.fDstCS,
298*c8dee2aaSAndroid Build Coastguard Worker rec.fSurfaceProps);
299*c8dee2aaSAndroid Build Coastguard Worker if (!bitmapShader) {
300*c8dee2aaSAndroid Build Coastguard Worker return false;
301*c8dee2aaSAndroid Build Coastguard Worker }
302*c8dee2aaSAndroid Build Coastguard Worker return as_SB(bitmapShader)->appendStages(rec, mRec);
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////////
306*c8dee2aaSAndroid Build Coastguard Worker
307*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const308*c8dee2aaSAndroid Build Coastguard Worker SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec,
309*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* alloc) const {
310*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> bitmapShader = this->rasterShader(
311*c8dee2aaSAndroid Build Coastguard Worker rec.fMatrixRec.totalMatrix(), rec.fDstColorType, rec.fDstColorSpace, rec.fProps);
312*c8dee2aaSAndroid Build Coastguard Worker if (!bitmapShader) {
313*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
314*c8dee2aaSAndroid Build Coastguard Worker }
315*c8dee2aaSAndroid Build Coastguard Worker
316*c8dee2aaSAndroid Build Coastguard Worker return as_SB(bitmapShader)->makeContext(rec, alloc);
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker #endif
319