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