xref: /aosp_15_r20/external/skia/src/shaders/SkPictureShader.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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