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