• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 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 
8 #include "src/image/SkImage_Gpu.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageGenerator.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkPixmap.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkSurface.h"
21 #include "include/gpu/GpuTypes.h"
22 #include "include/gpu/GrBackendSurface.h"
23 #include "include/gpu/GrContextThreadSafeProxy.h"
24 #include "include/gpu/GrDirectContext.h"
25 #include "include/gpu/GrRecordingContext.h"
26 #include "include/gpu/GrTypes.h"
27 #include "include/private/base/SkAssert.h"
28 #include "include/private/gpu/ganesh/GrImageContext.h"
29 #include "include/private/gpu/ganesh/GrTypesPriv.h"
30 #include "src/core/SkAutoPixmapStorage.h"
31 #include "src/core/SkImageInfoPriv.h"
32 #include "src/gpu/RefCntedCallback.h"
33 #include "src/gpu/SkBackingFit.h"
34 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
35 #include "src/gpu/ganesh/GrBackendUtils.h"
36 #include "src/gpu/ganesh/GrCaps.h"
37 #include "src/gpu/ganesh/GrColorInfo.h"
38 #include "src/gpu/ganesh/GrColorSpaceXform.h"
39 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
40 #include "src/gpu/ganesh/GrDirectContextPriv.h"
41 #include "src/gpu/ganesh/GrFragmentProcessor.h"
42 #include "src/gpu/ganesh/GrGpu.h"
43 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
44 #include "src/gpu/ganesh/GrImageContextPriv.h"
45 #include "src/gpu/ganesh/GrImageInfo.h"
46 #include "src/gpu/ganesh/GrProxyProvider.h"
47 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
48 #include "src/gpu/ganesh/GrRenderTask.h"
49 #include "src/gpu/ganesh/GrSemaphore.h"
50 #include "src/gpu/ganesh/GrSurfaceProxy.h"
51 #include "src/gpu/ganesh/GrTexture.h"
52 #include "src/gpu/ganesh/GrTextureProxy.h"
53 #include "src/gpu/ganesh/SkGr.h"
54 #include "src/gpu/ganesh/SurfaceContext.h"
55 #include "src/gpu/ganesh/SurfaceFillContext.h"
56 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
57 #include "src/image/SkImage_Base.h"
58 
59 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
60 #include "src/gpu/ganesh/GrAHardwareBufferImageGenerator.h"
61 #include "src/gpu/ganesh/GrAHardwareBufferUtils_impl.h"
62 #endif
63 
64 #include <algorithm>
65 #include <cstddef>
66 #include <utility>
67 
68 class SkMatrix;
69 enum SkColorType : int;
70 enum class SkTileMode;
71 
ProxyChooser(sk_sp<GrSurfaceProxy> stableProxy)72 inline SkImage_Gpu::ProxyChooser::ProxyChooser(sk_sp<GrSurfaceProxy> stableProxy)
73         : fStableProxy(std::move(stableProxy)) {
74     SkASSERT(fStableProxy);
75 }
76 
ProxyChooser(sk_sp<GrSurfaceProxy> stableProxy,sk_sp<GrSurfaceProxy> volatileProxy,sk_sp<GrRenderTask> copyTask,int volatileProxyTargetCount)77 inline SkImage_Gpu::ProxyChooser::ProxyChooser(sk_sp<GrSurfaceProxy> stableProxy,
78                                                sk_sp<GrSurfaceProxy> volatileProxy,
79                                                sk_sp<GrRenderTask> copyTask,
80                                                int volatileProxyTargetCount)
81         : fStableProxy(std::move(stableProxy))
82         , fVolatileProxy(std::move(volatileProxy))
83         , fVolatileToStableCopyTask(std::move(copyTask))
84         , fVolatileProxyTargetCount(volatileProxyTargetCount) {
85     SkASSERT(fStableProxy);
86     SkASSERT(fVolatileProxy);
87     SkASSERT(fVolatileToStableCopyTask);
88 }
89 
~ProxyChooser()90 inline SkImage_Gpu::ProxyChooser::~ProxyChooser() {
91     // The image is being destroyed. If there is a stable copy proxy but we've been able to use
92     // the volatile proxy for all requests then we can skip the copy.
93     if (fVolatileToStableCopyTask) {
94         fVolatileToStableCopyTask->makeSkippable();
95     }
96 }
97 
chooseProxy(GrRecordingContext * context)98 inline sk_sp<GrSurfaceProxy> SkImage_Gpu::ProxyChooser::chooseProxy(GrRecordingContext* context) {
99     SkAutoSpinlock hold(fLock);
100     if (fVolatileProxy) {
101         SkASSERT(fVolatileProxyTargetCount <= fVolatileProxy->getTaskTargetCount());
102         // If this image is used off the direct context it originated on, i.e. on a recording-only
103         // context, we don't know how the recording context's actions are ordered WRT direct context
104         // actions until the recording context's DAG is imported into the direct context.
105         if (context->asDirectContext() &&
106             fVolatileProxyTargetCount == fVolatileProxy->getTaskTargetCount()) {
107             return fVolatileProxy;
108         }
109         fVolatileProxy.reset();
110         fVolatileToStableCopyTask.reset();
111         return fStableProxy;
112     }
113     return fStableProxy;
114 }
115 
switchToStableProxy()116 inline sk_sp<GrSurfaceProxy> SkImage_Gpu::ProxyChooser::switchToStableProxy() {
117     SkAutoSpinlock hold(fLock);
118     fVolatileProxy.reset();
119     fVolatileToStableCopyTask.reset();
120     return fStableProxy;
121 }
122 
makeVolatileProxyStable()123 inline sk_sp<GrSurfaceProxy> SkImage_Gpu::ProxyChooser::makeVolatileProxyStable() {
124     SkAutoSpinlock hold(fLock);
125     if (fVolatileProxy) {
126         fStableProxy = std::move(fVolatileProxy);
127         fVolatileToStableCopyTask->makeSkippable();
128         fVolatileToStableCopyTask.reset();
129     }
130     return fStableProxy;
131 }
132 
surfaceMustCopyOnWrite(GrSurfaceProxy * surfaceProxy) const133 inline bool SkImage_Gpu::ProxyChooser::surfaceMustCopyOnWrite(GrSurfaceProxy* surfaceProxy) const {
134     SkAutoSpinlock hold(fLock);
135     return surfaceProxy->underlyingUniqueID() == fStableProxy->underlyingUniqueID();
136 }
137 
gpuMemorySize() const138 inline size_t SkImage_Gpu::ProxyChooser::gpuMemorySize() const {
139     SkAutoSpinlock hold(fLock);
140     size_t size = fStableProxy->gpuMemorySize();
141     if (fVolatileProxy) {
142         SkASSERT(fVolatileProxy->gpuMemorySize() == size);
143     }
144     return size;
145 }
146 
mipmapped() const147 inline GrMipmapped SkImage_Gpu::ProxyChooser::mipmapped() const {
148     SkAutoSpinlock hold(fLock);
149     GrMipmapped mipmapped = fStableProxy->asTextureProxy()->mipmapped();
150     if (fVolatileProxy) {
151         SkASSERT(fVolatileProxy->asTextureProxy()->mipmapped() == mipmapped);
152     }
153     return mipmapped;
154 }
155 
156 #ifdef SK_DEBUG
backendFormat()157 inline GrBackendFormat SkImage_Gpu::ProxyChooser::backendFormat() {
158     SkAutoSpinlock hold(fLock);
159     if (fVolatileProxy) {
160         SkASSERT(fVolatileProxy->backendFormat() == fStableProxy->backendFormat());
161     }
162     return fStableProxy->backendFormat();
163 }
164 #endif
165 
166 //////////////////////////////////////////////////////////////////////////////
167 
SkImage_Gpu(sk_sp<GrImageContext> context,uint32_t uniqueID,GrSurfaceProxyView view,SkColorInfo info)168 SkImage_Gpu::SkImage_Gpu(sk_sp<GrImageContext> context,
169                          uint32_t uniqueID,
170                          GrSurfaceProxyView view,
171                          SkColorInfo info)
172         : INHERITED(std::move(context),
173                     SkImageInfo::Make(view.proxy()->backingStoreDimensions(), std::move(info)),
174                     uniqueID)
175         , fChooser(view.detachProxy())
176         , fSwizzle(view.swizzle())
177         , fOrigin(view.origin()) {
178 #ifdef SK_DEBUG
179     const GrBackendFormat& format = fChooser.backendFormat();
180     const GrCaps* caps = this->context()->priv().caps();
181     GrColorType grCT = SkColorTypeToGrColorType(this->colorType());
182     SkASSERT(caps->isFormatCompressed(format) ||
183              caps->areColorTypeAndFormatCompatible(grCT, format));
184 #endif
185 }
186 
SkImage_Gpu(sk_sp<GrDirectContext> dContext,GrSurfaceProxyView volatileSrc,sk_sp<GrSurfaceProxy> stableCopy,sk_sp<GrRenderTask> copyTask,int volatileSrcTargetCount,SkColorInfo info)187 SkImage_Gpu::SkImage_Gpu(sk_sp<GrDirectContext> dContext,
188                          GrSurfaceProxyView volatileSrc,
189                          sk_sp<GrSurfaceProxy> stableCopy,
190                          sk_sp<GrRenderTask> copyTask,
191                          int volatileSrcTargetCount,
192                          SkColorInfo info)
193         : INHERITED(std::move(dContext),
194                     SkImageInfo::Make(volatileSrc.proxy()->backingStoreDimensions(),
195                                       std::move(info)),
196                     kNeedNewImageUniqueID)
197         , fChooser(std::move(stableCopy),
198                    volatileSrc.detachProxy(),
199                    std::move(copyTask),
200                    volatileSrcTargetCount)
201         , fSwizzle(volatileSrc.swizzle())
202         , fOrigin(volatileSrc.origin()) {
203 #ifdef SK_DEBUG
204     const GrBackendFormat& format = fChooser.backendFormat();
205     const GrCaps* caps = this->context()->priv().caps();
206     GrColorType grCT = SkColorTypeToGrColorType(this->colorType());
207     SkASSERT(caps->isFormatCompressed(format) ||
208              caps->areColorTypeAndFormatCompatible(grCT, format));
209 #endif
210 }
211 
MakeWithVolatileSrc(sk_sp<GrRecordingContext> rContext,GrSurfaceProxyView volatileSrc,SkColorInfo colorInfo)212 sk_sp<SkImage> SkImage_Gpu::MakeWithVolatileSrc(sk_sp<GrRecordingContext> rContext,
213                                                 GrSurfaceProxyView volatileSrc,
214                                                 SkColorInfo colorInfo) {
215     SkASSERT(rContext);
216     SkASSERT(volatileSrc);
217     SkASSERT(volatileSrc.proxy()->asTextureProxy());
218     GrMipmapped mm = volatileSrc.proxy()->asTextureProxy()->mipmapped();
219     sk_sp<GrRenderTask> copyTask;
220     auto copy = GrSurfaceProxy::Copy(rContext.get(),
221                                      volatileSrc.refProxy(),
222                                      volatileSrc.origin(),
223                                      mm,
224                                      SkBackingFit::kExact,
225                                      skgpu::Budgeted::kYes,
226                                      /*label=*/"ImageGpu_MakeWithVolatileSrc",
227                                      &copyTask);
228     if (!copy) {
229         return nullptr;
230     }
231     // We only attempt to make a dual-proxy image on a direct context. This optimziation requires
232     // knowing how things are ordered and recording-only contexts are not well ordered WRT other
233     // recording contexts.
234     if (auto direct = sk_ref_sp(rContext->asDirectContext())) {
235         int targetCount = volatileSrc.proxy()->getTaskTargetCount();
236         return sk_sp<SkImage>(new SkImage_Gpu(std::move(direct),
237                                               std::move(volatileSrc),
238                                               std::move(copy),
239                                               std::move(copyTask),
240                                               targetCount,
241                                               std::move(colorInfo)));
242     }
243     GrSurfaceProxyView copyView(std::move(copy), volatileSrc.origin(), volatileSrc.swizzle());
244     return sk_make_sp<SkImage_Gpu>(std::move(rContext),
245                                    kNeedNewImageUniqueID,
246                                    std::move(copyView),
247                                    std::move(colorInfo));
248 }
249 
250 SkImage_Gpu::~SkImage_Gpu() = default;
251 
surfaceMustCopyOnWrite(GrSurfaceProxy * surfaceProxy) const252 bool SkImage_Gpu::surfaceMustCopyOnWrite(GrSurfaceProxy* surfaceProxy) const {
253     return fChooser.surfaceMustCopyOnWrite(surfaceProxy);
254 }
255 
onHasMipmaps() const256 bool SkImage_Gpu::onHasMipmaps() const { return fChooser.mipmapped() == GrMipmapped::kYes; }
257 
onFlush(GrDirectContext * dContext,const GrFlushInfo & info) const258 GrSemaphoresSubmitted SkImage_Gpu::onFlush(GrDirectContext* dContext,
259                                            const GrFlushInfo& info) const {
260     if (!fContext->priv().matches(dContext) || dContext->abandoned()) {
261         if (info.fSubmittedProc) {
262             info.fSubmittedProc(info.fSubmittedContext, false);
263         }
264         if (info.fFinishedProc) {
265             info.fFinishedProc(info.fFinishedContext);
266         }
267         return GrSemaphoresSubmitted::kNo;
268     }
269 
270     sk_sp<GrSurfaceProxy> proxy = fChooser.chooseProxy(dContext);
271     return dContext->priv().flushSurface(proxy.get(),
272                                          SkSurface::BackendSurfaceAccess::kNoAccess,
273                                          info);
274 }
275 
onGetBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const276 GrBackendTexture SkImage_Gpu::onGetBackendTexture(bool flushPendingGrContextIO,
277                                                   GrSurfaceOrigin* origin) const {
278     auto direct = fContext->asDirectContext();
279     if (!direct) {
280         // This image was created with a DDL context and cannot be instantiated.
281         return GrBackendTexture();  // invalid
282     }
283     if (direct->abandoned()) {
284         return GrBackendTexture();  // invalid;
285     }
286 
287     // We don't know how client's use of the texture will be ordered WRT Skia's. Ensure the
288     // texture seen by the client won't be mutated by a SkSurface.
289     sk_sp<GrSurfaceProxy> proxy = fChooser.switchToStableProxy();
290 
291     if (!proxy->isInstantiated()) {
292         auto resourceProvider = direct->priv().resourceProvider();
293 
294         if (!proxy->instantiate(resourceProvider)) {
295             return GrBackendTexture();  // invalid
296         }
297     }
298 
299     GrTexture* texture = proxy->peekTexture();
300     if (texture) {
301         if (flushPendingGrContextIO) {
302             direct->priv().flushSurface(proxy.get());
303         }
304         if (origin) {
305             *origin = fOrigin;
306         }
307         return texture->getBackendTexture();
308     }
309     return GrBackendTexture();  // invalid
310 }
311 
onTextureSize() const312 size_t SkImage_Gpu::onTextureSize() const { return fChooser.gpuMemorySize(); }
313 
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext * dContext) const314 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(SkColorType targetCT,
315                                                          sk_sp<SkColorSpace> targetCS,
316                                                          GrDirectContext* dContext) const {
317     SkColorInfo info(targetCT, this->alphaType(), std::move(targetCS));
318     if (!fContext->priv().matches(dContext)) {
319         return nullptr;
320     }
321 
322     auto sfc = dContext->priv().makeSFCWithFallback(GrImageInfo(info, this->dimensions()),
323                                                     SkBackingFit::kExact);
324     if (!sfc) {
325         return nullptr;
326     }
327     // We respecify info's CT because we called MakeWithFallback.
328     auto ct = GrColorTypeToSkColorType(sfc->colorInfo().colorType());
329     info = info.makeColorType(ct);
330 
331     // Draw this image's texture into the SFC.
332     auto [view, _] = this->asView(dContext, GrMipmapped(this->hasMipmaps()));
333     auto texFP = GrTextureEffect::Make(std::move(view), this->alphaType());
334     auto colorFP = GrColorSpaceXformEffect::Make(std::move(texFP),
335                                                  this->imageInfo().colorInfo(),
336                                                  info);
337     sfc->fillWithFP(std::move(colorFP));
338 
339     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext),
340                                    kNeedNewImageUniqueID,
341                                    sfc->readSurfaceView(),
342                                    std::move(info));
343 }
344 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const345 sk_sp<SkImage> SkImage_Gpu::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
346     // It doesn't seem worth the complexity of trying to share the ProxyChooser among multiple
347     // images. Just fall back to the stable copy.
348     GrSurfaceProxyView view(fChooser.switchToStableProxy(), fOrigin, fSwizzle);
349     return sk_make_sp<SkImage_Gpu>(fContext,
350                                    kNeedNewImageUniqueID,
351                                    std::move(view),
352                                    this->imageInfo().colorInfo().makeColorSpace(std::move(newCS)));
353 }
354 
onAsyncRescaleAndReadPixels(const SkImageInfo & info,SkIRect srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const355 void SkImage_Gpu::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
356                                               SkIRect srcRect,
357                                               RescaleGamma rescaleGamma,
358                                               RescaleMode rescaleMode,
359                                               ReadPixelsCallback callback,
360                                               ReadPixelsContext context) const {
361     auto dContext = fContext->asDirectContext();
362     if (!dContext) {
363         // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
364         callback(context, nullptr);
365         return;
366     }
367     auto ctx = dContext->priv().makeSC(this->makeView(dContext), this->imageInfo().colorInfo());
368     if (!ctx) {
369         callback(context, nullptr);
370         return;
371     }
372     ctx->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode,
373                                    callback, context);
374 }
375 
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,SkIRect srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const376 void SkImage_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
377                                                     sk_sp<SkColorSpace> dstColorSpace,
378                                                     SkIRect srcRect,
379                                                     SkISize dstSize,
380                                                     RescaleGamma rescaleGamma,
381                                                     RescaleMode rescaleMode,
382                                                     ReadPixelsCallback callback,
383                                                     ReadPixelsContext context) const {
384     auto dContext = fContext->asDirectContext();
385     if (!dContext) {
386         // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
387         callback(context, nullptr);
388         return;
389     }
390     auto ctx = dContext->priv().makeSC(this->makeView(dContext), this->imageInfo().colorInfo());
391     if (!ctx) {
392         callback(context, nullptr);
393         return;
394     }
395     ctx->asyncRescaleAndReadPixelsYUV420(dContext,
396                                          yuvColorSpace,
397                                          std::move(dstColorSpace),
398                                          srcRect,
399                                          dstSize,
400                                          rescaleGamma,
401                                          rescaleMode,
402                                          callback,
403                                          context);
404 }
405 
generatingSurfaceIsDeleted()406 void SkImage_Gpu::generatingSurfaceIsDeleted() { fChooser.makeVolatileProxyStable(); }
407 
408 ///////////////////////////////////////////////////////////////////////////////////////////////////
409 
new_wrapped_texture_common(GrRecordingContext * rContext,const GrBackendTexture & backendTex,GrColorType colorType,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,GrWrapOwnership ownership,sk_sp<skgpu::RefCntedCallback> releaseHelper)410 static sk_sp<SkImage> new_wrapped_texture_common(GrRecordingContext* rContext,
411                                                  const GrBackendTexture& backendTex,
412                                                  GrColorType colorType,
413                                                  GrSurfaceOrigin origin,
414                                                  SkAlphaType at,
415                                                  sk_sp<SkColorSpace> colorSpace,
416                                                  GrWrapOwnership ownership,
417                                                  sk_sp<skgpu::RefCntedCallback> releaseHelper) {
418     if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
419         return nullptr;
420     }
421 
422     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
423     sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
424             backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
425     if (!proxy) {
426         return nullptr;
427     }
428 
429     skgpu::Swizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
430                                                                      colorType);
431     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
432     SkColorInfo info(GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
433     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(rContext),
434                                    kNeedNewImageUniqueID,
435                                    std::move(view),
436                                    std::move(info));
437 }
438 
MakeFromCompressedTexture(GrRecordingContext * rContext,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)439 sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrRecordingContext* rContext,
440                                                   const GrBackendTexture& tex,
441                                                   GrSurfaceOrigin origin,
442                                                   SkAlphaType at,
443                                                   sk_sp<SkColorSpace> cs,
444                                                   TextureReleaseProc releaseP,
445                                                   ReleaseContext releaseC) {
446     auto releaseHelper = skgpu::RefCntedCallback::Make(releaseP, releaseC);
447 
448     if (!rContext) {
449         return nullptr;
450     }
451 
452     const GrCaps* caps = rContext->priv().caps();
453 
454     if (!SkImage_GpuBase::ValidateCompressedBackendTexture(caps, tex, at)) {
455         return nullptr;
456     }
457 
458     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
459     sk_sp<GrTextureProxy> proxy = proxyProvider->wrapCompressedBackendTexture(
460             tex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, std::move(releaseHelper));
461     if (!proxy) {
462         return nullptr;
463     }
464 
465     CompressionType type = GrBackendFormatToCompressionType(tex.getBackendFormat());
466     SkColorType ct = GrCompressionTypeToSkColorType(type);
467 
468     GrSurfaceProxyView view(std::move(proxy), origin, skgpu::Swizzle::RGBA());
469     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(rContext),
470                                    kNeedNewImageUniqueID,
471                                    std::move(view),
472                                    SkColorInfo(ct, at, std::move(cs)));
473 }
474 
MakeFromTexture(GrRecordingContext * rContext,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)475 sk_sp<SkImage> SkImage::MakeFromTexture(GrRecordingContext* rContext,
476                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
477                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
478                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
479     auto releaseHelper = skgpu::RefCntedCallback::Make(releaseP, releaseC);
480 
481     if (!rContext) {
482         return nullptr;
483     }
484 
485     const GrCaps* caps = rContext->priv().caps();
486 
487     GrColorType grColorType = SkColorTypeToGrColorType(ct);
488     if (GrColorType::kUnknown == grColorType) {
489         return nullptr;
490     }
491 
492     if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
493         return nullptr;
494     }
495 
496     return new_wrapped_texture_common(rContext, tex, grColorType, origin, at, std::move(cs),
497                                       kBorrow_GrWrapOwnership, std::move(releaseHelper));
498 }
499 
MakeFromAdoptedTexture(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType)500 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext* context,
501                                                const GrBackendTexture& backendTexture,
502                                                GrSurfaceOrigin textureOrigin,
503                                                SkColorType colorType) {
504     return SkImage::MakeFromAdoptedTexture(context, backendTexture, textureOrigin,
505                                            colorType, kPremul_SkAlphaType, nullptr);
506 }
MakeFromAdoptedTexture(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType,SkAlphaType alphaType)507 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext* context,
508                                                const GrBackendTexture& backendTexture,
509                                                GrSurfaceOrigin textureOrigin,
510                                                SkColorType colorType,
511                                                SkAlphaType alphaType) {
512     return SkImage::MakeFromAdoptedTexture(context, backendTexture, textureOrigin,
513                                            colorType, alphaType, nullptr);
514 }
515 
MakeFromAdoptedTexture(GrRecordingContext * rContext,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)516 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext* rContext,
517                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
518                                                SkColorType ct, SkAlphaType at,
519                                                sk_sp<SkColorSpace> cs) {
520     auto dContext = GrAsDirectContext(rContext);
521     if (!dContext) {
522         // We have a DDL context and we don't support adopted textures for them.
523         return nullptr;
524     }
525 
526     const GrCaps* caps = dContext->priv().caps();
527 
528     GrColorType grColorType = SkColorTypeToGrColorType(ct);
529     if (GrColorType::kUnknown == grColorType) {
530         return nullptr;
531     }
532 
533     if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
534         return nullptr;
535     }
536 
537     return new_wrapped_texture_common(dContext, tex, grColorType, origin, at, std::move(cs),
538                                       kAdopt_GrWrapOwnership, nullptr);
539 }
540 
MakeTextureFromCompressed(GrDirectContext * direct,sk_sp<SkData> data,int width,int height,CompressionType type,GrMipmapped mipmapped,GrProtected isProtected)541 sk_sp<SkImage> SkImage::MakeTextureFromCompressed(GrDirectContext* direct, sk_sp<SkData> data,
542                                                   int width, int height, CompressionType type,
543                                                   GrMipmapped mipmapped,
544                                                   GrProtected isProtected) {
545     if (!direct || !data) {
546         return nullptr;
547     }
548 
549     GrBackendFormat beFormat = direct->compressedBackendFormat(type);
550     if (!beFormat.isValid()) {
551         sk_sp<SkImage> tmp = MakeRasterFromCompressed(std::move(data), width, height, type);
552         if (!tmp) {
553             return nullptr;
554         }
555         return tmp->makeTextureImage(direct, mipmapped);
556     }
557 
558     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
559     sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
560             {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
561     if (!proxy) {
562         return nullptr;
563     }
564     GrSurfaceProxyView view(std::move(proxy));
565 
566     SkColorType colorType = GrCompressionTypeToSkColorType(type);
567 
568     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct),
569                                    kNeedNewImageUniqueID,
570                                    std::move(view),
571                                    SkColorInfo(colorType, kOpaque_SkAlphaType, nullptr));
572 }
573 
makeTextureImage(GrDirectContext * dContext,GrMipmapped mipmapped,skgpu::Budgeted budgeted) const574 sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext* dContext,
575                                          GrMipmapped mipmapped,
576                                          skgpu::Budgeted budgeted) const {
577     if (!dContext) {
578         return nullptr;
579     }
580     if (!dContext->priv().caps()->mipmapSupport() || this->dimensions().area() <= 1) {
581         mipmapped = GrMipmapped::kNo;
582     }
583 
584     if (as_IB(this)->isGaneshBacked()) {
585         if (!as_IB(this)->context()->priv().matches(dContext)) {
586             return nullptr;
587         }
588 
589         if (mipmapped == GrMipmapped::kNo || this->hasMipmaps()) {
590             return sk_ref_sp(const_cast<SkImage*>(this));
591         }
592     }
593     GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
594                                          ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
595                                          : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
596     // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
597     auto [view, ct] = as_IB(this)->asView(dContext, mipmapped, policy);
598     if (!view) {
599         return nullptr;
600     }
601     SkASSERT(view.asTextureProxy());
602     SkASSERT(mipmapped == GrMipmapped::kNo ||
603              view.asTextureProxy()->mipmapped() == GrMipmapped::kYes);
604     SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), this->alphaType(), this->refColorSpace());
605     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext),
606                                    this->uniqueID(),
607                                    std::move(view),
608                                    std::move(colorInfo));
609 }
610 
611 ///////////////////////////////////////////////////////////////////////////////////////////////////
612 
MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrBackendFormat & backendFormat,SkISize dimensions,GrMipmapped mipmapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContext)613 sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
614                                            const GrBackendFormat& backendFormat,
615                                            SkISize dimensions,
616                                            GrMipmapped mipmapped,
617                                            GrSurfaceOrigin origin,
618                                            SkColorType colorType,
619                                            SkAlphaType alphaType,
620                                            sk_sp<SkColorSpace> colorSpace,
621                                            PromiseImageTextureFulfillProc textureFulfillProc,
622                                            PromiseImageTextureReleaseProc textureReleaseProc,
623                                            PromiseImageTextureContext textureContext) {
624     // Our contract is that we will always call the release proc even on failure.
625     // We use the helper to convey the context, so we need to ensure make doesn't fail.
626     textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
627     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
628     SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
629     if (!SkImageInfoIsValid(info)) {
630         return nullptr;
631     }
632 
633     if (!threadSafeProxy) {
634         return nullptr;
635     }
636 
637     if (dimensions.isEmpty()) {
638         return nullptr;
639     }
640 
641     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
642     if (GrColorType::kUnknown == grColorType) {
643         return nullptr;
644     }
645 
646     if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
647                                                                          backendFormat)) {
648         return nullptr;
649     }
650 
651     auto proxy = SkImage_GpuBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
652                                                             dimensions,
653                                                             backendFormat,
654                                                             mipmapped,
655                                                             textureFulfillProc,
656                                                             std::move(releaseHelper));
657     if (!proxy) {
658         return nullptr;
659     }
660     skgpu::Swizzle swizzle = threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat,
661                                                                             grColorType);
662     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
663     sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
664     return sk_make_sp<SkImage_Gpu>(std::move(ctx),
665                                    kNeedNewImageUniqueID,
666                                    std::move(view),
667                                    SkColorInfo(colorType, alphaType, std::move(colorSpace)));
668 }
669 
670 ///////////////////////////////////////////////////////////////////////////////////////////////////
671 
MakeCrossContextFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)672 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrDirectContext* dContext,
673                                                    const SkPixmap& originalPixmap, bool buildMips,
674                                                    bool limitToMaxTextureSize) {
675     // Some backends or drivers don't support (safely) moving resources between contexts
676     if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
677         return SkImage::MakeRasterCopy(originalPixmap);
678     }
679 
680     // If non-power-of-two mipmapping isn't supported, ignore the client's request
681     if (!dContext->priv().caps()->mipmapSupport()) {
682         buildMips = false;
683     }
684 
685     const SkPixmap* pixmap = &originalPixmap;
686     SkAutoPixmapStorage resized;
687     int maxTextureSize = dContext->priv().caps()->maxTextureSize();
688     int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
689     if (limitToMaxTextureSize && maxDim > maxTextureSize) {
690         float scale = static_cast<float>(maxTextureSize) / maxDim;
691         int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
692         int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
693         SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
694         SkSamplingOptions sampling(SkFilterMode::kLinear);
695         if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
696             return nullptr;
697         }
698         pixmap = &resized;
699     }
700     // Turn the pixmap into a GrTextureProxy
701     SkBitmap bmp;
702     bmp.installPixels(*pixmap);
703     GrMipmapped mipmapped = buildMips ? GrMipmapped::kYes : GrMipmapped::kNo;
704     auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
705     if (!view) {
706         return SkImage::MakeRasterCopy(*pixmap);
707     }
708 
709     sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
710 
711     // Flush any writes or uploads
712     dContext->priv().flushSurface(view.proxy());
713     GrGpu* gpu = dContext->priv().getGpu();
714 
715     std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
716 
717     SkColorType skCT = GrColorTypeToSkColorType(ct);
718     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), view.origin(),
719                                                     std::move(sema), skCT,
720                                                     pixmap->alphaType(),
721                                                     pixmap->info().refColorSpace());
722     return SkImage::MakeFromGenerator(std::move(gen));
723 }
724 
725 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(AHardwareBuffer * graphicBuffer,SkAlphaType at)726 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at) {
727     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, nullptr,
728                                                      kTopLeft_GrSurfaceOrigin);
729     return SkImage::MakeFromGenerator(std::move(gen));
730 }
731 
MakeFromAHardwareBuffer(AHardwareBuffer * graphicBuffer,SkAlphaType at,sk_sp<SkColorSpace> cs,GrSurfaceOrigin surfaceOrigin)732 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
733                                                 sk_sp<SkColorSpace> cs,
734                                                 GrSurfaceOrigin surfaceOrigin) {
735     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin);
736     return SkImage::MakeFromGenerator(std::move(gen));
737 }
738 
MakeFromAHardwareBufferWithData(GrDirectContext * dContext,const SkPixmap & pixmap,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin surfaceOrigin)739 sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrDirectContext* dContext,
740                                                         const SkPixmap& pixmap,
741                                                         AHardwareBuffer* hardwareBuffer,
742                                                         GrSurfaceOrigin surfaceOrigin) {
743     AHardwareBuffer_Desc bufferDesc;
744     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
745 
746     if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE)) {
747         return nullptr;
748     }
749 
750 
751     GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(dContext,
752                                                                              hardwareBuffer,
753                                                                              bufferDesc.format,
754                                                                              true);
755 
756     if (!backendFormat.isValid()) {
757         return nullptr;
758     }
759 
760     GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
761     GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
762     GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
763 
764     const bool isRenderable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER);
765 
766     GrBackendTexture backendTexture =
767             GrAHardwareBufferUtils::MakeBackendTexture(dContext, hardwareBuffer,
768                                                        bufferDesc.width, bufferDesc.height,
769                                                        &deleteImageProc, &updateImageProc,
770                                                        &deleteImageCtx, false, backendFormat,
771                                                        isRenderable);
772     if (!backendTexture.isValid()) {
773         return nullptr;
774     }
775     SkASSERT(deleteImageProc);
776 
777     auto releaseHelper = skgpu::RefCntedCallback::Make(deleteImageProc, deleteImageCtx);
778 
779     SkColorType colorType =
780             GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
781 
782     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
783 
784     GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
785     if (!proxyProvider) {
786         return nullptr;
787     }
788 
789     sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
790             backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType,
791             std::move(releaseHelper));
792     if (!proxy) {
793         return nullptr;
794     }
795 
796     skgpu::Swizzle swizzle = dContext->priv().caps()->getReadSwizzle(backendFormat, grColorType);
797     GrSurfaceProxyView framebufferView(std::move(proxy), surfaceOrigin, swizzle);
798     SkColorInfo colorInfo = pixmap.info().colorInfo().makeColorType(colorType);
799     sk_sp<SkImage> image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext),
800                                                    kNeedNewImageUniqueID,
801                                                    framebufferView,
802                                                    std::move(colorInfo));
803     if (!image) {
804         return nullptr;
805     }
806 
807     GrDrawingManager* drawingManager = dContext->priv().drawingManager();
808     if (!drawingManager) {
809         return nullptr;
810     }
811 
812     skgpu::v1::SurfaceContext surfaceContext(
813             dContext, std::move(framebufferView),image->imageInfo().colorInfo());
814 
815     surfaceContext.writePixels(dContext, pixmap, {0, 0});
816 
817     GrSurfaceProxy* p[1] = {surfaceContext.asSurfaceProxy()};
818     drawingManager->flush(p, SkSurface::BackendSurfaceAccess::kNoAccess, {}, nullptr);
819 
820     return image;
821 }
822 #endif
823 
824 ///////////////////////////////////////////////////////////////////////////////////////////////////
825 
MakeBackendTextureFromSkImage(GrDirectContext * direct,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)826 bool SkImage::MakeBackendTextureFromSkImage(GrDirectContext* direct,
827                                             sk_sp<SkImage> image,
828                                             GrBackendTexture* backendTexture,
829                                             BackendTextureReleaseProc* releaseProc) {
830     if (!image || !backendTexture || !releaseProc) {
831         return false;
832     }
833 
834     auto [view, ct] = as_IB(image)->asView(direct, GrMipmapped::kNo);
835 
836     if (!view) {
837         return false;
838     }
839 
840     // Flush any pending IO on the texture.
841     direct->priv().flushSurface(view.proxy());
842 
843     GrTexture* texture = view.asTextureProxy()->peekTexture();
844     if (!texture) {
845         return false;
846     }
847     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
848     // image is not unique, or if the texture wraps an external object.
849     if (!image->unique() || !texture->unique() ||
850         texture->resourcePriv().refsWrappedObjects()) {
851         // onMakeSubset will always copy the image.
852         image = as_IB(image)->onMakeSubset(image->bounds(), direct);
853         if (!image) {
854             return false;
855         }
856         return MakeBackendTextureFromSkImage(direct, std::move(image), backendTexture, releaseProc);
857     }
858 
859     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
860     SkASSERT(texture->unique());
861     SkASSERT(image->unique());
862 
863     // Take a reference to the GrTexture and release the image.
864     sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
865     view.reset();
866     image = nullptr;
867     SkASSERT(textureRef->unique());
868 
869     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
870     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
871 }
872 
onAsView(GrRecordingContext * recordingContext,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const873 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Gpu::onAsView(
874         GrRecordingContext* recordingContext,
875         GrMipmapped mipmapped,
876         GrImageTexGenPolicy policy) const {
877     if (!fContext->priv().matches(recordingContext)) {
878         return {};
879     }
880     if (policy != GrImageTexGenPolicy::kDraw) {
881         return {CopyView(recordingContext,
882                          this->makeView(recordingContext),
883                          mipmapped,
884                          policy,
885                          /*label=*/"SkImageGpu_AsView"),
886                 SkColorTypeToGrColorType(this->colorType())};
887     }
888     GrSurfaceProxyView view = this->makeView(recordingContext);
889     GrColorType ct = SkColorTypeToGrColorType(this->colorType());
890     if (mipmapped == GrMipmapped::kYes) {
891         view = FindOrMakeCachedMipmappedView(recordingContext, std::move(view), this->uniqueID());
892     }
893     return {std::move(view), ct};
894 }
895 
onAsFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const896 std::unique_ptr<GrFragmentProcessor> SkImage_Gpu::onAsFragmentProcessor(
897         GrRecordingContext* rContext,
898         SkSamplingOptions sampling,
899         const SkTileMode tileModes[2],
900         const SkMatrix& m,
901         const SkRect* subset,
902         const SkRect* domain) const {
903     if (!fContext->priv().matches(rContext)) {
904         return {};
905     }
906     auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
907     return MakeFragmentProcessorFromView(rContext,
908                                          std::get<0>(this->asView(rContext, mm)),
909                                          this->alphaType(),
910                                          sampling,
911                                          tileModes,
912                                          m,
913                                          subset,
914                                          domain);
915 }
916 
makeView(GrRecordingContext * rContext) const917 GrSurfaceProxyView SkImage_Gpu::makeView(GrRecordingContext* rContext) const {
918     return {fChooser.chooseProxy(rContext), fOrigin, fSwizzle};
919 }
920