1 /*
2 * Copyright 2023 Google LLC
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 "src/image/SkImage_Picture.h"
9
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageGenerator.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPicture.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkSurfaceProps.h"
21 #include "include/private/base/SkAssert.h"
22 #include "include/private/base/SkMutex.h"
23 #include "include/private/base/SkTFitsIn.h"
24 #include "src/base/SkTLazy.h"
25 #include "src/image/SkImageGeneratorPriv.h"
26 #include "src/image/SkImage_Lazy.h"
27 #include "src/image/SkPictureImageGenerator.h"
28
29 #include <cstring>
30 #include <memory>
31 #include <utility>
32
33 class SkPaint;
34 struct SkISize;
35
Make(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,SkImages::BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace,SkSurfaceProps props)36 sk_sp<SkImage> SkImage_Picture::Make(sk_sp<SkPicture> picture, const SkISize& dimensions,
37 const SkMatrix* matrix, const SkPaint* paint,
38 SkImages::BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace,
39 SkSurfaceProps props) {
40 auto gen = SkImageGenerators::MakeFromPicture(dimensions, std::move(picture), matrix, paint,
41 bitDepth, std::move(colorSpace), props);
42
43 SkImage_Lazy::Validator validator(
44 SharedGenerator::Make(std::move(gen)), nullptr, nullptr);
45
46 return validator ? sk_make_sp<SkImage_Picture>(&validator) : nullptr;
47 }
48
props() const49 const SkSurfaceProps* SkImage_Picture::props() const {
50 auto pictureIG = static_cast<SkPictureImageGenerator*>(this->generator()->fGenerator.get());
51 return &pictureIG->fProps;
52 }
53
replay(SkCanvas * canvas) const54 void SkImage_Picture::replay(SkCanvas* canvas) const {
55 auto sharedGenerator = this->generator();
56 SkAutoMutexExclusive mutex(sharedGenerator->fMutex);
57
58 auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get());
59 canvas->clear(SkColors::kTransparent);
60 canvas->drawPicture(pictureIG->fPicture,
61 &pictureIG->fMatrix,
62 pictureIG->fPaint.getMaybeNull());
63 }
64
onMakeSubset(GrDirectContext *,const SkIRect & subset) const65 sk_sp<SkImage> SkImage_Picture::onMakeSubset(GrDirectContext*, const SkIRect& subset) const {
66 auto sharedGenerator = this->generator();
67 auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get());
68
69 SkMatrix matrix = pictureIG->fMatrix;
70 matrix.postTranslate(-subset.left(), -subset.top());
71 SkImages::BitDepth bitDepth =
72 this->colorType() == kRGBA_F16_SkColorType ? SkImages::BitDepth::kF16
73 : SkImages::BitDepth::kU8;
74
75 return SkImage_Picture::Make(pictureIG->fPicture, subset.size(),
76 &matrix, pictureIG->fPaint.getMaybeNull(),
77 bitDepth, this->refColorSpace(), pictureIG->fProps);
78 }
79
onMakeSubset(skgpu::graphite::Recorder *,const SkIRect & subset,RequiredProperties) const80 sk_sp<SkImage> SkImage_Picture::onMakeSubset(skgpu::graphite::Recorder*,
81 const SkIRect& subset,
82 RequiredProperties) const {
83 // The Ganesh version doesn't make use of GrDirectContext so we can use it to
84 // generate our initial subset. In addition, requesting mipmaps doesn't make
85 // much sense in this case so we ignore the props.
86 return this->onMakeSubset(nullptr, subset);
87 }
88
getImageKeyValues(uint32_t keyValues[SkTiledImageUtils::kNumImageKeyValues]) const89 bool SkImage_Picture::getImageKeyValues(
90 uint32_t keyValues[SkTiledImageUtils::kNumImageKeyValues]) const {
91
92 auto sharedGenerator = this->generator();
93 SkAutoMutexExclusive mutex(sharedGenerator->fMutex);
94
95 auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get());
96 if (pictureIG->fPaint.getMaybeNull()) {
97 // A full paint complicates the potential key too much.
98 return false;
99 }
100
101 const SkImageInfo& ii = sharedGenerator->getInfo();
102 if (!ii.colorSpace()->isSRGB()) {
103 // We only return key values if the colorSpace is sRGB.
104 return false;
105 }
106
107 const SkMatrix& m = pictureIG->fMatrix;
108 if (!m.isIdentity() && !m.isTranslate()) {
109 // To keep the key small we only cache simple (<= translation) matrices
110 return false;
111 }
112
113 bool isU8 = ii.colorType() != kRGBA_F16_SkColorType;
114 uint32_t pixelGeometry = this->props()->pixelGeometry();
115 uint32_t surfacePropFlags = this->props()->flags();
116 int width = ii.width();
117 int height = ii.height();
118 float transX = m.getTranslateX();
119 float transY = m.getTranslateY();
120
121 SkASSERT(pixelGeometry <= 4);
122 SkASSERT(surfacePropFlags < 8);
123 SkASSERT(SkTFitsIn<uint32_t>(width));
124 SkASSERT(SkTFitsIn<uint32_t>(height));
125 SkASSERT(sizeof(float) == sizeof(uint32_t));
126
127 // The 0th slot usually holds either the SkBitmap's ID or the image's. In those two cases
128 // slot #1 is zero so we can reuse the 0th slot here.
129 keyValues[0] = (isU8 ? 0x1 : 0x0) | // 1 bit
130 (pixelGeometry << 1) | // 3 bits
131 (surfacePropFlags << 4); // 3 bits
132 keyValues[1] = pictureIG->fPicture->uniqueID();
133 SkASSERT(keyValues[1] != 0); // Double check we don't collide w/ bitmap or image keys
134 keyValues[2] = width;
135 keyValues[3] = height;
136 memcpy(&keyValues[4], &transX, sizeof(uint32_t));
137 memcpy(&keyValues[5], &transY, sizeof(uint32_t));
138 return true;
139 }
140