Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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;
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
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
274 if (!SkResourceCache::Find(key, ImageFromPictureRec::Visitor, &image)) {
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
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
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
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)
@ kUnknown_SkPixelGeometry
SkTileMode
Definition SkTileMode.h:13
static SkScalar center(float pos0, float pos1)
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
static sk_sp< SkColorSpace > MakeSRGB()
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition SkImage.cpp:179
static SkScalar DifferentialAreaScale(const SkMatrix &m, const SkPoint &p)
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
static void AddedToCache(const SkPicture *pic)
static uint64_t MakeSharedID(uint32_t pictureID)
@ kPictureShaderFilterParam_Version
@ kNoFilterQualityShaders_Version
static void Flatten(const sk_sp< const SkPicture >, SkWriteBuffer &buffer)
static sk_sp< SkPicture > MakeFromBuffer(SkReadBuffer &buffer)
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
SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const
T * get() const
Definition SkRefCnt.h:303
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
static const uint8_t buffer[]
GAsyncResult * result
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
Visitor(Ts...) -> Visitor< Ts... >
Definition ref_ptr.h:256
SkTileMode tmy
SkTileMode tmx
const Scalar scale
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
SkISize toCeil() const
Definition SkSize.h:83
const SkSurfaceProps & fSurfaceProps
SkColorSpace * fDstCS
SkArenaAlloc * fAlloc
SkColorType fDstColorType