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 <cstddef>
9#include <cstring>
10#include <type_traits>
11
12#include "include/core/SkCanvas.h"
13#include "include/gpu/GrBackendSurface.h"
14#include "include/gpu/GrDirectContext.h"
15#include "include/gpu/GrRecordingContext.h"
16#include "include/private/SkImageInfoPriv.h"
17#include "src/core/SkAutoPixmapStorage.h"
18#include "src/core/SkBitmapCache.h"
19#include "src/core/SkMipmap.h"
20#include "src/core/SkScopeExit.h"
21#include "src/core/SkTraceEvent.h"
22#include "src/gpu/GrAHardwareBufferImageGenerator.h"
23#include "src/gpu/GrAHardwareBufferUtils.h"
24#include "src/gpu/GrBackendTextureImageGenerator.h"
25#include "src/gpu/GrBackendUtils.h"
26#include "src/gpu/GrBitmapTextureMaker.h"
27#include "src/gpu/GrCaps.h"
28#include "src/gpu/GrColorSpaceXform.h"
29#include "src/gpu/GrContextPriv.h"
30#include "src/gpu/GrDrawingManager.h"
31#include "src/gpu/GrGpu.h"
32#include "src/gpu/GrImageInfo.h"
33#include "src/gpu/GrImageTextureMaker.h"
34#include "src/gpu/GrProxyProvider.h"
35#include "src/gpu/GrRecordingContextPriv.h"
36#include "src/gpu/GrRenderTargetContext.h"
37#include "src/gpu/GrSemaphore.h"
38#include "src/gpu/GrTexture.h"
39#include "src/gpu/GrTextureAdjuster.h"
40#include "src/gpu/GrTextureProxy.h"
41#include "src/gpu/GrTextureProxyPriv.h"
42#include "src/gpu/SkGr.h"
43#include "src/gpu/gl/GrGLTexture.h"
44#include "src/image/SkImage_Gpu.h"
45
46SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, GrSurfaceProxyView view,
47 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> colorSpace)
48 : INHERITED(std::move(context), view.proxy()->backingStoreDimensions(), uniqueID,
49 ct, at, colorSpace)
50 , fView(std::move(view)) {
51#ifdef SK_DEBUG
52 const GrBackendFormat& format = fView.proxy()->backendFormat();
53 GrColorType grCT = SkColorTypeToGrColorType(ct);
54 const GrCaps* caps = this->context()->priv().caps();
55 if (caps->isFormatSRGB(format)) {
56 SkASSERT(grCT == GrColorType::kRGBA_8888);
57 grCT = GrColorType::kRGBA_8888_SRGB;
58 }
59 SkASSERT(caps->isFormatCompressed(format) ||
60 caps->areColorTypeAndFormatCompatible(grCT, format));
61#endif
62}
63
64SkImage_Gpu::~SkImage_Gpu() {}
65
66GrSemaphoresSubmitted SkImage_Gpu::onFlush(GrDirectContext* dContext, const GrFlushInfo& info) {
67 if (!fContext->priv().matches(dContext) || dContext->abandoned()) {
68 if (info.fSubmittedProc) {
69 info.fSubmittedProc(info.fSubmittedContext, false);
70 }
71 if (info.fFinishedProc) {
72 info.fFinishedProc(info.fFinishedContext);
73 }
74 return GrSemaphoresSubmitted::kNo;
75 }
76
77 GrSurfaceProxy* p[1] = {fView.proxy()};
78 return dContext->priv().flushSurfaces(p, 1, info);
79}
80
81sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(SkColorType targetCT,
82 sk_sp<SkColorSpace> targetCS,
83 GrDirectContext* direct) const {
84 if (!fContext->priv().matches(direct)) {
85 return nullptr;
86 }
87
88 auto renderTargetContext = GrRenderTargetContext::MakeWithFallback(
89 direct, SkColorTypeToGrColorType(targetCT), nullptr, SkBackingFit::kExact,
90 this->dimensions());
91 if (!renderTargetContext) {
92 return nullptr;
93 }
94
95 auto texFP = GrTextureEffect::Make(*this->view(direct), this->alphaType());
96 auto colorFP = GrColorSpaceXformEffect::Make(std::move(texFP),
97 this->colorSpace(), this->alphaType(),
98 targetCS.get(), this->alphaType());
99 SkASSERT(colorFP);
100
101 GrPaint paint;
102 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
103 paint.setColorFragmentProcessor(std::move(colorFP));
104
105 renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
106 SkRect::MakeIWH(this->width(), this->height()));
107 if (!renderTargetContext->asTextureProxy()) {
108 return nullptr;
109 }
110
111 targetCT = GrColorTypeToSkColorType(renderTargetContext->colorInfo().colorType());
112 // MDB: this call is okay bc we know 'renderTargetContext' was exact
113 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct), kNeedNewImageUniqueID,
114 renderTargetContext->readSurfaceView(), targetCT,
115 this->alphaType(), std::move(targetCS));
116}
117
118sk_sp<SkImage> SkImage_Gpu::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
119 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fView, this->colorType(),
120 this->alphaType(), std::move(newCS));
121}
122
123void SkImage_Gpu::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
124 const SkIRect& srcRect,
125 RescaleGamma rescaleGamma,
126 SkFilterQuality rescaleQuality,
127 ReadPixelsCallback callback,
128 ReadPixelsContext context) {
129 auto dContext = fContext->asDirectContext();
130 if (!dContext) {
131 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
132 callback(context, nullptr);
133 return;
134 }
135 GrColorType ct = SkColorTypeToGrColorType(this->colorType());
136 auto ctx = GrSurfaceContext::Make(dContext, fView, ct, this->alphaType(),
137 this->refColorSpace());
138 if (!ctx) {
139 callback(context, nullptr);
140 return;
141 }
142 ctx->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleQuality,
143 callback, context);
144}
145
146void SkImage_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
147 sk_sp<SkColorSpace> dstColorSpace,
148 const SkIRect& srcRect,
149 const SkISize& dstSize,
150 RescaleGamma rescaleGamma,
151 SkFilterQuality rescaleQuality,
152 ReadPixelsCallback callback,
153 ReadPixelsContext context) {
154 auto dContext = fContext->asDirectContext();
155 if (!dContext) {
156 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
157 callback(context, nullptr);
158 return;
159 }
160 GrColorType ct = SkColorTypeToGrColorType(this->colorType());
161 auto ctx = GrSurfaceContext::Make(dContext, fView, ct, this->alphaType(),
162 this->refColorSpace());
163 if (!ctx) {
164 callback(context, nullptr);
165 return;
166 }
167 ctx->asyncRescaleAndReadPixelsYUV420(dContext,
168 yuvColorSpace,
169 std::move(dstColorSpace),
170 srcRect,
171 dstSize,
172 rescaleGamma,
173 rescaleQuality,
174 callback,
175 context);
176}
177
178///////////////////////////////////////////////////////////////////////////////////////////////////
179
180static sk_sp<SkImage> new_wrapped_texture_common(GrRecordingContext* rContext,
181 const GrBackendTexture& backendTex,
182 GrColorType colorType, GrSurfaceOrigin origin,
183 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
184 GrWrapOwnership ownership,
185 sk_sp<GrRefCntedCallback> releaseHelper) {
186 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
187 return nullptr;
188 }
189
190 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
191 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
192 backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
193 if (!proxy) {
194 return nullptr;
195 }
196
197 GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), colorType);
198 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
199 auto grContext = rContext->priv().backdoor();
200 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(grContext), kNeedNewImageUniqueID, std::move(view),
201 GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
202}
203
204sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrRecordingContext* rContext,
205 const GrBackendTexture& tex,
206 GrSurfaceOrigin origin,
207 SkAlphaType at,
208 sk_sp<SkColorSpace> cs,
209 TextureReleaseProc releaseP,
210 ReleaseContext releaseC) {
211 sk_sp<GrRefCntedCallback> releaseHelper;
212 if (releaseP) {
213 releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC));
214 }
215
216 if (!rContext) {
217 return nullptr;
218 }
219
220 const GrCaps* caps = rContext->priv().caps();
221
222 if (!SkImage_GpuBase::ValidateCompressedBackendTexture(caps, tex, at)) {
223 return nullptr;
224 }
225
226 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
227 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapCompressedBackendTexture(
228 tex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, std::move(releaseHelper));
229 if (!proxy) {
230 return nullptr;
231 }
232
233 CompressionType type = GrBackendFormatToCompressionType(tex.getBackendFormat());
234 SkColorType ct = GrCompressionTypeToSkColorType(type);
235
236 GrSurfaceProxyView view(std::move(proxy), origin, GrSwizzle::RGBA());
237 auto grContext = rContext->priv().backdoor();
238 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(grContext), kNeedNewImageUniqueID, std::move(view),
239 ct, at, std::move(cs));
240}
241
242sk_sp<SkImage> SkImage::MakeFromTexture(GrRecordingContext* rContext,
243 const GrBackendTexture& tex, GrSurfaceOrigin origin,
244 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
245 TextureReleaseProc releaseP, ReleaseContext releaseC) {
246 sk_sp<GrRefCntedCallback> releaseHelper;
247 if (releaseP) {
248 releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC));
249 }
250
251 if (!rContext) {
252 return nullptr;
253 }
254
255 const GrCaps* caps = rContext->priv().caps();
256
257 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
258 if (GrColorType::kUnknown == grColorType) {
259 return nullptr;
260 }
261
262 if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
263 return nullptr;
264 }
265
266 return new_wrapped_texture_common(rContext, tex, grColorType, origin, at, std::move(cs),
267 kBorrow_GrWrapOwnership, std::move(releaseHelper));
268}
269
270sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext* rContext,
271 const GrBackendTexture& tex, GrSurfaceOrigin origin,
272 SkColorType ct, SkAlphaType at,
273 sk_sp<SkColorSpace> cs) {
274 auto dContext = GrAsDirectContext(rContext);
275 if (!dContext) {
276 // We have a DDL context and we don't support adopted textures for them.
277 return nullptr;
278 }
279
280 const GrCaps* caps = dContext->priv().caps();
281
282 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
283 if (GrColorType::kUnknown == grColorType) {
284 return nullptr;
285 }
286
287 if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
288 return nullptr;
289 }
290
291 return new_wrapped_texture_common(dContext, tex, grColorType, origin, at, std::move(cs),
292 kAdopt_GrWrapOwnership, nullptr);
293}
294
295sk_sp<SkImage> SkImage::MakeTextureFromCompressed(GrDirectContext* direct, sk_sp<SkData> data,
296 int width, int height, CompressionType type,
297 GrMipmapped mipMapped,
298 GrProtected isProtected) {
299 if (!direct || !data) {
300 return nullptr;
301 }
302
303 GrBackendFormat beFormat = direct->compressedBackendFormat(type);
304 if (!beFormat.isValid()) {
305 sk_sp<SkImage> tmp = MakeRasterFromCompressed(std::move(data), width, height, type);
306 if (!tmp) {
307 return nullptr;
308 }
309 return tmp->makeTextureImage(direct, mipMapped);
310 }
311
312 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
313 sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
314 {width, height}, SkBudgeted::kYes, mipMapped, isProtected, type, std::move(data));
315 if (!proxy) {
316 return nullptr;
317 }
318 GrSurfaceProxyView view(std::move(proxy));
319
320 SkColorType colorType = GrCompressionTypeToSkColorType(type);
321
322 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct), kNeedNewImageUniqueID, std::move(view),
323 colorType, kOpaque_SkAlphaType, nullptr);
324}
325
326sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrRecordingContext* rContext,
327 SkYUVColorSpace yuvColorSpace,
328 const GrBackendTexture yuvaTextures[],
329 const SkYUVAIndex yuvaIndices[4], SkISize size,
330 GrSurfaceOrigin origin,
331 GrRenderTargetContext* renderTargetContext) {
332 SkASSERT(renderTargetContext);
333
334 int numTextures;
335 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
336 return nullptr;
337 }
338
339 GrSurfaceProxyView tempViews[4];
340 if (!SkImage_GpuBase::MakeTempTextureProxies(rContext, yuvaTextures, numTextures, yuvaIndices,
341 origin, tempViews, nullptr)) {
342 return nullptr;
343 }
344
345 const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
346 const GrCaps& caps = *rContext->priv().caps();
347 if (!RenderYUVAToRGBA(caps, renderTargetContext, rect, yuvColorSpace, nullptr,
348 tempViews, yuvaIndices)) {
349 return nullptr;
350 }
351
352 SkColorType ct = GrColorTypeToSkColorType(renderTargetContext->colorInfo().colorType());
353 SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices);
354 // TODO: Remove this use of backdoor.
355 GrContext* backdoorGrCtx = rContext->priv().backdoor();
356 // MDB: this call is okay bc we know 'renderTargetContext' was exact
357 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(backdoorGrCtx), kNeedNewImageUniqueID,
358 renderTargetContext->readSurfaceView(), ct, at,
359 renderTargetContext->colorInfo().refColorSpace());
360}
361
362sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrRecordingContext* rContext,
363 SkYUVColorSpace yuvColorSpace,
364 const GrBackendTexture yuvaTextures[],
365 const SkYUVAIndex yuvaIndices[4],
366 SkISize imageSize,
367 GrSurfaceOrigin imageOrigin,
368 sk_sp<SkColorSpace> imageColorSpace) {
369 auto renderTargetContext = GrRenderTargetContext::Make(
370 rContext, GrColorType::kRGBA_8888, std::move(imageColorSpace), SkBackingFit::kExact,
371 imageSize, 1, GrMipmapped::kNo, GrProtected::kNo, imageOrigin);
372 if (!renderTargetContext) {
373 return nullptr;
374 }
375
376 return SkImage_Gpu::ConvertYUVATexturesToRGB(rContext, yuvColorSpace, yuvaTextures, yuvaIndices,
377 imageSize, imageOrigin, renderTargetContext.get());
378}
379
380sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
381 GrRecordingContext* rContext,
382 SkYUVColorSpace yuvColorSpace,
383 const GrBackendTexture yuvaTextures[],
384 const SkYUVAIndex yuvaIndices[4],
385 SkISize imageSize,
386 GrSurfaceOrigin imageOrigin,
387 const GrBackendTexture& backendTexture,
388 sk_sp<SkColorSpace> imageColorSpace,
389 TextureReleaseProc textureReleaseProc,
390 ReleaseContext releaseContext) {
391 const GrCaps* caps = rContext->priv().caps();
392
393 sk_sp<GrRefCntedCallback> releaseHelper;
394 if (textureReleaseProc) {
395 releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext));
396 }
397
398 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, kRGBA_8888_SkColorType,
399 backendTexture.getBackendFormat());
400 if (GrColorType::kUnknown == grColorType) {
401 return nullptr;
402 }
403
404 SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices);
405 if (!SkImage_Gpu::ValidateBackendTexture(caps, backendTexture, grColorType,
406 kRGBA_8888_SkColorType, at, nullptr)) {
407 return nullptr;
408 }
409
410 // Needs to create a render target with external texture
411 // in order to draw to it for the yuv->rgb conversion.
412 auto renderTargetContext = GrRenderTargetContext::MakeFromBackendTexture(
413 rContext, grColorType, std::move(imageColorSpace), backendTexture, 1, imageOrigin,
414 nullptr, std::move(releaseHelper));
415 if (!renderTargetContext) {
416 return nullptr;
417 }
418
419 return SkImage_Gpu::ConvertYUVATexturesToRGB(rContext, yuvColorSpace, yuvaTextures, yuvaIndices,
420 imageSize, imageOrigin, renderTargetContext.get());
421}
422
423// Some YUVA factories infer the YUVAIndices. This helper identifies the channel to use for single
424// channel textures.
425static SkColorChannel get_single_channel(const GrBackendTexture& tex) {
426 switch (tex.getBackendFormat().channelMask()) {
427 case kGray_SkColorChannelFlag: // Gray can be read as any of kR, kG, kB.
428 case kRed_SkColorChannelFlag:
429 return SkColorChannel::kR;
430 case kAlpha_SkColorChannelFlag:
431 return SkColorChannel::kA;
432 default: // multiple channels in the texture. Guess kR.
433 return SkColorChannel::kR;
434 }
435}
436
437sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
438 GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
439 GrSurfaceOrigin imageOrigin, const GrBackendTexture& backendTexture,
440 sk_sp<SkColorSpace> imageColorSpace) {
441 SkYUVAIndex yuvaIndices[4] = {
442 SkYUVAIndex{0, get_single_channel(yuvTextures[0])},
443 SkYUVAIndex{1, get_single_channel(yuvTextures[1])},
444 SkYUVAIndex{2, get_single_channel(yuvTextures[2])},
445 SkYUVAIndex{-1, SkColorChannel::kA}};
446 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
447 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
448 ctx, yuvColorSpace, yuvTextures, yuvaIndices, size, imageOrigin, backendTexture,
449 std::move(imageColorSpace), nullptr, nullptr);
450}
451
452sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
453 const GrBackendTexture nv12Textures[2],
454 GrSurfaceOrigin imageOrigin,
455 sk_sp<SkColorSpace> imageColorSpace) {
456 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
457 SkYUVAIndex yuvaIndices[4] = {
458 SkYUVAIndex{0, get_single_channel(nv12Textures[0])},
459 SkYUVAIndex{1, SkColorChannel::kR},
460 SkYUVAIndex{1, SkColorChannel::kG},
461 SkYUVAIndex{-1, SkColorChannel::kA}};
462 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
463 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, nv12Textures, yuvaIndices,
464 size, imageOrigin, std::move(imageColorSpace));
465}
466
467sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
468 GrContext* ctx,
469 SkYUVColorSpace yuvColorSpace,
470 const GrBackendTexture nv12Textures[2],
471 GrSurfaceOrigin imageOrigin,
472 const GrBackendTexture& backendTexture,
473 sk_sp<SkColorSpace> imageColorSpace,
474 TextureReleaseProc textureReleaseProc,
475 ReleaseContext releaseContext) {
476 SkYUVAIndex yuvaIndices[4] = {
477 SkYUVAIndex{0, get_single_channel(nv12Textures[0])},
478 SkYUVAIndex{1, SkColorChannel::kR},
479 SkYUVAIndex{1, SkColorChannel::kG},
480 SkYUVAIndex{-1, SkColorChannel::kA}};
481 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
482 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
483 ctx, yuvColorSpace, nv12Textures, yuvaIndices, size, imageOrigin, backendTexture,
484 std::move(imageColorSpace), textureReleaseProc, releaseContext);
485}
486
487static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
488 uint32_t id, GrMipmapped mipMapped) {
489 auto view = producer->view(mipMapped);
490 if (!view) {
491 return nullptr;
492 }
493 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, std::move(view),
494 GrColorTypeToSkColorType(producer->colorType()),
495 producer->alphaType(), sk_ref_sp(producer->colorSpace()));
496}
497
498
499sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext* dContext,
500 GrMipmapped mipMapped,
501 SkBudgeted budgeted) const {
502 if (!dContext) {
503 return nullptr;
504 }
505
506 if (this->isTextureBacked()) {
507 if (!as_IB(this)->context()->priv().matches(dContext)) {
508 return nullptr;
509 }
510
511 // TODO: Don't flatten YUVA images here.
512 const GrSurfaceProxyView* view = as_IB(this)->view(dContext);
513 SkASSERT(view && view->asTextureProxy());
514
515 if (mipMapped == GrMipmapped::kNo || view->asTextureProxy()->mipmapped() == mipMapped ||
516 !dContext->priv().caps()->mipmapSupport()) {
517 return sk_ref_sp(const_cast<SkImage*>(this));
518 }
519 auto copy = GrCopyBaseMipMapToView(dContext, *view, budgeted);
520 if (!copy) {
521 return nullptr;
522 }
523 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext), this->uniqueID(), copy,
524 this->colorType(), this->alphaType(), this->refColorSpace());
525 }
526
527 auto policy = budgeted == SkBudgeted::kYes ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
528 : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
529 if (this->isLazyGenerated()) {
530 GrImageTextureMaker maker(dContext, this, policy);
531 return create_image_from_producer(dContext, &maker, this->uniqueID(), mipMapped);
532 }
533
534 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
535 GrBitmapTextureMaker maker(dContext, *bmp, policy);
536 return create_image_from_producer(dContext, &maker, this->uniqueID(), mipMapped);
537 }
538 return nullptr;
539}
540
541///////////////////////////////////////////////////////////////////////////////////////////////////
542
543sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrRecordingContext* context,
544 const GrBackendFormat& backendFormat,
545 int width,
546 int height,
547 GrMipmapped mipMapped,
548 GrSurfaceOrigin origin,
549 SkColorType colorType,
550 SkAlphaType alphaType,
551 sk_sp<SkColorSpace> colorSpace,
552 PromiseImageTextureFulfillProc textureFulfillProc,
553 PromiseImageTextureReleaseProc textureReleaseProc,
554 PromiseImageTextureDoneProc textureDoneProc,
555 PromiseImageTextureContext textureContext,
556 PromiseImageApiVersion version) {
557 // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
558 // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
559 // responsibility for calling the done proc.
560 if (!textureDoneProc) {
561 return nullptr;
562 }
563 SkScopeExit callDone([textureDoneProc, textureContext]() { textureDoneProc(textureContext); });
564
565 SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
566 if (!SkImageInfoIsValid(info)) {
567 return nullptr;
568 }
569
570 if (!context) {
571 return nullptr;
572 }
573
574 if (width <= 0 || height <= 0) {
575 return nullptr;
576 }
577
578 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(),
579 colorType,
580 backendFormat);
581 if (GrColorType::kUnknown == grColorType) {
582 return nullptr;
583 }
584
585 if (!context->priv().caps()->areColorTypeAndFormatCompatible(grColorType, backendFormat)) {
586 return nullptr;
587 }
588
589 callDone.clear();
590 auto proxy = MakePromiseImageLazyProxy(context, width, height, backendFormat,
591 mipMapped, textureFulfillProc, textureReleaseProc,
592 textureDoneProc, textureContext, version);
593 if (!proxy) {
594 return nullptr;
595 }
596 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(backendFormat, grColorType);
597 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
598 // CONTEXT TODO: rm this usage of the 'backdoor' to create an image
599 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context->priv().backdoor()), kNeedNewImageUniqueID,
600 std::move(view), colorType, alphaType, std::move(colorSpace));
601}
602
603///////////////////////////////////////////////////////////////////////////////////////////////////
604
605sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrDirectContext* dContext,
606 const SkPixmap& originalPixmap, bool buildMips,
607 bool limitToMaxTextureSize) {
608 // Some backends or drivers don't support (safely) moving resources between contexts
609 if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
610 return SkImage::MakeRasterCopy(originalPixmap);
611 }
612
613 // If non-power-of-two mipmapping isn't supported, ignore the client's request
614 if (!dContext->priv().caps()->mipmapSupport()) {
615 buildMips = false;
616 }
617
618 const SkPixmap* pixmap = &originalPixmap;
619 SkAutoPixmapStorage resized;
620 int maxTextureSize = dContext->priv().caps()->maxTextureSize();
621 int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
622 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
623 float scale = static_cast<float>(maxTextureSize) / maxDim;
624 int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
625 int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
626 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
627 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) {
628 return nullptr;
629 }
630 pixmap = &resized;
631 }
632 // Turn the pixmap into a GrTextureProxy
633 SkBitmap bmp;
634 bmp.installPixels(*pixmap);
635 GrBitmapTextureMaker bitmapMaker(dContext, bmp, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
636 GrMipmapped mipMapped = buildMips ? GrMipmapped::kYes : GrMipmapped::kNo;
637 auto view = bitmapMaker.view(mipMapped);
638 if (!view) {
639 return SkImage::MakeRasterCopy(*pixmap);
640 }
641
642 sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
643
644 // Flush any writes or uploads
645 dContext->priv().flushSurface(view.proxy());
646 GrGpu* gpu = dContext->priv().getGpu();
647
648 std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
649
650 SkColorType skCT = GrColorTypeToSkColorType(bitmapMaker.colorType());
651 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), view.origin(),
652 std::move(sema), skCT,
653 pixmap->alphaType(),
654 pixmap->info().refColorSpace());
655 return SkImage::MakeFromGenerator(std::move(gen));
656}
657
658#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
659sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
660 sk_sp<SkColorSpace> cs,
661 GrSurfaceOrigin surfaceOrigin) {
662 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin);
663 return SkImage::MakeFromGenerator(std::move(gen));
664}
665
666sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrContext* context,
667 const SkPixmap& pixmap,
668 AHardwareBuffer* hardwareBuffer,
669 GrSurfaceOrigin surfaceOrigin) {
670 AHardwareBuffer_Desc bufferDesc;
671 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
672
673 if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE)) {
674 return nullptr;
675 }
676
677 auto dContext = GrAsDirectContext(context);
678 if (!dContext) {
679 SkDebugf("Direct context required\n");
680 return nullptr;
681 }
682
683 GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(dContext,
684 hardwareBuffer,
685 bufferDesc.format,
686 true);
687
688 if (!backendFormat.isValid()) {
689 return nullptr;
690 }
691
692 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
693 GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
694 GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
695
696 GrBackendTexture backendTexture =
697 GrAHardwareBufferUtils::MakeBackendTexture(dContext, hardwareBuffer,
698 bufferDesc.width, bufferDesc.height,
699 &deleteImageProc, &updateImageProc,
700 &deleteImageCtx, false, backendFormat, true);
701 if (!backendTexture.isValid()) {
702 return nullptr;
703 }
704 SkASSERT(deleteImageProc);
705
706 sk_sp<GrRefCntedCallback> releaseHelper(new GrRefCntedCallback(deleteImageProc,
707 deleteImageCtx));
708
709 SkColorType colorType =
710 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
711
712 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
713
714 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
715 if (!proxyProvider) {
716 return nullptr;
717 }
718
719 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
720 backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType,
721 std::move(releaseHelper));
722 if (!proxy) {
723 return nullptr;
724 }
725
726 sk_sp<SkColorSpace> cs = pixmap.refColorSpace();
727 SkAlphaType at = pixmap.alphaType();
728
729 GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(backendFormat, grColorType);
730 GrSurfaceProxyView view(std::move(proxy), surfaceOrigin, swizzle);
731 sk_sp<SkImage> image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext), kNeedNewImageUniqueID, view,
732 colorType, at, cs);
733 if (!image) {
734 return nullptr;
735 }
736
737 GrDrawingManager* drawingManager = dContext->priv().drawingManager();
738 if (!drawingManager) {
739 return nullptr;
740 }
741
742 GrSurfaceContext surfaceContext(dContext, std::move(view),
743 SkColorTypeToGrColorType(pixmap.colorType()),
744 pixmap.alphaType(), cs);
745
746 SkImageInfo srcInfo = SkImageInfo::Make(bufferDesc.width, bufferDesc.height, colorType, at,
747 std::move(cs));
748 surfaceContext.writePixels(dContext, srcInfo, pixmap.addr(0, 0), pixmap.rowBytes(), {0, 0});
749
750 GrSurfaceProxy* p[1] = {surfaceContext.asSurfaceProxy()};
751 drawingManager->flush(p, 1, SkSurface::BackendSurfaceAccess::kNoAccess, {}, nullptr);
752
753 return image;
754}
755#endif
756
757///////////////////////////////////////////////////////////////////////////////////////////////////
758
759bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
760 sk_sp<SkImage> image,
761 GrBackendTexture* backendTexture,
762 BackendTextureReleaseProc* releaseProc) {
763 // TODO: Elevate direct context requirement to public API.
764 auto direct = GrAsDirectContext(ctx);
765 if (!image || !direct || !backendTexture || !releaseProc) {
766 return false;
767 }
768
769 // Ensure we have a texture backed image.
770 if (!image->isTextureBacked()) {
771 image = image->makeTextureImage(direct);
772 if (!image) {
773 return false;
774 }
775 }
776 SkImage_GpuBase* gpuImage = static_cast<SkImage_GpuBase*>(as_IB(image));
777 GrTexture* texture = gpuImage->getTexture();
778 if (!texture) {
779 // In context-loss cases, we may not have a texture.
780 return false;
781 }
782
783 // If the image's context doesn't match the provided context, fail.
784 if (texture->getContext() != direct) {
785 return false;
786 }
787
788 // Flush any pending IO on the texture.
789 direct->priv().flushSurface(as_IB(image)->peekProxy());
790
791 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
792 // image is not unique, or if the texture wraps an external object.
793 if (!image->unique() || !texture->unique() ||
794 texture->resourcePriv().refsWrappedObjects()) {
795 // onMakeSubset will always copy the image.
796 image = as_IB(image)->onMakeSubset(image->bounds(), direct);
797 if (!image) {
798 return false;
799 }
800
801 texture = gpuImage->getTexture();
802 if (!texture) {
803 return false;
804 }
805
806 // Flush to ensure that the copy is completed before we return the texture.
807 direct->priv().flushSurface(as_IB(image)->peekProxy());
808 }
809
810 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
811 SkASSERT(texture->unique());
812 SkASSERT(image->unique());
813
814 // Take a reference to the GrTexture and release the image.
815 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
816 image = nullptr;
817
818 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
819 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
820}
821