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 "GrAHardwareBufferImageGenerator.h"
13 #include "GrBackendSurface.h"
14 #include "GrBackendTextureImageGenerator.h"
15 #include "GrBitmapTextureMaker.h"
16 #include "GrCaps.h"
17 #include "GrClip.h"
18 #include "GrColorSpaceXform.h"
19 #include "GrContext.h"
20 #include "GrContextPriv.h"
21 #include "GrGpu.h"
22 #include "GrImageTextureMaker.h"
23 #include "GrProxyProvider.h"
24 #include "GrRenderTargetContext.h"
25 #include "GrResourceProvider.h"
26 #include "GrResourceProviderPriv.h"
27 #include "GrSemaphore.h"
28 #include "GrSurfacePriv.h"
29 #include "GrTexture.h"
30 #include "GrTextureAdjuster.h"
31 #include "GrTexturePriv.h"
32 #include "GrTextureProxy.h"
33 #include "GrTextureProxyPriv.h"
34 #include "SkAutoPixmapStorage.h"
35 #include "SkBitmapCache.h"
36 #include "SkCanvas.h"
37 #include "SkGr.h"
38 #include "SkImageInfoPriv.h"
39 #include "SkImage_Gpu.h"
40 #include "SkMipMap.h"
41 #include "SkScopeExit.h"
42 #include "SkTraceEvent.h"
43 #include "effects/GrYUVtoRGBEffect.h"
44 #include "gl/GrGLTexture.h"
45 
46 SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
47                          sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace)
48         : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID,
49                     at, colorSpace)
50         , fProxy(std::move(proxy)) {}
51 
52 SkImage_Gpu::~SkImage_Gpu() {}
53 
54 SkImageInfo SkImage_Gpu::onImageInfo() const {
55     SkColorType colorType;
56     if (!GrPixelConfigToColorType(fProxy->config(), &colorType)) {
57         colorType = kUnknown_SkColorType;
58     }
59 
60     return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace);
61 }
62 
63 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(SkColorType targetCT,
64                                                          sk_sp<SkColorSpace> targetCS) const {
65     auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
66                                                targetCS.get(), fAlphaType);
67     SkASSERT(xform || targetCT != this->colorType());
68 
69     sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
70 
71     GrBackendFormat format = proxy->backendFormat().makeTexture2D();
72     if (!format.isValid()) {
73         return nullptr;
74     }
75 
76     sk_sp<GrRenderTargetContext> renderTargetContext(
77         fContext->contextPriv().makeDeferredRenderTargetContextWithFallback(
78             format, SkBackingFit::kExact, this->width(), this->height(),
79             SkColorType2GrPixelConfig(targetCT), nullptr));
80     if (!renderTargetContext) {
81         return nullptr;
82     }
83 
84     GrPaint paint;
85     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
86     paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I());
87     if (xform) {
88         paint.addColorFragmentProcessor(std::move(xform));
89     }
90 
91     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
92                                   SkRect::MakeIWH(this->width(), this->height()));
93     if (!renderTargetContext->asTextureProxy()) {
94         return nullptr;
95     }
96 
97     // MDB: this call is okay bc we know 'renderTargetContext' was exact
98     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
99                                    renderTargetContext->asTextureProxyRef(), std::move(targetCS));
100 }
101 
102 ///////////////////////////////////////////////////////////////////////////////////////////////////
103 
104 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
105                                                  const GrBackendTexture& backendTex,
106                                                  GrSurfaceOrigin origin,
107                                                  SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
108                                                  GrWrapOwnership ownership,
109                                                  SkImage::TextureReleaseProc releaseProc,
110                                                  SkImage::ReleaseContext releaseCtx) {
111     if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
112         return nullptr;
113     }
114 
115     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
116     sk_sp<GrTextureProxy> proxy =
117             proxyProvider->wrapBackendTexture(backendTex, origin, ownership, GrWrapCacheable::kNo,
118                                               kRead_GrIOType, releaseProc, releaseCtx);
119     if (!proxy) {
120         return nullptr;
121     }
122     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy),
123                                    std::move(colorSpace));
124 }
125 
126 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
127                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
128                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
129                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
130     if (!ctx) {
131         return nullptr;
132     }
133     GrBackendTexture texCopy = tex;
134     if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
135         return nullptr;
136     }
137     return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
138                                       kBorrow_GrWrapOwnership, releaseP, releaseC);
139 }
140 
141 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
142                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
143                                                SkColorType ct, SkAlphaType at,
144                                                sk_sp<SkColorSpace> cs) {
145     if (!ctx || !ctx->contextPriv().resourceProvider()) {
146         // We have a DDL context and we don't support adopted textures for them.
147         return nullptr;
148     }
149     GrBackendTexture texCopy = tex;
150     if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
151         return nullptr;
152     }
153     return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
154                                       kAdopt_GrWrapOwnership, nullptr, nullptr);
155 }
156 
157 sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
158                                            int width, int height, CompressionType type) {
159     // create the backing texture
160     GrSurfaceDesc desc;
161     desc.fFlags = kNone_GrSurfaceFlags;
162     desc.fWidth = width;
163     desc.fHeight = height;
164     switch (type) {
165         case kETC1_CompressionType:
166             desc.fConfig = kRGB_ETC1_GrPixelConfig;
167             break;
168         default:
169             desc.fConfig = kUnknown_GrPixelConfig;
170             break;
171     }
172     desc.fSampleCnt = 1;
173 
174     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
175     sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(std::move(data), desc);
176 
177     if (!proxy) {
178         return nullptr;
179     }
180 
181     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
182                                    std::move(proxy), nullptr);
183 }
184 
185 sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
186                                                      const GrBackendTexture yuvaTextures[],
187                                                      const SkYUVAIndex yuvaIndices[4], SkISize size,
188                                                      GrSurfaceOrigin origin,
189                                                      GrRenderTargetContext* renderTargetContext) {
190     SkASSERT(renderTargetContext);
191 
192     int numTextures;
193     if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
194         return nullptr;
195     }
196 
197     sk_sp<GrTextureProxy> tempTextureProxies[4];
198     if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
199                                                  origin, tempTextureProxies)) {
200         return nullptr;
201     }
202 
203     const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
204     if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace,
205                           tempTextureProxies, yuvaIndices)) {
206         return nullptr;
207     }
208 
209     SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices);
210     // MDB: this call is okay bc we know 'renderTargetContext' was exact
211     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at,
212                                    renderTargetContext->asTextureProxyRef(),
213                                    renderTargetContext->colorSpaceInfo().refColorSpace());
214 }
215 
216 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* ctx,
217                                                  SkYUVColorSpace yuvColorSpace,
218                                                  const GrBackendTexture yuvaTextures[],
219                                                  const SkYUVAIndex yuvaIndices[4],
220                                                  SkISize imageSize,
221                                                  GrSurfaceOrigin imageOrigin,
222                                                  sk_sp<SkColorSpace> imageColorSpace) {
223     const int width = imageSize.width();
224     const int height = imageSize.height();
225 
226     const GrBackendFormat format =
227             ctx->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
228 
229     // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
230     sk_sp<GrRenderTargetContext> renderTargetContext(
231             ctx->contextPriv().makeDeferredRenderTargetContext(
232                     format, SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
233                     std::move(imageColorSpace), 1, GrMipMapped::kNo, imageOrigin));
234     if (!renderTargetContext) {
235         return nullptr;
236     }
237 
238     return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
239                                                  imageSize, imageOrigin, renderTargetContext.get());
240 }
241 
242 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
243         GrContext* ctx,
244         SkYUVColorSpace yuvColorSpace,
245         const GrBackendTexture yuvaTextures[],
246         const SkYUVAIndex yuvaIndices[4],
247         SkISize imageSize,
248         GrSurfaceOrigin imageOrigin,
249         const GrBackendTexture& backendTexture,
250         sk_sp<SkColorSpace> imageColorSpace) {
251     GrBackendTexture backendTextureCopy = backendTexture;
252 
253     SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices);
254     if (!SkImage_Gpu::ValidateBackendTexture(ctx, backendTextureCopy, &backendTextureCopy.fConfig,
255                                              kRGBA_8888_SkColorType, at, nullptr)) {
256         return nullptr;
257     }
258 
259     // Needs to create a render target with external texture
260     // in order to draw to it for the yuv->rgb conversion.
261     sk_sp<GrRenderTargetContext> renderTargetContext(
262             ctx->contextPriv().makeBackendTextureRenderTargetContext(backendTextureCopy,
263                                                                      imageOrigin, 1,
264                                                                      std::move(imageColorSpace)));
265 
266     if (!renderTargetContext) {
267         return nullptr;
268     }
269 
270     return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
271                                                  imageSize, imageOrigin, renderTargetContext.get());
272 }
273 
274 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
275                                                 const GrBackendTexture yuvTextures[3],
276                                                 GrSurfaceOrigin imageOrigin,
277                                                 sk_sp<SkColorSpace> imageColorSpace) {
278     // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
279     SkYUVAIndex yuvaIndices[4] = {
280             SkYUVAIndex{0, SkColorChannel::kR},
281             SkYUVAIndex{1, SkColorChannel::kR},
282             SkYUVAIndex{2, SkColorChannel::kR},
283             SkYUVAIndex{-1, SkColorChannel::kA}};
284     SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
285     return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, yuvTextures, yuvaIndices,
286                                                  size, imageOrigin, std::move(imageColorSpace));
287 }
288 
289 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
290         GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
291         GrSurfaceOrigin imageOrigin, const GrBackendTexture& backendTexture,
292         sk_sp<SkColorSpace> imageColorSpace) {
293     SkYUVAIndex yuvaIndices[4] = {
294             SkYUVAIndex{0, SkColorChannel::kR},
295             SkYUVAIndex{1, SkColorChannel::kR},
296             SkYUVAIndex{2, SkColorChannel::kR},
297             SkYUVAIndex{-1, SkColorChannel::kA}};
298     SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
299     return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
300             ctx, yuvColorSpace, yuvTextures, yuvaIndices, size, imageOrigin, backendTexture,
301             std::move(imageColorSpace));
302 }
303 
304 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
305                                                  const GrBackendTexture nv12Textures[2],
306                                                  GrSurfaceOrigin imageOrigin,
307                                                  sk_sp<SkColorSpace> imageColorSpace) {
308     // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
309     SkYUVAIndex yuvaIndices[4] = {
310             SkYUVAIndex{0, SkColorChannel::kR},
311             SkYUVAIndex{1, SkColorChannel::kR},
312             SkYUVAIndex{1, SkColorChannel::kG},
313             SkYUVAIndex{-1, SkColorChannel::kA}};
314     SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
315     return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, nv12Textures, yuvaIndices,
316                                                  size, imageOrigin, std::move(imageColorSpace));
317 }
318 
319 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
320         GrContext* ctx,
321         SkYUVColorSpace yuvColorSpace,
322         const GrBackendTexture nv12Textures[2],
323         GrSurfaceOrigin imageOrigin,
324         const GrBackendTexture& backendTexture,
325         sk_sp<SkColorSpace> imageColorSpace) {
326     SkYUVAIndex yuvaIndices[4] = {
327             SkYUVAIndex{0, SkColorChannel::kR},
328             SkYUVAIndex{1, SkColorChannel::kR},
329             SkYUVAIndex{1, SkColorChannel::kG},
330             SkYUVAIndex{-1, SkColorChannel::kA}};
331     SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
332     return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
333             ctx, yuvColorSpace, nv12Textures, yuvaIndices, size, imageOrigin, backendTexture,
334             std::move(imageColorSpace));
335 }
336 
337 static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
338                                                  SkAlphaType at, uint32_t id,
339                                                  GrMipMapped mipMapped) {
340     sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped));
341     if (!proxy) {
342         return nullptr;
343     }
344     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, at, std::move(proxy),
345                                    sk_ref_sp(producer->colorSpace()));
346 }
347 
348 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
349                                          GrMipMapped mipMapped) const {
350     if (!context) {
351         return nullptr;
352     }
353     if (uint32_t incumbentID = as_IB(this)->contextID()) {
354         if (incumbentID != context->contextPriv().contextID()) {
355             return nullptr;
356         }
357         sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef();
358         SkASSERT(proxy);
359         if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) {
360             return sk_ref_sp(const_cast<SkImage*>(this));
361         }
362         GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(),
363                                    this->uniqueID(), this->colorSpace());
364         return create_image_from_producer(context, &adjuster, this->alphaType(),
365                                           this->uniqueID(), mipMapped);
366     }
367 
368     if (this->isLazyGenerated()) {
369         GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
370         return create_image_from_producer(context, &maker, this->alphaType(),
371                                           this->uniqueID(), mipMapped);
372     }
373 
374     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
375         GrBitmapTextureMaker maker(context, *bmp);
376         return create_image_from_producer(context, &maker, this->alphaType(),
377                                           this->uniqueID(), mipMapped);
378     }
379     return nullptr;
380 }
381 
382 ///////////////////////////////////////////////////////////////////////////////////////////////////
383 
384 sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
385                                                const GrBackendFormat& backendFormat,
386                                                int width,
387                                                int height,
388                                                GrMipMapped mipMapped,
389                                                GrSurfaceOrigin origin,
390                                                SkColorType colorType,
391                                                SkAlphaType alphaType,
392                                                sk_sp<SkColorSpace> colorSpace,
393                                                PromiseImageTextureFulfillProc textureFulfillProc,
394                                                PromiseImageTextureReleaseProc textureReleaseProc,
395                                                PromiseImageTextureDoneProc textureDoneProc,
396                                                PromiseImageTextureContext textureContext,
397                                                DelayReleaseCallback delayReleaseCallback) {
398     // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
399     // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
400     // responsibility for calling the done proc.
401     if (!textureDoneProc) {
402         return nullptr;
403     }
404     SkScopeExit callDone([textureDoneProc, textureContext]() { textureDoneProc(textureContext); });
405 
406     SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
407     if (!SkImageInfoIsValid(info)) {
408         return nullptr;
409     }
410 
411     if (!context) {
412         return nullptr;
413     }
414 
415     if (width <= 0 || height <= 0) {
416         return nullptr;
417     }
418 
419     GrPixelConfig config =
420             context->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, colorType);
421     if (config == kUnknown_GrPixelConfig) {
422         return nullptr;
423     }
424 
425     callDone.clear();
426     auto proxy = MakePromiseImageLazyProxy(context, width, height, origin, config, backendFormat,
427                                            mipMapped, textureFulfillProc, textureReleaseProc,
428                                            textureDoneProc, textureContext, delayReleaseCallback);
429     if (!proxy) {
430         return nullptr;
431     }
432     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType,
433                                    std::move(proxy), std::move(colorSpace));
434 }
435 
436 ///////////////////////////////////////////////////////////////////////////////////////////////////
437 
438 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
439                                                     bool buildMips, SkColorSpace* dstColorSpace,
440                                                     bool limitToMaxTextureSize) {
441     sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
442     if (!codecImage) {
443         return nullptr;
444     }
445 
446     // Some backends or drivers don't support (safely) moving resources between contexts
447     if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
448         return codecImage;
449     }
450 
451     auto maxTextureSize = context->contextPriv().caps()->maxTextureSize();
452     if (limitToMaxTextureSize &&
453         (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) {
454         SkAutoPixmapStorage pmap;
455         SkImageInfo info = as_IB(codecImage)->onImageInfo();
456         if (!dstColorSpace) {
457             info = info.makeColorSpace(nullptr);
458         }
459         if (!pmap.tryAlloc(info) || !codecImage->readPixels(pmap, 0, 0, kDisallow_CachingHint)) {
460             return nullptr;
461         }
462         return MakeCrossContextFromPixmap(context, pmap, buildMips, dstColorSpace, true);
463     }
464 
465     // Turn the codec image into a GrTextureProxy
466     GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
467     GrSamplerState samplerState(
468             GrSamplerState::WrapMode::kClamp,
469             buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
470     sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(samplerState, nullptr));
471     if (!proxy) {
472         return codecImage;
473     }
474 
475     if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
476         return codecImage;
477     }
478     sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
479 
480     // Flush any writes or uploads
481     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
482 
483     GrGpu* gpu = context->contextPriv().getGpu();
484     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
485 
486     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
487                                                     std::move(sema),
488                                                     as_IB(codecImage)->onImageInfo().colorType(),
489                                                     codecImage->alphaType(),
490                                                     codecImage->refColorSpace());
491     return SkImage::MakeFromGenerator(std::move(gen));
492 }
493 
494 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context,
495                                                    const SkPixmap& originalPixmap, bool buildMips,
496                                                    SkColorSpace* dstColorSpace,
497                                                    bool limitToMaxTextureSize) {
498     // Some backends or drivers don't support (safely) moving resources between contexts
499     if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
500         return SkImage::MakeRasterCopy(originalPixmap);
501     }
502 
503     // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not
504     // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy
505     // instead.
506     if (!context->contextPriv().resourceProvider()) {
507         return SkImage::MakeRasterCopy(originalPixmap);
508     }
509 
510     const SkPixmap* pixmap = &originalPixmap;
511     SkAutoPixmapStorage resized;
512     int maxTextureSize = context->contextPriv().caps()->maxTextureSize();
513     int maxDim = SkTMax(originalPixmap.width(), originalPixmap.height());
514     if (limitToMaxTextureSize && maxDim > maxTextureSize) {
515         float scale = static_cast<float>(maxTextureSize) / maxDim;
516         int newWidth = SkTMin(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
517         int newHeight = SkTMin(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
518         SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
519         if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) {
520             return nullptr;
521         }
522         pixmap = &resized;
523     }
524     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
525     // Turn the pixmap into a GrTextureProxy
526     sk_sp<GrTextureProxy> proxy;
527     if (buildMips) {
528         SkBitmap bmp;
529         bmp.installPixels(*pixmap);
530         proxy = proxyProvider->createMipMapProxyFromBitmap(bmp);
531     } else {
532         if (SkImageInfoIsValid(pixmap->info())) {
533             ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap->width(), pixmap->height());
534             // We don't need a release proc on the data in pixmap since we know we are in a
535             // GrContext that has a resource provider. Thus the createTextureProxy call will
536             // immediately upload the data.
537             sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
538             proxy = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
539                                                       SkBudgeted::kYes, SkBackingFit::kExact);
540         }
541     }
542 
543     if (!proxy) {
544         return SkImage::MakeRasterCopy(*pixmap);
545     }
546 
547     sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
548 
549     // Flush any writes or uploads
550     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
551     GrGpu* gpu = context->contextPriv().getGpu();
552 
553     sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
554 
555     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
556                                                     std::move(sema), pixmap->colorType(),
557                                                     pixmap->alphaType(),
558                                                     pixmap->info().refColorSpace());
559     return SkImage::MakeFromGenerator(std::move(gen));
560 }
561 
562 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
563 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
564                                                 sk_sp<SkColorSpace> cs,
565                                                 GrSurfaceOrigin surfaceOrigin) {
566     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin);
567     return SkImage::MakeFromGenerator(std::move(gen));
568 }
569 #endif
570 
571 ///////////////////////////////////////////////////////////////////////////////////////////////////
572 
573 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
574                                             sk_sp<SkImage> image,
575                                             GrBackendTexture* backendTexture,
576                                             BackendTextureReleaseProc* releaseProc) {
577     if (!image || !ctx || !backendTexture || !releaseProc) {
578         return false;
579     }
580 
581     // Ensure we have a texture backed image.
582     if (!image->isTextureBacked()) {
583         image = image->makeTextureImage(ctx, nullptr);
584         if (!image) {
585             return false;
586         }
587     }
588     GrTexture* texture = image->getTexture();
589     if (!texture) {
590         // In context-loss cases, we may not have a texture.
591         return false;
592     }
593 
594     // If the image's context doesn't match the provided context, fail.
595     if (texture->getContext() != ctx) {
596         return false;
597     }
598 
599     // Flush any pending IO on the texture.
600     ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
601     SkASSERT(!texture->surfacePriv().hasPendingIO());
602 
603     // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
604     // image is not unique, or if the texture wraps an external object.
605     if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
606         texture->resourcePriv().refsWrappedObjects()) {
607         // onMakeSubset will always copy the image.
608         image = as_IB(image)->onMakeSubset(image->bounds());
609         if (!image) {
610             return false;
611         }
612 
613         texture = image->getTexture();
614         if (!texture) {
615             return false;
616         }
617 
618         // Flush to ensure that the copy is completed before we return the texture.
619         ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
620         SkASSERT(!texture->surfacePriv().hasPendingIO());
621     }
622 
623     SkASSERT(!texture->resourcePriv().refsWrappedObjects());
624     SkASSERT(texture->surfacePriv().hasUniqueRef());
625     SkASSERT(image->unique());
626 
627     // Take a reference to the GrTexture and release the image.
628     sk_sp<GrTexture> textureRef(SkSafeRef(texture));
629     image = nullptr;
630 
631     // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
632     return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
633 }
634