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 ©Task);
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,sk_sp<SkColorSpace> colorSpace)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 sk_sp<SkColorSpace> colorSpace) {
504 if (!direct || !data) {
505 return nullptr;
506 }
507
508 GrBackendFormat beFormat = direct->compressedBackendFormat(type);
509 if (!beFormat.isValid()) {
510 sk_sp<SkImage> tmp = MakeRasterFromCompressed(std::move(data), width, height, type);
511 if (!tmp) {
512 return nullptr;
513 }
514 return tmp->makeTextureImage(direct, mipMapped);
515 }
516
517 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
518 sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
519 {width, height}, SkBudgeted::kYes, mipMapped, isProtected, type, std::move(data));
520 if (!proxy) {
521 return nullptr;
522 }
523 GrSurfaceProxyView view(std::move(proxy));
524
525 SkColorType colorType = GrCompressionTypeToSkColorType(type);
526
527 // modify for support astc texture format
528 SkAlphaType alphaType = GrCompressionTypeToSkAlphaType(type);
529
530 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct),
531 kNeedNewImageUniqueID,
532 std::move(view),
533 SkColorInfo(colorType, alphaType, colorSpace));
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 = SkColorTypeToGrColorType(colorType);
604 if (GrColorType::kUnknown == grColorType) {
605 return nullptr;
606 }
607
608 if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
609 backendFormat)) {
610 return nullptr;
611 }
612
613 auto proxy = SkImage_GpuBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
614 dimensions,
615 backendFormat,
616 mipMapped,
617 textureFulfillProc,
618 std::move(releaseHelper));
619 if (!proxy) {
620 return nullptr;
621 }
622 GrSwizzle swizzle = threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
623 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
624 sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
625 return sk_make_sp<SkImage_Gpu>(std::move(ctx),
626 kNeedNewImageUniqueID,
627 std::move(view),
628 SkColorInfo(colorType, alphaType, std::move(colorSpace)));
629 }
630
631 ///////////////////////////////////////////////////////////////////////////////////////////////////
632
MakeCrossContextFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)633 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrDirectContext* dContext,
634 const SkPixmap& originalPixmap, bool buildMips,
635 bool limitToMaxTextureSize) {
636 // Some backends or drivers don't support (safely) moving resources between contexts
637 if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
638 return SkImage::MakeRasterCopy(originalPixmap);
639 }
640
641 // If non-power-of-two mipmapping isn't supported, ignore the client's request
642 if (!dContext->priv().caps()->mipmapSupport()) {
643 buildMips = false;
644 }
645
646 const SkPixmap* pixmap = &originalPixmap;
647 SkAutoPixmapStorage resized;
648 int maxTextureSize = dContext->priv().caps()->maxTextureSize();
649 int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
650 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
651 float scale = static_cast<float>(maxTextureSize) / maxDim;
652 int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
653 int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
654 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
655 SkSamplingOptions sampling(SkFilterMode::kLinear);
656 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
657 return nullptr;
658 }
659 pixmap = &resized;
660 }
661 // Turn the pixmap into a GrTextureProxy
662 SkBitmap bmp;
663 bmp.installPixels(*pixmap);
664 GrMipmapped mipmapped = buildMips ? GrMipmapped::kYes : GrMipmapped::kNo;
665 auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
666 if (!view) {
667 return SkImage::MakeRasterCopy(*pixmap);
668 }
669
670 sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
671
672 // Flush any writes or uploads
673 dContext->priv().flushSurface(view.proxy());
674 GrGpu* gpu = dContext->priv().getGpu();
675
676 std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
677
678 SkColorType skCT = GrColorTypeToSkColorType(ct);
679 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), view.origin(),
680 std::move(sema), skCT,
681 pixmap->alphaType(),
682 pixmap->info().refColorSpace());
683 return SkImage::MakeFromGenerator(std::move(gen));
684 }
685
686 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(AHardwareBuffer * graphicBuffer,SkAlphaType at,sk_sp<SkColorSpace> cs,GrSurfaceOrigin surfaceOrigin)687 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
688 sk_sp<SkColorSpace> cs,
689 GrSurfaceOrigin surfaceOrigin) {
690 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin);
691 return SkImage::MakeFromGenerator(std::move(gen));
692 }
693
MakeFromAHardwareBufferWithData(GrDirectContext * dContext,const SkPixmap & pixmap,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin surfaceOrigin)694 sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrDirectContext* dContext,
695 const SkPixmap& pixmap,
696 AHardwareBuffer* hardwareBuffer,
697 GrSurfaceOrigin surfaceOrigin) {
698 AHardwareBuffer_Desc bufferDesc;
699 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
700
701 if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE)) {
702 return nullptr;
703 }
704
705
706 GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(dContext,
707 hardwareBuffer,
708 bufferDesc.format,
709 true);
710
711 if (!backendFormat.isValid()) {
712 return nullptr;
713 }
714
715 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
716 GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
717 GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
718
719 const bool isRenderable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER);
720
721 GrBackendTexture backendTexture =
722 GrAHardwareBufferUtils::MakeBackendTexture(dContext, hardwareBuffer,
723 bufferDesc.width, bufferDesc.height,
724 &deleteImageProc, &updateImageProc,
725 &deleteImageCtx, false, backendFormat,
726 isRenderable);
727 if (!backendTexture.isValid()) {
728 return nullptr;
729 }
730 SkASSERT(deleteImageProc);
731
732 auto releaseHelper = GrRefCntedCallback::Make(deleteImageProc, deleteImageCtx);
733
734 SkColorType colorType =
735 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
736
737 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
738
739 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
740 if (!proxyProvider) {
741 return nullptr;
742 }
743
744 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
745 backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType,
746 std::move(releaseHelper));
747 if (!proxy) {
748 return nullptr;
749 }
750
751 GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(backendFormat, grColorType);
752 GrSurfaceProxyView framebufferView(std::move(proxy), surfaceOrigin, swizzle);
753 SkColorInfo colorInfo = pixmap.info().colorInfo().makeColorType(colorType);
754 sk_sp<SkImage> image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext),
755 kNeedNewImageUniqueID,
756 framebufferView,
757 std::move(colorInfo));
758 if (!image) {
759 return nullptr;
760 }
761
762 GrDrawingManager* drawingManager = dContext->priv().drawingManager();
763 if (!drawingManager) {
764 return nullptr;
765 }
766
767 skgpu::SurfaceContext surfaceContext(
768 dContext, std::move(framebufferView),image->imageInfo().colorInfo());
769
770 surfaceContext.writePixels(dContext, pixmap, {0, 0});
771
772 GrSurfaceProxy* p[1] = {surfaceContext.asSurfaceProxy()};
773 drawingManager->flush(SkMakeSpan(p), SkSurface::BackendSurfaceAccess::kNoAccess, {}, nullptr);
774
775 return image;
776 }
777 #endif
778
779 ///////////////////////////////////////////////////////////////////////////////////////////////////
780
MakeBackendTextureFromSkImage(GrDirectContext * direct,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)781 bool SkImage::MakeBackendTextureFromSkImage(GrDirectContext* direct,
782 sk_sp<SkImage> image,
783 GrBackendTexture* backendTexture,
784 BackendTextureReleaseProc* releaseProc) {
785 if (!image || !backendTexture || !releaseProc) {
786 return false;
787 }
788
789 auto [view, ct] = as_IB(image)->asView(direct, GrMipmapped::kNo);
790
791 if (!view) {
792 return false;
793 }
794
795 // Flush any pending IO on the texture.
796 direct->priv().flushSurface(view.proxy());
797
798 GrTexture* texture = view.asTextureProxy()->peekTexture();
799 if (!texture) {
800 return false;
801 }
802 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
803 // image is not unique, or if the texture wraps an external object.
804 if (!image->unique() || !texture->unique() ||
805 texture->resourcePriv().refsWrappedObjects()) {
806 // onMakeSubset will always copy the image.
807 image = as_IB(image)->onMakeSubset(image->bounds(), direct);
808 if (!image) {
809 return false;
810 }
811 return MakeBackendTextureFromSkImage(direct, std::move(image), backendTexture, releaseProc);
812 }
813
814 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
815 SkASSERT(texture->unique());
816 SkASSERT(image->unique());
817
818 // Take a reference to the GrTexture and release the image.
819 sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
820 view.reset();
821 image = nullptr;
822 SkASSERT(textureRef->unique());
823
824 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
825 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
826 }
827
onAsView(GrRecordingContext * recordingContext,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const828 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Gpu::onAsView(
829 GrRecordingContext* recordingContext,
830 GrMipmapped mipmapped,
831 GrImageTexGenPolicy policy) const {
832 if (!fContext->priv().matches(recordingContext)) {
833 return {};
834 }
835 if (policy != GrImageTexGenPolicy::kDraw) {
836 return {CopyView(recordingContext, this->makeView(recordingContext), mipmapped, policy),
837 SkColorTypeToGrColorType(this->colorType())};
838 }
839 GrSurfaceProxyView view = this->makeView(recordingContext);
840 GrColorType ct = SkColorTypeToGrColorType(this->colorType());
841 if (mipmapped == GrMipmapped::kYes) {
842 view = FindOrMakeCachedMipmappedView(recordingContext, std::move(view), this->uniqueID());
843 }
844 return {std::move(view), ct};
845 }
846
onAsFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const847 std::unique_ptr<GrFragmentProcessor> SkImage_Gpu::onAsFragmentProcessor(
848 GrRecordingContext* rContext,
849 SkSamplingOptions sampling,
850 const SkTileMode tileModes[2],
851 const SkMatrix& m,
852 const SkRect* subset,
853 const SkRect* domain) const {
854 if (!fContext->priv().matches(rContext)) {
855 return {};
856 }
857 auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
858 return MakeFragmentProcessorFromView(rContext,
859 std::get<0>(this->asView(rContext, mm)),
860 this->alphaType(),
861 sampling,
862 tileModes,
863 m,
864 subset,
865 domain);
866 }
867
makeView(GrRecordingContext * rContext) const868 GrSurfaceProxyView SkImage_Gpu::makeView(GrRecordingContext* rContext) const {
869 return {fChooser.chooseProxy(rContext), fOrigin, fSwizzle};
870 }
871
hintCacheGpuResource()872 void SkImage_Gpu::hintCacheGpuResource() {
873 auto dContext = fContext->asDirectContext();
874 if (!dContext) {
875 return;
876 }
877 GrTextureProxy* texProxy = this->makeView(dContext).asTextureProxy();
878 if (texProxy) {
879 texProxy->setUserCacheTarget(true);
880 }
881 }
882