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