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