Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Image_Base_Graphite.cpp
Go to the documentation of this file.
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
9
16
17namespace skgpu::graphite {
18
19Image_Base::Image_Base(const SkImageInfo& info, uint32_t uniqueID)
20 : SkImage_Base(info, uniqueID) {}
21
22Image_Base::~Image_Base() = default;
23
25 SkASSERT(other);
26
27 SkAutoSpinlock lock{other->fDeviceLinkLock};
28 for (const auto& device : other->fLinkedDevices) {
29 this->linkDevice(device);
30 }
31}
32
34 // Technically this lock isn't needed since this is only called before the Image is returned to
35 // user code that could expose it to multiple threads. But this quiets threading warnings and
36 // should be uncontested.
37 SkAutoSpinlock lock{fDeviceLinkLock};
38 fLinkedDevices.push_back(std::move(device));
39}
40
41void Image_Base::notifyInUse(Recorder* recorder) const {
42 // The ref counts stored on each linked device are thread safe, but the Image's sk_sp's that
43 // track the refs its responsible for are *not* thread safe. Use a spin lock since the majority
44 // of device-linked images will be used only on the Recorder's thread. Since it should be
45 // uncontended, the empty check is also done inside the lock vs. a double-checked locking
46 // pattern that is non-trivial to ensure correctness in C++.
47 SkAutoSpinlock lock{fDeviceLinkLock};
48
49 if (!fLinkedDevices.empty()) {
50 int emptyCount = 0;
51 for (sk_sp<Device>& device : fLinkedDevices) {
52 if (!device) {
53 emptyCount++; // Already unlinked but array isn't empty yet
54 } else {
55 // Automatic flushing of image views only happens when mixing reads and writes on
56 // the originating Recorder. Draws of the view on another Recorder will always see
57 // the texture content dependent on how Recordings are inserted.
58 if (device->recorder() == recorder) {
59 device->flushPendingWorkToRecorder();
60 }
61 if (!device->recorder() || device->unique()) {
62 // The device will not record any more commands that modify the texture, so the
63 // image doesn't need to be linked
64 device.reset();
65 emptyCount++;
66 }
67 }
68 }
69 if (emptyCount == fLinkedDevices.size()) {
70 fLinkedDevices.clear();
71 }
72 }
73}
74
76 SkAutoSpinlock lock{fDeviceLinkLock};
77 int emptyCount = 0;
78 if (!fLinkedDevices.empty()) {
79 for (sk_sp<Device>& device : fLinkedDevices) {
80 if (!device || !device->recorder() || device->unique()) {
81 device.reset();
82 emptyCount++;
83 }
84 }
85 if (emptyCount == fLinkedDevices.size()) {
86 fLinkedDevices.clear();
87 emptyCount = 0;
88 }
89 }
90
91 return emptyCount > 0;
92}
93
95 const Image_Base* image,
96 const SkIRect& subset,
97 const SkColorInfo& dstColorInfo,
98 Budgeted budgeted,
99 Mipmapped mipmapped,
100 SkBackingFit backingFit) {
101 SkImageInfo dstInfo = SkImageInfo::Make(subset.size(),
102 dstColorInfo.makeAlphaType(kPremul_SkAlphaType));
103 // The surface goes out of scope when we return, so it can be scratch, but it may or may
104 // not be budgeted depending on how the copied image is used (or returned to the client).
105 auto surface = Surface::MakeScratch(recorder,
106 dstInfo,
107 budgeted,
108 mipmapped,
109 backingFit);
110 if (!surface) {
111 return nullptr;
112 }
113
115 paint.setBlendMode(SkBlendMode::kSrc);
116 surface->getCanvas()->drawImage(image, -subset.left(), -subset.top(),
118 // And the image draw into `surface` is flushed when it goes out of scope
119 return surface->asImage();
120}
121
123 const SkIRect& subset,
124 Budgeted budgeted,
125 Mipmapped mipmapped,
126 SkBackingFit backingFit) const {
127 return CopyAsDraw(recorder, this, subset, this->imageInfo().colorInfo(),
128 budgeted, mipmapped, backingFit);
129}
130
132 const SkIRect& subset,
133 RequiredProperties requiredProps) const {
134 // optimization : return self if the subset == our bounds and requirements met and the image's
135 // texture is immutable
136 if (this->bounds() == subset &&
137 (!requiredProps.fMipmapped || this->hasMipmaps()) &&
138 !this->isDynamic()) {
139 return sk_ref_sp(this);
140 }
141
142 // The copied image is not considered budgeted because this is a client-invoked API and they
143 // will own the image.
144 return this->copyImage(recorder,
145 subset,
147 requiredProps.fMipmapped ? Mipmapped::kYes : Mipmapped::kNo,
149}
150
152 SkColorType targetCT,
153 sk_sp<SkColorSpace> targetCS,
154 RequiredProperties requiredProps) const {
155 SkColorInfo dstColorInfo{targetCT, this->alphaType(), std::move(targetCS)};
156 // optimization : return self if there's no color type/space change and the image's texture
157 // is immutable
158 if (this->imageInfo().colorInfo() == dstColorInfo && !this->isDynamic()) {
159 return sk_ref_sp(this);
160 }
161
162 // Use CopyAsDraw directly to perform the color space changes. The copied image is not
163 // considered budgeted because this is a client-invoked API and they will own the image.
164 return CopyAsDraw(recorder,
165 this,
166 this->bounds(),
167 dstColorInfo,
169 requiredProps.fMipmapped ? Mipmapped::kYes : Mipmapped::kNo,
171}
172
173// Ganesh APIs are no-ops
174
176 SKGPU_LOG_W("Cannot convert Graphite-backed image to Ganesh");
177 return nullptr;
178}
179
182 GrDirectContext*) const {
183 SKGPU_LOG_W("Cannot convert Graphite-backed image to Ganesh");
184 return nullptr;
185}
186
188 SkIRect srcRect,
189 RescaleGamma rescaleGamma,
190 RescaleMode rescaleMode,
192 ReadPixelsContext context) const {
193 SKGPU_LOG_W("Cannot use Ganesh async API with Graphite-backed image, use API on Context");
194 callback(context, nullptr);
195}
196
198 bool readAlpha,
199 sk_sp<SkColorSpace> dstColorSpace,
200 const SkIRect srcRect,
201 const SkISize dstSize,
202 RescaleGamma rescaleGamma,
203 RescaleMode rescaleMode,
205 ReadPixelsContext context) const {
206 SKGPU_LOG_W("Cannot use Ganesh async API with Graphite-backed image, use API on Context");
207 callback(context, nullptr);
208}
209
210} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBackingFit
SkColorType
Definition SkColorType.h:19
SkYUVColorSpace
Definition SkImageInfo.h:68
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
SkColorInfo makeAlphaType(SkAlphaType newAlphaType) const
virtual GrImageContext * context() const
const SkImageInfo & imageInfo() const
Definition SkImage.h:279
void * ReadPixelsContext
Definition SkImage.h:578
SkAlphaType alphaType() const
Definition SkImage.cpp:154
RescaleMode
Definition SkImage.h:587
RescaleGamma
Definition SkImage.h:585
SkIRect bounds() const
Definition SkImage.h:303
void(ReadPixelsContext, std::unique_ptr< const AsyncReadResult >) ReadPixelsCallback
Definition SkImage.h:583
Image_Base(const SkImageInfo &info, uint32_t uniqueID)
void onAsyncRescaleAndReadPixels(const SkImageInfo &, SkIRect srcRect, RescaleGamma, RescaleMode, ReadPixelsCallback, ReadPixelsContext) const override
virtual sk_sp< Image > copyImage(Recorder *, const SkIRect &subset, Budgeted, Mipmapped, SkBackingFit) const
sk_sp< SkImage > onMakeSubset(Recorder *, const SkIRect &, RequiredProperties) const override
sk_sp< SkImage > makeColorTypeAndColorSpace(Recorder *, SkColorType targetCT, sk_sp< SkColorSpace > targetCS, RequiredProperties) const override
void notifyInUse(Recorder *) const
sk_sp< SkImage > onMakeColorTypeAndColorSpace(SkColorType, sk_sp< SkColorSpace >, GrDirectContext *) const override
static sk_sp< Image > CopyAsDraw(Recorder *, const Image_Base *, const SkIRect &subset, const SkColorInfo &dstColorInfo, Budgeted, Mipmapped, SkBackingFit)
void linkDevices(const Image_Base *)
void onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace, bool readAlpha, sk_sp< SkColorSpace >, SkIRect srcRect, SkISize dstSize, RescaleGamma, RescaleMode, ReadPixelsCallback, ReadPixelsContext) const override
static sk_sp< Surface > MakeScratch(Recorder *recorder, const SkImageInfo &info, Budgeted budgeted=Budgeted::kYes, Mipmapped mipmapped=Mipmapped::kNo, SkBackingFit backingFit=SkBackingFit::kApprox)
const Paint & paint
VkDevice device
Definition main.cc:53
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
Budgeted
Definition GpuTypes.h:35
Mipmapped
Definition GpuTypes.h:53
constexpr int32_t top() const
Definition SkRect.h:120
constexpr SkISize size() const
Definition SkRect.h:172
constexpr int32_t left() const
Definition SkRect.h:113
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)