• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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/gpu/graphite/Image_Graphite.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkSurface.h"
13 #include "include/gpu/graphite/BackendTexture.h"
14 #include "include/gpu/graphite/Recorder.h"
15 #include "src/gpu/RefCntedCallback.h"
16 #include "src/gpu/graphite/Caps.h"
17 #include "src/gpu/graphite/Log.h"
18 #include "src/gpu/graphite/RecorderPriv.h"
19 #include "src/gpu/graphite/ResourceProvider.h"
20 #include "src/gpu/graphite/Texture.h"
21 
22 namespace skgpu::graphite {
23 
Image(uint32_t uniqueID,TextureProxyView view,const SkColorInfo & info)24 Image::Image(uint32_t uniqueID,
25              TextureProxyView view,
26              const SkColorInfo& info)
27     : Image_Base(SkImageInfo::Make(view.proxy()->dimensions(), info), uniqueID)
28     , fTextureProxyView(std::move(view)) {
29 }
30 
Image(TextureProxyView view,const SkColorInfo & info)31 Image::Image(TextureProxyView view,
32              const SkColorInfo& info)
33     : Image_Base(SkImageInfo::Make(view.proxy()->dimensions(), info), kNeedNewImageUniqueID)
34     , fTextureProxyView(std::move(view)) {
35 }
36 
~Image()37 Image::~Image() {}
38 
onMakeSubset(const SkIRect & subset,Recorder * recorder,RequiredImageProperties requiredProps) const39 sk_sp<SkImage> Image::onMakeSubset(const SkIRect& subset,
40                                    Recorder* recorder,
41                                    RequiredImageProperties requiredProps) const {
42     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
43 
44     // optimization : return self if the subset == our bounds and requirements met
45     if (bounds == subset && (requiredProps.fMipmapped == Mipmapped::kNo || this->hasMipmaps())) {
46         const SkImage* image = this;
47         return sk_ref_sp(const_cast<SkImage*>(image));
48     }
49 
50     return this->copyImage(subset, recorder, requiredProps);
51 }
52 
onMakeTextureImage(Recorder * recorder,RequiredImageProperties requiredProps) const53 sk_sp<SkImage> Image::onMakeTextureImage(Recorder* recorder,
54                                          RequiredImageProperties requiredProps) const {
55     if (requiredProps.fMipmapped == Mipmapped::kNo || this->hasMipmaps()) {
56         const SkImage* image = this;
57         return sk_ref_sp(const_cast<SkImage*>(image));
58     }
59 
60     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
61     return this->copyImage(bounds, recorder, requiredProps);
62 }
63 
copyImage(const SkIRect & subset,Recorder * recorder,RequiredImageProperties requiredProps) const64 sk_sp<SkImage> Image::copyImage(const SkIRect& subset,
65                                 Recorder* recorder,
66                                 RequiredImageProperties requiredProps) const {
67     TextureProxyView srcView = this->textureProxyView();
68     if (!srcView) {
69         return nullptr;
70     }
71 
72     TextureProxyView copiedView = TextureProxyView::Copy(recorder,
73                                                          this->imageInfo().colorInfo(),
74                                                          srcView,
75                                                          subset,
76                                                          requiredProps.fMipmapped);
77     if (!copiedView) {
78         return nullptr;
79     }
80 
81     return sk_sp<Image>(new Image(kNeedNewImageUniqueID,
82                                   std::move(copiedView),
83                                   this->imageInfo().colorInfo()));
84 }
85 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const86 sk_sp<SkImage> Image::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
87     return sk_make_sp<Image>(kNeedNewImageUniqueID,
88                              fTextureProxyView,
89                              this->imageInfo().colorInfo().makeColorSpace(std::move(newCS)));
90 }
91 
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,Recorder * recorder,RequiredImageProperties requiredProps) const92 sk_sp<SkImage> Image::onMakeColorTypeAndColorSpace(SkColorType targetCT,
93                                                    sk_sp<SkColorSpace> targetCS,
94                                                    Recorder* recorder,
95                                                    RequiredImageProperties requiredProps) const {
96     SkAlphaType at = (this->alphaType() == kOpaque_SkAlphaType) ? kPremul_SkAlphaType
97                                                                 : this->alphaType();
98 
99     SkImageInfo ii = SkImageInfo::Make(this->dimensions(), targetCT, at, std::move(targetCS));
100 
101     sk_sp<SkSurface> s = SkSurface::MakeGraphite(recorder, ii, requiredProps.fMipmapped);
102     if (!s) {
103         return nullptr;
104     }
105 
106     s->getCanvas()->drawImage(this, 0, 0);
107 
108     return s->asImage();
109 }
110 
111 } // namespace skgpu::graphite
112 
113 using namespace skgpu::graphite;
114 
115 namespace {
116 
validate_backend_texture(const Caps * caps,const BackendTexture & texture,const SkColorInfo & info)117 bool validate_backend_texture(const Caps* caps,
118                               const BackendTexture& texture,
119                               const SkColorInfo& info) {
120     if (!texture.isValid() ||
121         texture.dimensions().width() <= 0 ||
122         texture.dimensions().height() <= 0) {
123         return false;
124     }
125 
126     if (!SkColorInfoIsValid(info)) {
127         return false;
128     }
129 
130     if (!caps->isTexturable(texture.info())) {
131         return false;
132     }
133 
134     return caps->areColorTypeAndTextureInfoCompatible(info.colorType(), texture.info());
135 }
136 
137 } // anonymous namespace
138 
MakePromiseImageLazyProxy(SkISize dimensions,TextureInfo textureInfo,Volatile isVolatile,GraphitePromiseImageFulfillProc fulfillProc,sk_sp<skgpu::RefCntedCallback> releaseHelper,GraphitePromiseTextureReleaseProc textureReleaseProc)139 sk_sp<TextureProxy> Image::MakePromiseImageLazyProxy(
140         SkISize dimensions,
141         TextureInfo textureInfo,
142         Volatile isVolatile,
143         GraphitePromiseImageFulfillProc fulfillProc,
144         sk_sp<skgpu::RefCntedCallback> releaseHelper,
145         GraphitePromiseTextureReleaseProc textureReleaseProc) {
146     SkASSERT(!dimensions.isEmpty());
147     SkASSERT(releaseHelper);
148 
149     if (!fulfillProc) {
150         return nullptr;
151     }
152 
153     /**
154      * This class is the lazy instantiation callback for promise images. It manages calling the
155      * client's Fulfill, ImageRelease, and TextureRelease procs.
156      */
157     class PromiseLazyInstantiateCallback {
158     public:
159         PromiseLazyInstantiateCallback(GraphitePromiseImageFulfillProc fulfillProc,
160                                        sk_sp<skgpu::RefCntedCallback> releaseHelper,
161                                        GraphitePromiseTextureReleaseProc textureReleaseProc)
162                 : fFulfillProc(fulfillProc)
163                 , fReleaseHelper(std::move(releaseHelper))
164                 , fTextureReleaseProc(textureReleaseProc) {
165         }
166         PromiseLazyInstantiateCallback(PromiseLazyInstantiateCallback&&) = default;
167         PromiseLazyInstantiateCallback(const PromiseLazyInstantiateCallback&) {
168             // Because we get wrapped in std::function we must be copyable. But we should never
169             // be copied.
170             SkASSERT(false);
171         }
172         PromiseLazyInstantiateCallback& operator=(PromiseLazyInstantiateCallback&&) = default;
173         PromiseLazyInstantiateCallback& operator=(const PromiseLazyInstantiateCallback&) {
174             SkASSERT(false);
175             return *this;
176         }
177 
178         sk_sp<Texture> operator()(ResourceProvider* resourceProvider) {
179 
180             auto [ backendTexture, textureReleaseCtx ] = fFulfillProc(fReleaseHelper->context());
181             if (!backendTexture.isValid()) {
182                 SKGPU_LOG_W("FulFill Proc failed");
183                 return nullptr;
184             }
185 
186             sk_sp<RefCntedCallback> textureReleaseCB = RefCntedCallback::Make(fTextureReleaseProc,
187                                                                               textureReleaseCtx);
188 
189             sk_sp<Texture> texture = resourceProvider->createWrappedTexture(backendTexture);
190             if (!texture) {
191                 SKGPU_LOG_W("Texture creation failed");
192                 return nullptr;
193             }
194 
195             texture->setReleaseCallback(std::move(textureReleaseCB));
196             return texture;
197         }
198 
199     private:
200         GraphitePromiseImageFulfillProc fFulfillProc;
201         sk_sp<skgpu::RefCntedCallback> fReleaseHelper;
202         GraphitePromiseTextureReleaseProc fTextureReleaseProc;
203 
204     } callback(fulfillProc, std::move(releaseHelper), textureReleaseProc);
205 
206     return TextureProxy::MakeLazy(dimensions,
207                                   textureInfo,
208                                   skgpu::Budgeted::kNo,  // This is destined for a user's SkImage
209                                   isVolatile,
210                                   std::move(callback));
211 }
212 
MakeGraphitePromiseTexture(Recorder * recorder,SkISize dimensions,const TextureInfo & textureInfo,const SkColorInfo & colorInfo,Volatile isVolatile,GraphitePromiseImageFulfillProc fulfillProc,GraphitePromiseImageReleaseProc imageReleaseProc,GraphitePromiseTextureReleaseProc textureReleaseProc,GraphitePromiseImageContext imageContext)213 sk_sp<SkImage> SkImage::MakeGraphitePromiseTexture(
214         Recorder* recorder,
215         SkISize dimensions,
216         const TextureInfo& textureInfo,
217         const SkColorInfo& colorInfo,
218         Volatile isVolatile,
219         GraphitePromiseImageFulfillProc fulfillProc,
220         GraphitePromiseImageReleaseProc imageReleaseProc,
221         GraphitePromiseTextureReleaseProc textureReleaseProc,
222         GraphitePromiseImageContext imageContext) {
223 
224     // Our contract is that we will always call the _image_ release proc even on failure.
225     // We use the helper to convey the imageContext, so we need to ensure Make doesn't fail.
226     imageReleaseProc = imageReleaseProc ? imageReleaseProc : [](void*) {};
227     auto releaseHelper = skgpu::RefCntedCallback::Make(imageReleaseProc, imageContext);
228 
229     if (!recorder) {
230         SKGPU_LOG_W("Null Recorder");
231         return nullptr;
232     }
233 
234     const Caps* caps = recorder->priv().caps();
235 
236     SkImageInfo info = SkImageInfo::Make(dimensions, colorInfo);
237     if (!SkImageInfoIsValid(info)) {
238         SKGPU_LOG_W("Invalid SkImageInfo");
239         return nullptr;
240     }
241 
242     if (!caps->areColorTypeAndTextureInfoCompatible(colorInfo.colorType(), textureInfo)) {
243         SKGPU_LOG_W("Incompatible SkColorType and TextureInfo");
244         return nullptr;
245     }
246 
247     sk_sp<TextureProxy> proxy = Image::MakePromiseImageLazyProxy(dimensions,
248                                                                  textureInfo,
249                                                                  isVolatile,
250                                                                  fulfillProc,
251                                                                  std::move(releaseHelper),
252                                                                  textureReleaseProc);
253     if (!proxy) {
254         return nullptr;
255     }
256 
257     skgpu::Swizzle swizzle = caps->getReadSwizzle(colorInfo.colorType(), textureInfo);
258     TextureProxyView view(std::move(proxy), swizzle);
259     return sk_make_sp<Image>(view, colorInfo);
260 }
261 
MakeGraphiteFromBackendTexture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)262 sk_sp<SkImage> SkImage::MakeGraphiteFromBackendTexture(Recorder* recorder,
263                                                        const BackendTexture& backendTex,
264                                                        SkColorType ct,
265                                                        SkAlphaType at,
266                                                        sk_sp<SkColorSpace> cs) {
267     if (!recorder) {
268         return nullptr;
269     }
270 
271     const Caps* caps = recorder->priv().caps();
272 
273     SkColorInfo info(ct, at, std::move(cs));
274 
275     if (!validate_backend_texture(caps, backendTex, info)) {
276         return nullptr;
277     }
278 
279     sk_sp<Texture> texture = recorder->priv().resourceProvider()->createWrappedTexture(backendTex);
280     if (!texture) {
281         return nullptr;
282     }
283 
284     sk_sp<TextureProxy> proxy(new TextureProxy(std::move(texture)));
285 
286     skgpu::Swizzle swizzle = caps->getReadSwizzle(ct, backendTex.info());
287     TextureProxyView view(std::move(proxy), swizzle);
288     return sk_make_sp<Image>(view, info);
289 }
290