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