• 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 "SkAutoPixmapStorage.h"
13 #include "GrBackendSurface.h"
14 #include "GrBackendTextureImageGenerator.h"
15 #include "GrAHardwareBufferImageGenerator.h"
16 #include "GrBitmapTextureMaker.h"
17 #include "GrCaps.h"
18 #include "GrContext.h"
19 #include "GrContextPriv.h"
20 #include "GrGpu.h"
21 #include "GrImageTextureMaker.h"
22 #include "GrRenderTargetContext.h"
23 #include "GrResourceProvider.h"
24 #include "GrSemaphore.h"
25 #include "GrTextureAdjuster.h"
26 #include "GrTexture.h"
27 #include "GrTextureProxy.h"
28 #include "effects/GrNonlinearColorSpaceXformEffect.h"
29 #include "effects/GrYUVEffect.h"
30 #include "SkCanvas.h"
31 #include "SkBitmapCache.h"
32 #include "SkGr.h"
33 #include "SkImage_Gpu.h"
34 #include "SkImageCacherator.h"
35 #include "SkImageInfoPriv.h"
36 #include "SkMipMap.h"
37 #include "SkPixelRef.h"
38 #include "SkReadPixelsRec.h"
39 
SkImage_Gpu(GrContext * context,uint32_t uniqueID,SkAlphaType at,sk_sp<GrTextureProxy> proxy,sk_sp<SkColorSpace> colorSpace,SkBudgeted budgeted)40 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
41                          sk_sp<GrTextureProxy> proxy,
42                          sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
43     : INHERITED(proxy->width(), proxy->height(), uniqueID)
44     , fContext(context)
45     , fProxy(std::move(proxy))
46     , fAlphaType(at)
47     , fBudgeted(budgeted)
48     , fColorSpace(std::move(colorSpace))
49     , fAddedRasterVersionToCache(false) {
50 }
51 
~SkImage_Gpu()52 SkImage_Gpu::~SkImage_Gpu() {
53     if (fAddedRasterVersionToCache.load()) {
54         SkNotifyBitmapGenIDIsStale(this->uniqueID());
55     }
56 }
57 
onImageInfo() const58 SkImageInfo SkImage_Gpu::onImageInfo() const {
59     SkColorType ct;
60     if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
61         ct = kUnknown_SkColorType;
62     }
63     return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
64 }
65 
getROPixels(SkBitmap * dst,SkColorSpace *,CachingHint chint) const66 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
67     // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
68     // will be used. The client doesn't expect that we convert to that color space, it's intended
69     // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
70     // into that color space (to save the client some effort in whatever they're about to do), but
71     // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
72     // rolled the dstColorSpace into the key).
73     const auto desc = SkBitmapCacheDesc::Make(this);
74     if (SkBitmapCache::Find(desc, dst)) {
75         SkASSERT(dst->getGenerationID() == this->uniqueID());
76         SkASSERT(dst->isImmutable());
77         SkASSERT(dst->getPixels());
78         return true;
79     }
80 
81     SkBitmapCache::RecPtr rec = nullptr;
82     SkPixmap pmap;
83     if (kAllow_CachingHint == chint) {
84         rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
85         if (!rec) {
86             return false;
87         }
88     } else {
89         if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
90             return false;
91         }
92     }
93 
94     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
95                                                                                     fProxy,
96                                                                                     fColorSpace);
97     if (!sContext) {
98         return false;
99     }
100 
101     if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
102         return false;
103     }
104 
105     if (rec) {
106         SkBitmapCache::Add(std::move(rec), dst);
107         fAddedRasterVersionToCache.store(true);
108     }
109     return true;
110 }
111 
asTextureProxyRef(GrContext * context,const GrSamplerParams & params,SkColorSpace * dstColorSpace,sk_sp<SkColorSpace> * texColorSpace,SkScalar scaleAdjust[2]) const112 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
113                                                      const GrSamplerParams& params,
114                                                      SkColorSpace* dstColorSpace,
115                                                      sk_sp<SkColorSpace>* texColorSpace,
116                                                      SkScalar scaleAdjust[2]) const {
117     if (context != fContext) {
118         SkASSERT(0);
119         return nullptr;
120     }
121 
122     if (texColorSpace) {
123         *texColorSpace = this->fColorSpace;
124     }
125 
126     GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(),
127                                this->uniqueID(), this->fColorSpace.get());
128     return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
129 }
130 
apply_premul(const SkImageInfo & info,void * pixels,size_t rowBytes)131 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
132     switch (info.colorType()) {
133         case kRGBA_8888_SkColorType:
134         case kBGRA_8888_SkColorType:
135             break;
136         default:
137             return; // nothing to do
138     }
139 
140     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
141     // and in either case, the alpha-byte is always in the same place, so we can safely call
142     // SkPreMultiplyColor()
143     //
144     SkColor* row = (SkColor*)pixels;
145     for (int y = 0; y < info.height(); ++y) {
146         for (int x = 0; x < info.width(); ++x) {
147             row[x] = SkPreMultiplyColor(row[x]);
148         }
149     }
150 }
151 
onGetTextureHandle(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const152 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
153                                                 GrSurfaceOrigin* origin) const {
154     SkASSERT(fProxy);
155 
156     if (!fProxy->instantiate(fContext->resourceProvider())) {
157         return 0;
158     }
159 
160     GrTexture* texture = fProxy->priv().peekTexture();
161 
162     if (texture) {
163         if (flushPendingGrContextIO) {
164             fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
165         }
166         if (origin) {
167             *origin = fProxy->origin();
168         }
169         return texture->getTextureHandle();
170     }
171     return 0;
172 }
173 
onGetTexture() const174 GrTexture* SkImage_Gpu::onGetTexture() const {
175     GrTextureProxy* proxy = this->peekProxy();
176     if (!proxy) {
177         return nullptr;
178     }
179 
180     if (!proxy->instantiate(fContext->resourceProvider())) {
181         return nullptr;
182     }
183 
184     return proxy->priv().peekTexture();
185 }
186 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,int srcX,int srcY,CachingHint) const187 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
188                                int srcX, int srcY, CachingHint) const {
189     if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
190         return false;
191     }
192 
193     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
194     if (!rec.trim(this->width(), this->height())) {
195         return false;
196     }
197 
198     // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
199     // GrRenderTargetContext::onReadPixels
200     uint32_t flags = 0;
201     if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
202         // let the GPU perform this transformation for us
203         flags = GrContextPriv::kUnpremul_PixelOpsFlag;
204     }
205 
206     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
207                                                                                     fProxy,
208                                                                                     fColorSpace);
209     if (!sContext) {
210         return false;
211     }
212 
213     if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
214         return false;
215     }
216 
217     // do we have to manually fix-up the alpha channel?
218     //      src         dst
219     //      unpremul    premul      fix manually
220     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
221     // all other combos need to change.
222     //
223     // Should this be handled by Ganesh? todo:?
224     //
225     if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
226         apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
227     }
228     return true;
229 }
230 
onMakeSubset(const SkIRect & subset) const231 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
232     GrSurfaceDesc desc;
233     desc.fConfig = fProxy->config();
234     desc.fWidth = subset.width();
235     desc.fHeight = subset.height();
236     desc.fOrigin = fProxy->origin();
237 
238     sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
239                                                                         desc,
240                                                                         SkBackingFit::kExact,
241                                                                         fBudgeted));
242     if (!sContext) {
243         return nullptr;
244     }
245 
246     if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
247         return nullptr;
248     }
249 
250     // MDB: this call is okay bc we know 'sContext' was kExact
251     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
252                                    fAlphaType, sContext->asTextureProxyRef(),
253                                    fColorSpace, fBudgeted);
254 }
255 
256 ///////////////////////////////////////////////////////////////////////////////////////////////////
257 
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)258 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
259                                                  const GrBackendTexture& backendTex,
260                                                  GrSurfaceOrigin origin,
261                                                  SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
262                                                  GrWrapOwnership ownership,
263                                                  SkImage::TextureReleaseProc releaseProc,
264                                                  SkImage::ReleaseContext releaseCtx) {
265     if (backendTex.width() <= 0 || backendTex.height() <= 0) {
266         return nullptr;
267     }
268 
269     GrBackendTextureFlags flags = kNone_GrBackendTextureFlag;
270     sk_sp<GrTexture> tex = ctx->resourceProvider()->wrapBackendTexture(backendTex,
271                                                                        origin,
272                                                                        flags,
273                                                                        0,
274                                                                        ownership);
275     if (!tex) {
276         return nullptr;
277     }
278     if (releaseProc) {
279         tex->setRelease(releaseProc, releaseCtx);
280     }
281 
282     const SkBudgeted budgeted = SkBudgeted::kNo;
283     sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
284     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
285                                    at, std::move(proxy), std::move(colorSpace), budgeted);
286 }
287 
MakeFromTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)288 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
289                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
290                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
291     SkASSERT(!(kRenderTarget_GrBackendTextureFlag & desc.fFlags));
292     GrBackendTexture tex(desc, ctx->contextPriv().getBackend());
293     return new_wrapped_texture_common(ctx, tex, desc.fOrigin, at, std::move(cs),
294                                       kBorrow_GrWrapOwnership,
295                                       releaseP, releaseC);
296 }
297 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,sk_sp<SkColorSpace> cs)298 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
299                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
300     SkASSERT(!(kRenderTarget_GrBackendTextureFlag & desc.fFlags));
301     GrBackendTexture tex(desc, ctx->contextPriv().getBackend());
302     return new_wrapped_texture_common(ctx, tex, desc.fOrigin, at, std::move(cs),
303                                       kAdopt_GrWrapOwnership,
304                                       nullptr, nullptr);
305 }
306 
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)307 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
308                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
309                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
310                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
311     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership,
312                                       releaseP, releaseC);
313 }
314 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs)315 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
316                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
317                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
318     return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
319                                       nullptr, nullptr);
320 }
321 
make_backend_texture_from_handle(GrBackend backend,int width,int height,GrPixelConfig config,GrBackendObject handle)322 static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
323                                                          int width, int height,
324                                                          GrPixelConfig config,
325                                                          GrBackendObject handle) {
326     switch (backend) {
327         case kOpenGL_GrBackend: {
328             const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle);
329             return GrBackendTexture(width, height, config, *glInfo);
330         }
331 #ifdef SK_VULKAN
332         case kVulkan_GrBackend: {
333             const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle);
334             return GrBackendTexture(width, height, *vkInfo);
335         }
336 #endif
337         case kMock_GrBackend: {
338             const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle);
339             return GrBackendTexture(width, height, config, *mockInfo);
340         }
341         default:
342             return GrBackendTexture();
343     }
344 }
345 
make_from_yuv_textures_copy(GrContext * ctx,SkYUVColorSpace colorSpace,bool nv12,const GrBackendObject yuvTextureHandles[],const SkISize yuvSizes[],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)346 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
347                                                   bool nv12,
348                                                   const GrBackendObject yuvTextureHandles[],
349                                                   const SkISize yuvSizes[],
350                                                   GrSurfaceOrigin origin,
351                                                   sk_sp<SkColorSpace> imageColorSpace) {
352     const SkBudgeted budgeted = SkBudgeted::kYes;
353 
354     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 ||
355         yuvSizes[1].fHeight <= 0) {
356         return nullptr;
357     }
358     if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
359         return nullptr;
360     }
361 
362     const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
363 
364     GrBackend backend = ctx->contextPriv().getBackend();
365     GrBackendTexture yTex = make_backend_texture_from_handle(backend,
366                                                              yuvSizes[0].fWidth,
367                                                              yuvSizes[0].fHeight,
368                                                              kConfig,
369                                                              yuvTextureHandles[0]);
370     GrBackendTexture uTex = make_backend_texture_from_handle(backend,
371                                                              yuvSizes[1].fWidth,
372                                                              yuvSizes[1].fHeight,
373                                                              kConfig,
374                                                              yuvTextureHandles[1]);
375 
376     sk_sp<GrTextureProxy> yProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, yTex, origin);
377     sk_sp<GrTextureProxy> uProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, uTex, origin);
378     sk_sp<GrTextureProxy> vProxy;
379 
380     if (nv12) {
381         vProxy = uProxy;
382     } else {
383         GrBackendTexture vTex = make_backend_texture_from_handle(backend,
384                                                                  yuvSizes[2].fWidth,
385                                                                  yuvSizes[2].fHeight,
386                                                                  kConfig,
387                                                                  yuvTextureHandles[2]);
388         vProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, vTex, origin);
389     }
390     if (!yProxy || !uProxy || !vProxy) {
391         return nullptr;
392     }
393 
394     const int width = yuvSizes[0].fWidth;
395     const int height = yuvSizes[0].fHeight;
396 
397     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
398     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
399                                                                          SkBackingFit::kExact,
400                                                                          width, height,
401                                                                          kRGBA_8888_GrPixelConfig,
402                                                                          std::move(imageColorSpace),
403                                                                          0,
404                                                                          origin));
405     if (!renderTargetContext) {
406         return nullptr;
407     }
408 
409     GrPaint paint;
410     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
411     paint.addColorFragmentProcessor(GrYUVEffect::MakeYUVToRGB(yProxy, uProxy, vProxy,
412                                                               yuvSizes, colorSpace, nv12));
413 
414     const SkRect rect = SkRect::MakeIWH(width, height);
415 
416     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
417 
418     if (!renderTargetContext->asSurfaceProxy()) {
419         return nullptr;
420     }
421     ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
422 
423     // MDB: this call is okay bc we know 'renderTargetContext' was exact
424     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
425                                    kOpaque_SkAlphaType, renderTargetContext->asTextureProxyRef(),
426                                    renderTargetContext->refColorSpace(), budgeted);
427 }
428 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace colorSpace,const GrBackendObject yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)429 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
430                                                 const GrBackendObject yuvTextureHandles[3],
431                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
432                                                 sk_sp<SkColorSpace> imageColorSpace) {
433     return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
434                                        std::move(imageColorSpace));
435 }
436 
MakeFromNV12TexturesCopy(GrContext * ctx,SkYUVColorSpace colorSpace,const GrBackendObject yuvTextureHandles[2],const SkISize yuvSizes[2],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)437 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
438                                                  const GrBackendObject yuvTextureHandles[2],
439                                                  const SkISize yuvSizes[2],
440                                                  GrSurfaceOrigin origin,
441                                                  sk_sp<SkColorSpace> imageColorSpace) {
442     return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
443                                        std::move(imageColorSpace));
444 }
445 
create_image_from_maker(GrContext * context,GrTextureMaker * maker,SkAlphaType at,uint32_t id,SkColorSpace * dstColorSpace)446 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
447                                               SkAlphaType at, uint32_t id,
448                                               SkColorSpace* dstColorSpace) {
449     sk_sp<SkColorSpace> texColorSpace;
450     sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
451                                                                 dstColorSpace,
452                                                                 &texColorSpace, nullptr));
453     if (!proxy) {
454         return nullptr;
455     }
456     return sk_make_sp<SkImage_Gpu>(context, id, at,
457                                    std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
458 }
459 
makeTextureImage(GrContext * context,SkColorSpace * dstColorSpace) const460 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
461     if (!context) {
462         return nullptr;
463     }
464     if (GrContext* incumbent = as_IB(this)->context()) {
465         return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
466     }
467 
468     if (this->isLazyGenerated()) {
469         GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
470         return create_image_from_maker(context, &maker, this->alphaType(),
471                                        this->uniqueID(), dstColorSpace);
472     }
473 
474     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
475         GrBitmapTextureMaker maker(context, *bmp);
476         return create_image_from_maker(context, &maker, this->alphaType(),
477                                        this->uniqueID(), dstColorSpace);
478     }
479     return nullptr;
480 }
481 
MakeCrossContextFromEncoded(GrContext * context,sk_sp<SkData> encoded,bool buildMips,SkColorSpace * dstColorSpace)482 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
483                                                     bool buildMips, SkColorSpace* dstColorSpace) {
484     sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
485     if (!codecImage) {
486         return nullptr;
487     }
488 
489     // Some backends or drivers don't support (safely) moving resources between contexts
490     if (!context || !context->caps()->crossContextTextureSupport()) {
491         return codecImage;
492     }
493 
494     // Turn the codec image into a GrTextureProxy
495     GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
496     sk_sp<SkColorSpace> texColorSpace;
497     GrSamplerParams params(SkShader::kClamp_TileMode,
498                            buildMips ? GrSamplerParams::kMipMap_FilterMode
499                                      : GrSamplerParams::kBilerp_FilterMode);
500     sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(params, dstColorSpace,
501                                                                &texColorSpace, nullptr));
502     if (!proxy) {
503         return codecImage;
504     }
505 
506     if (!proxy->instantiate(context->resourceProvider())) {
507         return codecImage;
508     }
509     sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
510 
511     // Flush any writes or uploads
512     context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
513 
514     sk_sp<GrSemaphore> sema = context->getGpu()->prepareTextureForCrossContextUsage(texture.get());
515 
516     auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), std::move(sema),
517                                                     codecImage->alphaType(),
518                                                     std::move(texColorSpace));
519     return SkImage::MakeFromGenerator(std::move(gen));
520 }
521 
522 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(AHardwareBuffer * graphicBuffer,SkAlphaType at,sk_sp<SkColorSpace> cs)523 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
524                                                sk_sp<SkColorSpace> cs) {
525     auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
526     return SkImage::MakeFromGenerator(std::move(gen));
527 }
528 #endif
529 
makeNonTextureImage() const530 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
531     if (!this->isTextureBacked()) {
532         return sk_ref_sp(const_cast<SkImage*>(this));
533     }
534     SkImageInfo info = as_IB(this)->onImageInfo();
535     size_t rowBytes = info.minRowBytes();
536     size_t size = info.getSafeSize(rowBytes);
537     auto data = SkData::MakeUninitialized(size);
538     if (!data) {
539         return nullptr;
540     }
541     SkPixmap pm(info, data->writable_data(), rowBytes);
542     if (!this->readPixels(pm, 0, 0, kDisallow_CachingHint)) {
543         return nullptr;
544     }
545     return MakeRasterData(info, data, rowBytes);
546 }
547 
548 ///////////////////////////////////////////////////////////////////////////////////////////////////
549 
550 namespace {
551 struct MipMapLevelData {
552     void* fPixelData;
553     size_t fRowBytes;
554 };
555 
556 struct DeferredTextureImage {
557     uint32_t                      fContextUniqueID;
558     // Right now, the destination color mode is only considered when generating mipmaps
559     SkDestinationSurfaceColorMode fColorMode;
560     // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
561     int                           fWidth;
562     int                           fHeight;
563     SkColorType                   fColorType;
564     SkAlphaType                   fAlphaType;
565     void*                         fColorSpace;
566     size_t                        fColorSpaceSize;
567     int                           fMipMapLevelCount;
568     // The fMipMapLevelData array may contain more than 1 element.
569     // It contains fMipMapLevelCount elements.
570     // That means this struct's size is not known at compile-time.
571     MipMapLevelData               fMipMapLevelData[1];
572 };
573 }  // anonymous namespace
574 
should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param)575 static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
576     // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
577     // This can cause runaway memory leaks, so we are disabling this path until we can
578     // investigate further. crbug.com/669775
579     return false;
580 }
581 
582 namespace {
583 
584 class DTIBufferFiller
585 {
586 public:
DTIBufferFiller(char * bufferAsCharPtr)587     explicit DTIBufferFiller(char* bufferAsCharPtr)
588         : bufferAsCharPtr_(bufferAsCharPtr) {}
589 
fillMember(const void * source,size_t memberOffset,size_t size)590     void fillMember(const void* source, size_t memberOffset, size_t size) {
591         memcpy(bufferAsCharPtr_ + memberOffset, source, size);
592     }
593 
594 private:
595 
596     char* bufferAsCharPtr_;
597 };
598 }
599 
600 #define FILL_MEMBER(bufferFiller, member, source) \
601     bufferFiller.fillMember(source, \
602                offsetof(DeferredTextureImage, member), \
603                sizeof(DeferredTextureImage::member));
604 
SupportsColorSpace(SkColorType colorType)605 static bool SupportsColorSpace(SkColorType colorType) {
606     switch (colorType) {
607         case kRGBA_8888_SkColorType:
608         case kBGRA_8888_SkColorType:
609         case kRGBA_F16_SkColorType:
610             return true;
611         default:
612             return false;
613     }
614 }
615 
getDeferredTextureImageData(const GrContextThreadSafeProxy & proxy,const DeferredTextureImageUsageParams params[],int paramCnt,void * buffer,SkColorSpace * dstColorSpace,SkColorType dstColorType) const616 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
617                                             const DeferredTextureImageUsageParams params[],
618                                             int paramCnt, void* buffer,
619                                             SkColorSpace* dstColorSpace,
620                                             SkColorType dstColorType) const {
621     // Some quick-rejects where is makes no sense to return CPU data
622     //  e.g.
623     //      - texture backed
624     //      - picture backed
625     //
626     if (this->isTextureBacked()) {
627         return 0;
628     }
629     if (as_IB(this)->onCanLazyGenerateOnGPU()) {
630         return 0;
631     }
632 
633     bool supportsColorSpace = SupportsColorSpace(dstColorType);
634     // Quick reject if the caller requests a color space with an unsupported color type.
635     if (SkToBool(dstColorSpace) && !supportsColorSpace) {
636         return 0;
637     }
638 
639     // Extract relevant min/max values from the params array.
640     int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
641     SkFilterQuality highestFilterQuality = params[0].fQuality;
642     bool useMipMaps = should_use_mip_maps(params[0]);
643     for (int i = 1; i < paramCnt; ++i) {
644         if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
645             lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
646         if (highestFilterQuality < params[i].fQuality)
647             highestFilterQuality = params[i].fQuality;
648         useMipMaps |= should_use_mip_maps(params[i]);
649     }
650 
651     const bool fillMode = SkToBool(buffer);
652     if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
653         return 0;
654     }
655 
656     // Calculate scaling parameters.
657     bool isScaled = lowestPreScaleMipLevel != 0;
658 
659     SkISize scaledSize;
660     if (isScaled) {
661         // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
662         // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
663         scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
664                                                 lowestPreScaleMipLevel - 1);
665     } else {
666         scaledSize = SkISize::Make(this->width(), this->height());
667     }
668 
669     // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
670     SkFilterQuality scaleFilterQuality = highestFilterQuality;
671     if (scaleFilterQuality > kMedium_SkFilterQuality) {
672         scaleFilterQuality = kMedium_SkFilterQuality;
673     }
674 
675     const int maxTextureSize = proxy.fCaps->maxTextureSize();
676     if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
677         return 0;
678     }
679 
680     SkAutoPixmapStorage pixmap;
681     SkImageInfo info;
682     size_t pixelSize = 0;
683     if (!isScaled && this->peekPixels(&pixmap) && pixmap.info().colorType() == dstColorType) {
684         info = pixmap.info();
685         pixelSize = SkAlign8(pixmap.getSafeSize());
686         if (!dstColorSpace) {
687             pixmap.setColorSpace(nullptr);
688             info = info.makeColorSpace(nullptr);
689         }
690     } else {
691         if (!this->isLazyGenerated() && !this->peekPixels(nullptr)) {
692             return 0;
693         }
694         if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
695             // Generator backed image. Tweak info to trigger correct kind of decode.
696             SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
697                 dstColorSpace, proxy.fCaps.get());
698             info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
699                                                               scaledSize.height());
700         } else {
701             info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
702             if (!dstColorSpace) {
703                 info = info.makeColorSpace(nullptr);
704             }
705         }
706         // Force color type to be the requested type.
707         info = info.makeColorType(dstColorType);
708         pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
709         if (fillMode) {
710             // Always decode to N32 and convert to the requested type if necessary.
711             SkImageInfo decodeInfo = info.makeColorType(kN32_SkColorType);
712             SkAutoPixmapStorage decodePixmap;
713             decodePixmap.alloc(decodeInfo);
714 
715             if (isScaled) {
716                 if (!this->scalePixels(decodePixmap, scaleFilterQuality,
717                                        SkImage::kDisallow_CachingHint)) {
718                     return 0;
719                 }
720             } else {
721                 if (!this->readPixels(decodePixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
722                     return 0;
723                 }
724             }
725 
726             if (decodeInfo.colorType() != info.colorType()) {
727                 pixmap.alloc(info);
728                 // Convert and copy the decoded pixmap to the target pixmap.
729                 decodePixmap.readPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 0,
730                                         0);
731             } else {
732                 pixmap = std::move(decodePixmap);
733             }
734         }
735     }
736     int mipMapLevelCount = 1;
737     if (useMipMaps) {
738         // SkMipMap only deals with the mipmap levels it generates, which does
739         // not include the base level.
740         // That means it generates and holds levels 1-x instead of 0-x.
741         // So the total mipmap level count is 1 more than what
742         // SkMipMap::ComputeLevelCount returns.
743         mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
744 
745         // We already initialized pixelSize to the size of the base level.
746         // SkMipMap will generate the extra mipmap levels. Their sizes need to
747         // be added to the total.
748         // Index 0 here does not refer to the base mipmap level -- it is
749         // SkMipMap's first generated mipmap level (level 1).
750         for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
751              currentMipMapLevelIndex--) {
752             SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
753                                                          currentMipMapLevelIndex);
754             SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
755             pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
756         }
757     }
758     size_t size = 0;
759     size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
760     size += dtiSize;
761     size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
762     // We subtract 1 because DeferredTextureImage already includes the base
763     // level in its size
764     size_t pixelOffset = size;
765     size += pixelSize;
766     size_t colorSpaceOffset = 0;
767     size_t colorSpaceSize = 0;
768     SkColorSpaceTransferFn fn;
769     if (info.colorSpace()) {
770         SkASSERT(dstColorSpace);
771         SkASSERT(supportsColorSpace);
772         colorSpaceOffset = size;
773         colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
774         size += colorSpaceSize;
775     } else if (supportsColorSpace && this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
776         // In legacy mode, preserve the color space tag on the SkImage.  This is only
777         // supported if the color space has a parametric transfer function.
778         SkASSERT(!dstColorSpace);
779         colorSpaceOffset = size;
780         colorSpaceSize = this->colorSpace()->writeToMemory(nullptr);
781         size += colorSpaceSize;
782     }
783     if (!fillMode) {
784         return size;
785     }
786     char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
787     char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
788     void* pixels = pixelsAsCharPtr;
789 
790     memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
791                                    pixmap.addr(), pixmap.getSafeSize());
792 
793     // If the context has sRGB support, and we're intending to render to a surface with an attached
794     // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
795     // aware mip-mapping.
796     SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
797     if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
798         info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
799         SkASSERT(supportsColorSpace);
800         colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
801     }
802 
803     SkASSERT(info == pixmap.info());
804     size_t rowBytes = pixmap.rowBytes();
805     static_assert(std::is_standard_layout<DeferredTextureImage>::value,
806                   "offsetof, which we use below, requires the type have standard layout");
807     auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
808     FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
809     FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
810     int width = info.width();
811     FILL_MEMBER(dtiBufferFiller, fWidth, &width);
812     int height = info.height();
813     FILL_MEMBER(dtiBufferFiller, fHeight, &height);
814     SkColorType colorType = info.colorType();
815     FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
816     SkAlphaType alphaType = info.alphaType();
817     FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
818     FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
819     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
820            &pixels, sizeof(pixels));
821     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
822            &rowBytes, sizeof(rowBytes));
823     if (colorSpaceSize) {
824         void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
825         FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
826         FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
827         if (info.colorSpace()) {
828             info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
829         } else {
830             SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn));
831             SkASSERT(!dstColorSpace);
832             this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
833         }
834     } else {
835         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
836                0, sizeof(DeferredTextureImage::fColorSpace));
837         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
838                0, sizeof(DeferredTextureImage::fColorSpaceSize));
839     }
840 
841     // Fill in the mipmap levels if they exist
842     char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.getSafeSize());
843 
844     if (useMipMaps) {
845         static_assert(std::is_standard_layout<MipMapLevelData>::value,
846                       "offsetof, which we use below, requires the type have a standard layout");
847 
848         std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
849         // SkMipMap holds only the mipmap levels it generates.
850         // A programmer can use the data they provided to SkMipMap::Build as level 0.
851         // So the SkMipMap provides levels 1-x but it stores them in its own
852         // range 0-(x-1).
853         for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
854              generatedMipLevelIndex++) {
855             SkMipMap::Level mipLevel;
856             mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
857 
858             // Make sure the mipmap data is after the start of the buffer
859             SkASSERT(mipLevelPtr > bufferAsCharPtr);
860             // Make sure the mipmap data starts before the end of the buffer
861             SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
862             // Make sure the mipmap data ends before the end of the buffer
863             SkASSERT(mipLevelPtr + mipLevel.fPixmap.getSafeSize() <=
864                      bufferAsCharPtr + pixelOffset + pixelSize);
865 
866             // getSafeSize includes rowbyte padding except for the last row,
867             // right?
868 
869             memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.getSafeSize());
870 
871             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
872                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
873                    offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
874             size_t rowBytes = mipLevel.fPixmap.rowBytes();
875             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
876                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
877                    offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
878 
879             mipLevelPtr += SkAlign8(mipLevel.fPixmap.getSafeSize());
880         }
881     }
882     return size;
883 }
884 
MakeFromDeferredTextureImageData(GrContext * context,const void * data,SkBudgeted budgeted)885 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
886                                                          SkBudgeted budgeted) {
887     if (!data) {
888         return nullptr;
889     }
890     const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
891 
892     if (!context || context->uniqueID() != dti->fContextUniqueID || context->abandoned()) {
893         return nullptr;
894     }
895     int mipLevelCount = dti->fMipMapLevelCount;
896     SkASSERT(mipLevelCount >= 1);
897     sk_sp<SkColorSpace> colorSpace;
898     if (dti->fColorSpaceSize) {
899         colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
900     }
901     SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
902                                          dti->fColorType, dti->fAlphaType, colorSpace);
903     if (mipLevelCount == 1) {
904         SkPixmap pixmap;
905         pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
906 
907         // Pass nullptr for the |dstColorSpace|.  This opts in to more lenient color space
908         // verification.  This is ok because we've already verified the color space in
909         // getDeferredTextureImageData().
910         sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy(
911                 context->resourceProvider(), pixmap, budgeted, nullptr));
912         if (!proxy) {
913             return nullptr;
914         }
915         return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
916                                        std::move(proxy), std::move(colorSpace), budgeted);
917     } else {
918         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
919         for (int i = 0; i < mipLevelCount; i++) {
920             texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
921             texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
922         }
923 
924         return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
925                                               mipLevelCount, SkBudgeted::kYes,
926                                               dti->fColorMode);
927     }
928 }
929 
930 ///////////////////////////////////////////////////////////////////////////////////////////////////
931 
MakeTextureFromMipMap(GrContext * ctx,const SkImageInfo & info,const GrMipLevel texels[],int mipLevelCount,SkBudgeted budgeted,SkDestinationSurfaceColorMode colorMode)932 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
933                                               const GrMipLevel texels[], int mipLevelCount,
934                                               SkBudgeted budgeted,
935                                               SkDestinationSurfaceColorMode colorMode) {
936     SkASSERT(mipLevelCount >= 1);
937     if (!ctx) {
938         return nullptr;
939     }
940     sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount,
941                                                              colorMode));
942     if (!proxy) {
943         return nullptr;
944     }
945 
946     SkASSERT(proxy->priv().isExact());
947     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
948                                    info.alphaType(), std::move(proxy),
949                                    info.refColorSpace(), budgeted);
950 }
951 
onMakeColorSpace(sk_sp<SkColorSpace> target,SkColorType,SkTransferFunctionBehavior premulBehavior) const952 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType,
953                                              SkTransferFunctionBehavior premulBehavior) const {
954     if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
955         // TODO: Implement this.
956         return nullptr;
957     }
958 
959     sk_sp<SkColorSpace> srcSpace = fColorSpace;
960     if (!fColorSpace) {
961         if (target->isSRGB()) {
962             return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
963         }
964 
965         srcSpace = SkColorSpace::MakeSRGB();
966     }
967 
968     auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get());
969     if (!xform) {
970         return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
971     }
972 
973     sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext(
974         SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
975     if (!renderTargetContext) {
976         return nullptr;
977     }
978 
979     GrPaint paint;
980     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
981     paint.addColorTextureProcessor(fProxy, nullptr, SkMatrix::I());
982     paint.addColorFragmentProcessor(std::move(xform));
983 
984     const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
985 
986     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
987 
988     if (!renderTargetContext->asTextureProxy()) {
989         return nullptr;
990     }
991 
992     // MDB: this call is okay bc we know 'renderTargetContext' was exact
993     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
994                                    fAlphaType, renderTargetContext->asTextureProxyRef(),
995                                    std::move(target), fBudgeted);
996 
997 }
998 
onIsValid(GrContext * context) const999 bool SkImage_Gpu::onIsValid(GrContext* context) const {
1000     // The base class has already checked that context isn't abandoned (if it's not nullptr)
1001     if (fContext->abandoned()) {
1002         return false;
1003     }
1004 
1005     if (context && context != fContext) {
1006         return false;
1007     }
1008 
1009     return true;
1010 }
1011