Flutter Engine
The Flutter Engine
SkPictureShader.cpp
Go to the documentation of this file.
1/*
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
9
32
33#include <algorithm>
34#include <cstddef>
35#include <cstdint>
36#include <utility>
38
40 const SkMatrix* localMatrix, const SkRect* tile) const {
41 if (localMatrix && !localMatrix->invert(nullptr)) {
42 return nullptr;
43 }
44 return SkPictureShader::Make(sk_ref_sp(this), tmx, tmy, filter, localMatrix, tile);
45}
46
47namespace {
48static unsigned gImageFromPictureKeyNamespaceLabel;
49
50struct ImageFromPictureKey : public SkResourceCache::Key {
51public:
52 ImageFromPictureKey(SkColorSpace* colorSpace, SkColorType colorType,
53 uint32_t pictureID, const SkRect& subset,
54 SkSize scale, const SkSurfaceProps& surfaceProps)
55 : fColorSpaceXYZHash(colorSpace->toXYZD50Hash())
56 , fColorSpaceTransferFnHash(colorSpace->transferFnHash())
57 , fColorType(static_cast<uint32_t>(colorType))
58 , fSubset(subset)
59 , fScale(scale)
60 , fSurfaceProps(surfaceProps)
61 {
62 static const size_t keySize = sizeof(fColorSpaceXYZHash) +
63 sizeof(fColorSpaceTransferFnHash) +
64 sizeof(fColorType) +
65 sizeof(fSubset) +
66 sizeof(fScale) +
67 sizeof(fSurfaceProps);
68 // This better be packed.
69 SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fColorSpaceXYZHash) == keySize);
70 this->init(&gImageFromPictureKeyNamespaceLabel,
72 keySize);
73 }
74
75private:
76 uint32_t fColorSpaceXYZHash;
77 uint32_t fColorSpaceTransferFnHash;
78 uint32_t fColorType;
79 SkRect fSubset;
80 SkSize fScale;
81 SkSurfaceProps fSurfaceProps;
82
83 SkDEBUGCODE(uint32_t fEndOfStruct;)
84};
85
86struct ImageFromPictureRec : public SkResourceCache::Rec {
87 ImageFromPictureRec(const ImageFromPictureKey& key, sk_sp<SkImage> image)
88 : fKey(key)
89 , fImage(std::move(image)) {}
90
91 ImageFromPictureKey fKey;
92 sk_sp<SkImage> fImage;
93
94 const Key& getKey() const override { return fKey; }
95 size_t bytesUsed() const override {
96 // Just the record overhead -- the actual pixels are accounted by SkImage_Lazy.
97 return sizeof(fKey) + (size_t)fImage->width() * fImage->height() * 4;
98 }
99 const char* getCategory() const override { return "bitmap-shader"; }
100 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
101
102 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
103 const ImageFromPictureRec& rec = static_cast<const ImageFromPictureRec&>(baseRec);
104 sk_sp<SkImage>* result = reinterpret_cast<sk_sp<SkImage>*>(contextShader);
105
106 *result = rec.fImage;
107 return true;
108 }
109};
110
111} // namespace
112
116 SkFilterMode filter,
117 const SkRect* tile)
118 : fPicture(std::move(picture))
119 , fTile(tile ? *tile : fPicture->cullRect())
120 , fTmx(tmx)
121 , fTmy(tmy)
122 , fFilter(filter) {}
123
125 SkFilterMode filter, const SkMatrix* lm, const SkRect* tile) {
126 if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
127 return SkShaders::Empty();
128 }
129 return SkLocalMatrixShader::MakeWrapped<SkPictureShader>(lm,
130 std::move(picture),
131 tmx, tmy,
132 filter,
133 tile);
134}
135
136sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
137 SkMatrix lm;
138 if (buffer.isVersionLT(SkPicturePriv::Version::kNoShaderLocalMatrix)) {
139 buffer.readMatrix(&lm);
140 }
141 auto tmx = buffer.read32LE(SkTileMode::kLastTileMode);
142 auto tmy = buffer.read32LE(SkTileMode::kLastTileMode);
143 SkRect tile = buffer.readRect();
144
146
150 bool didSerialize = buffer.readBool();
151 if (didSerialize) {
153 }
154 } else {
155 unsigned legacyFilter = buffer.read32();
156 if (legacyFilter <= (unsigned)SkFilterMode::kLast) {
157 filter = (SkFilterMode)legacyFilter;
158 }
160 }
161 } else {
164 }
166}
167
169 buffer.write32((unsigned)fTmx);
170 buffer.write32((unsigned)fTmy);
171 buffer.writeRect(fTile);
172 buffer.write32((unsigned)fFilter);
174}
175
177 return cs ? sk_ref_sp(cs) : SkColorSpace::MakeSRGB();
178}
179
181 const SkRect& bounds,
182 const SkMatrix& totalM,
183 SkColorType dstColorType,
184 SkColorSpace* dstColorSpace,
185 const int maxTextureSize,
186 const SkSurfaceProps& propsIn) {
188
189 const SkSize scaledSize = [&]() {
190 SkSize size;
191 // Use a rotation-invariant scale
192 if (!totalM.decomposeScale(&size, nullptr)) {
193 SkPoint center = {bounds.centerX(), bounds.centerY()};
195 if (!SkIsFinite(area) || SkScalarNearlyZero(area)) {
196 size = {1, 1}; // ill-conditioned matrix
197 } else {
198 size.fWidth = size.fHeight = SkScalarSqrt(area);
199 }
200 }
201 size.fWidth *= bounds.width();
202 size.fHeight *= bounds.height();
203
204 // Clamp the tile size to about 4M pixels
205 static const SkScalar kMaxTileArea = 2048 * 2048;
206 SkScalar tileArea = size.width() * size.height();
207 if (tileArea > kMaxTileArea) {
208 SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
209 size.set(size.width() * clampScale, size.height() * clampScale);
210 }
211
212 // Scale down the tile size if larger than maxTextureSize for GPU path
213 // or it should fail on create texture
214 if (maxTextureSize) {
215 if (size.width() > maxTextureSize || size.height() > maxTextureSize) {
216 SkScalar downScale = maxTextureSize / std::max(size.width(), size.height());
217 size.set(SkScalarFloorToScalar(size.width() * downScale),
218 SkScalarFloorToScalar(size.height() * downScale));
219 }
220 }
221 return size;
222 }();
223
224 const SkISize tileSize = scaledSize.toCeil();
225 if (tileSize.isEmpty()) {
226 return {false, {}, {}, {}, {}};
227 }
228
229 const SkSize tileScale = {tileSize.width() / bounds.width(),
230 tileSize.height() / bounds.height()};
231 auto imgCS = ref_or_srgb(dstColorSpace);
232 const SkColorType imgCT = SkColorTypeMaxBitsPerChannel(dstColorType) <= 8
235
236 return {true,
237 tileScale,
238 SkMatrix::RectToRect(bounds, SkRect::MakeIWH(tileSize.width(), tileSize.height())),
239 SkImageInfo::Make(tileSize, imgCT, kPremul_SkAlphaType, imgCS),
240 props};
241}
242
244 const SkPicture* pict) const {
245 if (!surf) {
246 return nullptr;
247 }
248 auto canvas = surf->getCanvas();
249 canvas->concat(matrixForDraw);
250 canvas->drawPicture(pict);
251 return surf->makeImageSnapshot();
252}
253
254// Returns a cached image shader, which wraps a single picture tile at the given
255// CTM/local matrix. Also adjusts the local matrix for tile scaling.
256sk_sp<SkShader> SkPictureShader::rasterShader(const SkMatrix& totalM,
257 SkColorType dstColorType,
258 SkColorSpace* dstColorSpace,
259 const SkSurfaceProps& propsIn) const {
260 const int maxTextureSize_NotUsedForCPU = 0;
262 totalM,
263 dstColorType, dstColorSpace,
264 maxTextureSize_NotUsedForCPU,
265 propsIn);
266 if (!info.success) {
267 return nullptr;
268 }
269
270 ImageFromPictureKey key(info.imageInfo.colorSpace(), info.imageInfo.colorType(),
271 fPicture->uniqueID(), fTile, info.tileScale, info.props);
272
275 image = info.makeImage(SkSurfaces::Raster(info.imageInfo, &info.props), fPicture.get());
276 if (!image) {
277 return nullptr;
278 }
279
280 SkResourceCache::Add(new ImageFromPictureRec(key, image));
282 }
283 // Scale the image to the original picture size.
284 auto lm = SkMatrix::Scale(1.f/info.tileScale.width(), 1.f/info.tileScale.height());
285 return image->makeShader(fTmx, fTmy, SkSamplingOptions(fFilter), &lm);
286}
287
289 // Keep bitmapShader alive by using alloc instead of stack memory
290 auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
291 // We don't check whether the total local matrix is valid here because we have to assume *some*
292 // mapping to make an image. It could be wildly wrong if there is a runtime shader transforming
293 // the coordinates in a manner we don't know about here. However, that is a fundamental problem
294 // with the technique of converting a picture to an image to implement this shader.
295 bitmapShader = this->rasterShader(mRec.totalMatrix(),
296 rec.fDstColorType,
297 rec.fDstCS,
298 rec.fSurfaceProps);
299 if (!bitmapShader) {
300 return false;
301 }
302 return as_SB(bitmapShader)->appendStages(rec, mRec);
303}
304
305/////////////////////////////////////////////////////////////////////////////////////////
306
307#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
308SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec,
309 SkArenaAlloc* alloc) const {
310 sk_sp<SkShader> bitmapShader = this->rasterShader(
311 rec.fMatrixRec.totalMatrix(), rec.fDstColorType, rec.fDstColorSpace, rec.fProps);
312 if (!bitmapShader) {
313 return nullptr;
314 }
315
316 return as_SB(bitmapShader)->makeContext(rec, alloc);
317}
318#endif
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
TArray< uint32_t > Key
SkColorType fColorType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorType
Definition: SkColorType.h:19
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition: SkColorType.h:36
static bool SkIsFinite(T x, Pack... values)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static int SkColorTypeMaxBitsPerChannel(SkColorType ct)
static sk_sp< SkColorSpace > ref_or_srgb(SkColorSpace *cs)
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkFilterMode
#define SkScalarFloorToScalar(x)
Definition: SkScalar.h:30
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
#define SkScalarSqrt(x)
Definition: SkScalar.h:42
SkShaderBase * as_SB(SkShader *shader)
Definition: SkShaderBase.h:412
@ kUnknown_SkPixelGeometry
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
SkTileMode
Definition: SkTileMode.h:13
static SkScalar center(float pos0, float pos1)
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
static sk_sp< SkColorSpace > MakeSRGB()
int width() const
Definition: SkImage.h:285
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
int height() const
Definition: SkImage.h:291
static SkScalar DifferentialAreaScale(const SkMatrix &m, const SkPoint &p)
Definition: SkMatrix.cpp:1786
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
bool decomposeScale(SkSize *scale, SkMatrix *remaining=nullptr) const
Definition: SkMatrix.cpp:1559
static void AddedToCache(const SkPicture *pic)
Definition: SkPicturePriv.h:45
static uint64_t MakeSharedID(uint32_t pictureID)
Definition: SkPicturePriv.h:40
@ kPictureShaderFilterParam_Version
@ kNoFilterQualityShaders_Version
static void Flatten(const sk_sp< const SkPicture >, SkWriteBuffer &buffer)
Definition: SkPicture.cpp:314
static sk_sp< SkPicture > MakeFromBuffer(SkReadBuffer &buffer)
Definition: SkPicture.cpp:213
SkRect tile() const
bool appendStages(const SkStageRec &, const SkShaders::MatrixRec &) const override
static sk_sp< SkShader > Make(sk_sp< SkPicture >, SkTileMode, SkTileMode, SkFilterMode, const SkMatrix *, const SkRect *)
SkFilterMode filter() const
sk_sp< SkPicture > picture() const
void flatten(SkWriteBuffer &) const override
SkPictureShader(sk_sp< SkPicture >, SkTileMode, SkTileMode, SkFilterMode, const SkRect *)
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, const SkMatrix *localMatrix, const SkRect *tileRect) const
uint32_t uniqueID() const
Definition: SkPicture.h:155
virtual SkRect cullRect() const =0
static void Add(Rec *, void *payload=nullptr)
static bool Find(const Key &key, FindVisitor, void *context)
Context * makeContext(const ContextRec &, SkArenaAlloc *) const
virtual bool appendStages(const SkStageRec &, const SkShaders::MatrixRec &) const =0
SkMatrix totalMatrix() const
Definition: SkShaderBase.h:117
SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
sk_sp< SkImage > makeImageSnapshot()
Definition: SkSurface.cpp:90
T * get() const
Definition: SkRefCnt.h:303
float SkScalar
Definition: extension.cpp:12
GAsyncResult * result
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static bool init()
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
SK_API sk_sp< SkShader > Empty()
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
Visitor(Ts...) -> Visitor< Ts... >
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkSamplingOptions(SkFilterMode::kLinear))
Definition: ref_ptr.h:256
SkTileMode tmy
SkTileMode tmx
const Scalar scale
Definition: SkSize.h:16
bool isEmpty() const
Definition: SkSize.h:31
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static CachedImageInfo Make(const SkRect &bounds, const SkMatrix &totalM, SkColorType dstColorType, SkColorSpace *dstColorSpace, const int maxTextureSize, const SkSurfaceProps &propsIn)
sk_sp< SkImage > makeImage(sk_sp< SkSurface > surf, const SkPicture *pict) const
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
bool isEmpty() const
Definition: SkRect.h:693
Definition: SkSize.h:52
SkISize toCeil() const
Definition: SkSize.h:83
const SkSurfaceProps & fSurfaceProps
Definition: SkEffectPriv.h:26
SkColorSpace * fDstCS
Definition: SkEffectPriv.h:24
SkArenaAlloc * fAlloc
Definition: SkEffectPriv.h:22
SkColorType fDstColorType
Definition: SkEffectPriv.h:23