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 ©Task);
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