• 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 "GrBitmapTextureMaker.h"
14 #include "GrCaps.h"
15 #include "GrContext.h"
16 #include "GrContextPriv.h"
17 #include "GrGpu.h"
18 #include "GrImageTextureMaker.h"
19 #include "GrRenderTargetContext.h"
20 #include "GrResourceProvider.h"
21 #include "GrSemaphore.h"
22 #include "GrTextureAdjuster.h"
23 #include "GrTexturePriv.h"
24 #include "GrTextureProxy.h"
25 #include "GrTextureToYUVPlanes.h"
26 #include "effects/GrNonlinearColorSpaceXformEffect.h"
27 #include "effects/GrYUVEffect.h"
28 #include "SkCanvas.h"
29 #include "SkCrossContextImageData.h"
30 #include "SkBitmapCache.h"
31 #include "SkGr.h"
32 #include "SkImage_Gpu.h"
33 #include "SkImageCacherator.h"
34 #include "SkImageInfoPriv.h"
35 #include "SkMipMap.h"
36 #include "SkPixelRef.h"
37 #include "SkReadPixelsRec.h"
38 
SkImage_Gpu(GrContext * context,uint32_t uniqueID,SkAlphaType at,sk_sp<GrTextureProxy> proxy,sk_sp<SkColorSpace> colorSpace,SkBudgeted budgeted)39 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
40                          sk_sp<GrTextureProxy> proxy,
41                          sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
42     : INHERITED(proxy->width(), proxy->height(), uniqueID)
43     , fContext(context)
44     , fProxy(std::move(proxy))
45     , fAlphaType(at)
46     , fBudgeted(budgeted)
47     , fColorSpace(std::move(colorSpace))
48     , fAddedRasterVersionToCache(false) {
49 }
50 
~SkImage_Gpu()51 SkImage_Gpu::~SkImage_Gpu() {
52     if (fAddedRasterVersionToCache.load()) {
53         SkNotifyBitmapGenIDIsStale(this->uniqueID());
54     }
55 }
56 
onImageInfo() const57 SkImageInfo SkImage_Gpu::onImageInfo() const {
58     SkColorType ct;
59     if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
60         ct = kUnknown_SkColorType;
61     }
62     return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
63 }
64 
make_info(int w,int h,SkAlphaType at,sk_sp<SkColorSpace> colorSpace)65 static SkImageInfo make_info(int w, int h, SkAlphaType at, sk_sp<SkColorSpace> colorSpace) {
66     return SkImageInfo::MakeN32(w, h, at, std::move(colorSpace));
67 }
68 
getROPixels(SkBitmap * dst,SkColorSpace * dstColorSpace,CachingHint chint) const69 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint chint) const {
70     const auto desc = SkBitmapCacheDesc::Make(this);
71     if (SkBitmapCache::Find(desc, dst)) {
72         SkASSERT(dst->getGenerationID() == this->uniqueID());
73         SkASSERT(dst->isImmutable());
74         SkASSERT(dst->getPixels());
75         return true;
76     }
77 
78     SkImageInfo ii = make_info(this->width(), this->height(), this->alphaType(),
79                                sk_ref_sp(dstColorSpace));
80     if (!dst->tryAllocPixels(ii)) {
81         return false;
82     }
83 
84     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
85                                                                                     fProxy,
86                                                                                     fColorSpace);
87     if (!sContext) {
88         return false;
89     }
90 
91     if (!sContext->readPixels(dst->info(), dst->getPixels(), dst->rowBytes(), 0, 0)) {
92         return false;
93     }
94 
95     dst->pixelRef()->setImmutableWithID(this->uniqueID());
96     if (kAllow_CachingHint == chint) {
97         SkBitmapCache::Add(desc, *dst);
98         fAddedRasterVersionToCache.store(true);
99     }
100     return true;
101 }
102 
asTextureProxyRef(GrContext * context,const GrSamplerParams & params,SkColorSpace * dstColorSpace,sk_sp<SkColorSpace> * texColorSpace,SkScalar scaleAdjust[2]) const103 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
104                                                      const GrSamplerParams& params,
105                                                      SkColorSpace* dstColorSpace,
106                                                      sk_sp<SkColorSpace>* texColorSpace,
107                                                      SkScalar scaleAdjust[2]) const {
108     if (context != fContext) {
109         SkASSERT(0);
110         return nullptr;
111     }
112 
113     if (texColorSpace) {
114         *texColorSpace = this->fColorSpace;
115     }
116 
117     GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(),
118                                this->uniqueID(), this->fColorSpace.get());
119     return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
120 }
121 
apply_premul(const SkImageInfo & info,void * pixels,size_t rowBytes)122 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
123     switch (info.colorType()) {
124         case kRGBA_8888_SkColorType:
125         case kBGRA_8888_SkColorType:
126             break;
127         default:
128             return; // nothing to do
129     }
130 
131     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
132     // and in either case, the alpha-byte is always in the same place, so we can safely call
133     // SkPreMultiplyColor()
134     //
135     SkColor* row = (SkColor*)pixels;
136     for (int y = 0; y < info.height(); ++y) {
137         for (int x = 0; x < info.width(); ++x) {
138             row[x] = SkPreMultiplyColor(row[x]);
139         }
140     }
141 }
142 
onGetTextureHandle(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const143 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
144                                                 GrSurfaceOrigin* origin) const {
145     GrTextureProxy* proxy = this->peekProxy();
146     SkASSERT(proxy);
147 
148     GrSurface* surface = proxy->instantiate(fContext->resourceProvider());
149     if (surface && surface->asTexture()) {
150         if (flushPendingGrContextIO) {
151             fContext->prepareSurfaceForExternalIO(surface);
152         }
153         if (origin) {
154             *origin = surface->origin();
155         }
156         return surface->asTexture()->getTextureHandle();
157     }
158     return 0;
159 }
160 
onGetTexture() const161 GrTexture* SkImage_Gpu::onGetTexture() const {
162     GrTextureProxy* proxy = this->peekProxy();
163     if (!proxy) {
164         return nullptr;
165     }
166 
167     return proxy->instantiate(fContext->resourceProvider());
168 }
169 
onReadYUV8Planes(const SkISize sizes[3],void * const planes[3],const size_t rowBytes[3],SkYUVColorSpace colorSpace) const170 bool SkImage_Gpu::onReadYUV8Planes(const SkISize sizes[3], void* const planes[3],
171                                    const size_t rowBytes[3], SkYUVColorSpace colorSpace) const {
172     if (GrTextureToYUVPlanes(fContext, fProxy, sizes, planes, rowBytes, colorSpace)) {
173         return true;
174     }
175 
176     return INHERITED::onReadYUV8Planes(sizes, planes, rowBytes, colorSpace);
177 }
178 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,int srcX,int srcY,CachingHint) const179 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
180                                int srcX, int srcY, CachingHint) const {
181     if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
182         return false;
183     }
184 
185     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
186     if (!rec.trim(this->width(), this->height())) {
187         return false;
188     }
189 
190     // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
191     // GrRenderTargetContext::onReadPixels
192     uint32_t flags = 0;
193     if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
194         // let the GPU perform this transformation for us
195         flags = GrContext::kUnpremul_PixelOpsFlag;
196     }
197 
198     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
199                                                                                     fProxy,
200                                                                                     fColorSpace);
201     if (!sContext) {
202         return false;
203     }
204 
205     if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
206         return false;
207     }
208 
209     // do we have to manually fix-up the alpha channel?
210     //      src         dst
211     //      unpremul    premul      fix manually
212     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
213     // all other combos need to change.
214     //
215     // Should this be handled by Ganesh? todo:?
216     //
217     if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
218         apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
219     }
220     return true;
221 }
222 
onMakeSubset(const SkIRect & subset) const223 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
224     GrSurfaceDesc desc = fProxy->desc();
225     desc.fWidth = subset.width();
226     desc.fHeight = subset.height();
227 
228     sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
229                                                                         desc,
230                                                                         SkBackingFit::kExact,
231                                                                         fBudgeted));
232     if (!sContext) {
233         return nullptr;
234     }
235 
236     if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
237         return nullptr;
238     }
239 
240     // MDB: this call is okay bc we know 'sContext' was kExact
241     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
242                                    fAlphaType, sContext->asTextureProxyRef(),
243                                    fColorSpace, fBudgeted);
244 }
245 
246 ///////////////////////////////////////////////////////////////////////////////////////////////////
247 
new_wrapped_texture_common(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,GrWrapOwnership ownership,SkImage::TextureReleaseProc releaseProc,SkImage::ReleaseContext releaseCtx)248 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc,
249                                                  SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
250                                                  GrWrapOwnership ownership,
251                                                  SkImage::TextureReleaseProc releaseProc,
252                                                  SkImage::ReleaseContext releaseCtx) {
253     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
254         return nullptr;
255     }
256 
257     sk_sp<GrTexture> tex = ctx->resourceProvider()->wrapBackendTexture(desc, ownership);
258     if (!tex) {
259         return nullptr;
260     }
261     if (releaseProc) {
262         tex->setRelease(releaseProc, releaseCtx);
263     }
264 
265     const SkBudgeted budgeted = (kAdoptAndCache_GrWrapOwnership == ownership)
266             ? SkBudgeted::kYes : SkBudgeted::kNo;
267     sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
268     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
269                                    at, std::move(proxy), std::move(colorSpace), budgeted);
270 }
271 
MakeFromTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)272 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
273                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
274                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
275     return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kBorrow_GrWrapOwnership,
276                                       releaseP, releaseC);
277 }
278 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,sk_sp<SkColorSpace> cs)279 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
280                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
281     return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kAdopt_GrWrapOwnership,
282                                       nullptr, nullptr);
283 }
284 
make_from_yuv_textures_copy(GrContext * ctx,SkYUVColorSpace colorSpace,bool nv12,const GrBackendObject yuvTextureHandles[],const SkISize yuvSizes[],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)285 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
286                                                   bool nv12,
287                                                   const GrBackendObject yuvTextureHandles[],
288                                                   const SkISize yuvSizes[],
289                                                   GrSurfaceOrigin origin,
290                                                   sk_sp<SkColorSpace> imageColorSpace) {
291     const SkBudgeted budgeted = SkBudgeted::kYes;
292 
293     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 ||
294         yuvSizes[1].fHeight <= 0) {
295         return nullptr;
296     }
297     if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
298         return nullptr;
299     }
300 
301     const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
302 
303     GrBackendTextureDesc yDesc;
304     yDesc.fConfig = kConfig;
305     yDesc.fOrigin = origin;
306     yDesc.fSampleCnt = 0;
307     yDesc.fTextureHandle = yuvTextureHandles[0];
308     yDesc.fWidth = yuvSizes[0].fWidth;
309     yDesc.fHeight = yuvSizes[0].fHeight;
310 
311     GrBackendTextureDesc uDesc;
312     uDesc.fConfig = kConfig;
313     uDesc.fOrigin = origin;
314     uDesc.fSampleCnt = 0;
315     uDesc.fTextureHandle = yuvTextureHandles[1];
316     uDesc.fWidth = yuvSizes[1].fWidth;
317     uDesc.fHeight = yuvSizes[1].fHeight;
318 
319     sk_sp<GrSurfaceProxy> yProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, yDesc);
320     sk_sp<GrSurfaceProxy> uProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, uDesc);
321     sk_sp<GrSurfaceProxy> vProxy;
322 
323     if (nv12) {
324         vProxy = uProxy;
325     } else {
326         GrBackendTextureDesc vDesc;
327         vDesc.fConfig = kConfig;
328         vDesc.fOrigin = origin;
329         vDesc.fSampleCnt = 0;
330         vDesc.fTextureHandle = yuvTextureHandles[2];
331         vDesc.fWidth = yuvSizes[2].fWidth;
332         vDesc.fHeight = yuvSizes[2].fHeight;
333 
334         vProxy = GrSurfaceProxy::MakeWrappedBackend(ctx, vDesc);
335     }
336     if (!yProxy || !uProxy || !vProxy) {
337         return nullptr;
338     }
339 
340     const int width = yuvSizes[0].fWidth;
341     const int height = yuvSizes[0].fHeight;
342 
343     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
344     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeRenderTargetContext(
345                                                                          SkBackingFit::kExact,
346                                                                          width, height,
347                                                                          kRGBA_8888_GrPixelConfig,
348                                                                          std::move(imageColorSpace),
349                                                                          0,
350                                                                          origin));
351     if (!renderTargetContext) {
352         return nullptr;
353     }
354 
355     GrPaint paint;
356     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
357     paint.addColorFragmentProcessor(
358         GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(),
359                                   sk_ref_sp(yProxy->asTextureProxy()),
360                                   sk_ref_sp(uProxy->asTextureProxy()),
361                                   sk_ref_sp(vProxy->asTextureProxy()), yuvSizes, colorSpace, nv12));
362 
363     const SkRect rect = SkRect::MakeIWH(width, height);
364 
365     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
366 
367     if (!renderTargetContext->accessRenderTarget()) {
368         return nullptr;
369     }
370     ctx->flushSurfaceWrites(renderTargetContext->accessRenderTarget());
371 
372     // MDB: this call is okay bc we know 'renderTargetContext' was exact
373     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
374                                    kOpaque_SkAlphaType, renderTargetContext->asTextureProxyRef(),
375                                    renderTargetContext->refColorSpace(), budgeted);
376 }
377 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace colorSpace,const GrBackendObject yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)378 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
379                                                 const GrBackendObject yuvTextureHandles[3],
380                                                 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
381                                                 sk_sp<SkColorSpace> imageColorSpace) {
382     return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
383                                        std::move(imageColorSpace));
384 }
385 
MakeFromNV12TexturesCopy(GrContext * ctx,SkYUVColorSpace colorSpace,const GrBackendObject yuvTextureHandles[2],const SkISize yuvSizes[2],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)386 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
387                                                  const GrBackendObject yuvTextureHandles[2],
388                                                  const SkISize yuvSizes[2],
389                                                  GrSurfaceOrigin origin,
390                                                  sk_sp<SkColorSpace> imageColorSpace) {
391     return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
392                                        std::move(imageColorSpace));
393 }
394 
create_image_from_maker(GrContext * context,GrTextureMaker * maker,SkAlphaType at,uint32_t id,SkColorSpace * dstColorSpace)395 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
396                                               SkAlphaType at, uint32_t id,
397                                               SkColorSpace* dstColorSpace) {
398     sk_sp<SkColorSpace> texColorSpace;
399     sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
400                                                                 dstColorSpace,
401                                                                 &texColorSpace, nullptr));
402     if (!proxy) {
403         return nullptr;
404     }
405     return sk_make_sp<SkImage_Gpu>(context, id, at,
406                                    std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
407 }
408 
makeTextureImage(GrContext * context,SkColorSpace * dstColorSpace) const409 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
410     if (!context) {
411         return nullptr;
412     }
413     if (GrTexture* peek = as_IB(this)->peekTexture()) {
414         return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
415     }
416 
417     if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
418         GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
419         return create_image_from_maker(context, &maker, this->alphaType(),
420                                        this->uniqueID(), dstColorSpace);
421     }
422 
423     if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
424         GrBitmapTextureMaker maker(context, *bmp);
425         return create_image_from_maker(context, &maker, this->alphaType(),
426                                        this->uniqueID(), dstColorSpace);
427     }
428     return nullptr;
429 }
430 
MakeFromEncoded(GrContext * context,sk_sp<SkData> encoded,SkColorSpace * dstColorSpace)431 std::unique_ptr<SkCrossContextImageData> SkCrossContextImageData::MakeFromEncoded(
432         GrContext* context, sk_sp<SkData> encoded, SkColorSpace* dstColorSpace) {
433     sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
434     if (!codecImage) {
435         return nullptr;
436     }
437 
438     // Some backends or drivers don't support (safely) moving resources between contexts
439     if (!context->caps()->crossContextTextureSupport()) {
440         return std::unique_ptr<SkCrossContextImageData>(
441             new SkCrossContextImageData(std::move(codecImage)));
442     }
443 
444     sk_sp<SkImage> textureImage = codecImage->makeTextureImage(context, dstColorSpace);
445     if (!textureImage) {
446         // TODO: Force decode to raster here? Do mip-mapping, like getDeferredTextureImageData?
447         return std::unique_ptr<SkCrossContextImageData>(
448             new SkCrossContextImageData(std::move(codecImage)));
449     }
450 
451     // Crack open the gpu image, extract the backend data, stick it in the SkCCID
452     GrTexture* texture = as_IB(textureImage)->peekTexture();
453     SkASSERT(texture);
454 
455     GrBackendTextureDesc desc;
456     desc.fFlags = kNone_GrBackendTextureFlag;
457     desc.fOrigin = texture->origin();
458     desc.fWidth = texture->width();
459     desc.fHeight = texture->height();
460     desc.fConfig = texture->config();
461     desc.fSampleCnt = 0;
462 
463     auto textureData = texture->texturePriv().detachBackendTexture();
464     SkASSERT(textureData);
465 
466     SkImageInfo info = as_IB(textureImage)->onImageInfo();
467     return std::unique_ptr<SkCrossContextImageData>(new SkCrossContextImageData(
468         desc, std::move(textureData), info.alphaType(), info.refColorSpace()));
469 }
470 
MakeFromCrossContextImageData(GrContext * context,std::unique_ptr<SkCrossContextImageData> ccid)471 sk_sp<SkImage> SkImage::MakeFromCrossContextImageData(
472         GrContext* context, std::unique_ptr<SkCrossContextImageData> ccid) {
473     if (ccid->fImage) {
474         // No pre-existing GPU resource. We could upload it now (with makeTextureImage),
475         // but we'd need a dstColorSpace.
476         return ccid->fImage;
477     }
478 
479     if (ccid->fTextureData) {
480         ccid->fTextureData->attachToContext(context);
481     }
482 
483     // This texture was created by Ganesh on another thread (see MakeFromEncoded, above).
484     // Thus, we can import it back into our cache and treat it as our own (again).
485     GrWrapOwnership ownership = kAdoptAndCache_GrWrapOwnership;
486     return new_wrapped_texture_common(context, ccid->fDesc, ccid->fAlphaType,
487                                       std::move(ccid->fColorSpace), ownership, nullptr, nullptr);
488 }
489 
makeNonTextureImage() const490 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
491     if (!this->isTextureBacked()) {
492         return sk_ref_sp(const_cast<SkImage*>(this));
493     }
494     SkImageInfo info = as_IB(this)->onImageInfo();
495     size_t rowBytes = info.minRowBytes();
496     size_t size = info.getSafeSize(rowBytes);
497     auto data = SkData::MakeUninitialized(size);
498     if (!data) {
499         return nullptr;
500     }
501     SkPixmap pm(info, data->writable_data(), rowBytes);
502     if (!this->readPixels(pm, 0, 0, kDisallow_CachingHint)) {
503         return nullptr;
504     }
505     return MakeRasterData(info, data, rowBytes);
506 }
507 
508 ///////////////////////////////////////////////////////////////////////////////////////////////////
509 
510 namespace {
511 struct MipMapLevelData {
512     void* fPixelData;
513     size_t fRowBytes;
514 };
515 
516 struct DeferredTextureImage {
517     uint32_t                      fContextUniqueID;
518     // Right now, the destination color mode is only considered when generating mipmaps
519     SkDestinationSurfaceColorMode fColorMode;
520     // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
521     int                           fWidth;
522     int                           fHeight;
523     SkColorType                   fColorType;
524     SkAlphaType                   fAlphaType;
525     void*                         fColorSpace;
526     size_t                        fColorSpaceSize;
527     int                           fMipMapLevelCount;
528     // The fMipMapLevelData array may contain more than 1 element.
529     // It contains fMipMapLevelCount elements.
530     // That means this struct's size is not known at compile-time.
531     MipMapLevelData               fMipMapLevelData[1];
532 };
533 }  // anonymous namespace
534 
should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param)535 static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
536     // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
537     // This can cause runaway memory leaks, so we are disabling this path until we can
538     // investigate further. crbug.com/669775
539     return false;
540 }
541 
542 namespace {
543 
544 class DTIBufferFiller
545 {
546 public:
DTIBufferFiller(char * bufferAsCharPtr)547     explicit DTIBufferFiller(char* bufferAsCharPtr)
548         : bufferAsCharPtr_(bufferAsCharPtr) {}
549 
fillMember(const void * source,size_t memberOffset,size_t size)550     void fillMember(const void* source, size_t memberOffset, size_t size) {
551         memcpy(bufferAsCharPtr_ + memberOffset, source, size);
552     }
553 
554 private:
555 
556     char* bufferAsCharPtr_;
557 };
558 }
559 
560 #define FILL_MEMBER(bufferFiller, member, source) \
561     bufferFiller.fillMember(source, \
562                offsetof(DeferredTextureImage, member), \
563                sizeof(DeferredTextureImage::member));
564 
getDeferredTextureImageData(const GrContextThreadSafeProxy & proxy,const DeferredTextureImageUsageParams params[],int paramCnt,void * buffer,SkColorSpace * dstColorSpace) const565 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
566                                             const DeferredTextureImageUsageParams params[],
567                                             int paramCnt, void* buffer,
568                                             SkColorSpace* dstColorSpace) const {
569     // Extract relevant min/max values from the params array.
570     int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
571     SkFilterQuality highestFilterQuality = params[0].fQuality;
572     bool useMipMaps = should_use_mip_maps(params[0]);
573     for (int i = 1; i < paramCnt; ++i) {
574         if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
575             lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
576         if (highestFilterQuality < params[i].fQuality)
577             highestFilterQuality = params[i].fQuality;
578         useMipMaps |= should_use_mip_maps(params[i]);
579     }
580 
581     const bool fillMode = SkToBool(buffer);
582     if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
583         return 0;
584     }
585 
586     // Calculate scaling parameters.
587     bool isScaled = lowestPreScaleMipLevel != 0;
588 
589     SkISize scaledSize;
590     if (isScaled) {
591         // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
592         // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
593         scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
594                                                 lowestPreScaleMipLevel - 1);
595     } else {
596         scaledSize = SkISize::Make(this->width(), this->height());
597     }
598 
599     // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
600     SkFilterQuality scaleFilterQuality = highestFilterQuality;
601     if (scaleFilterQuality > kMedium_SkFilterQuality) {
602         scaleFilterQuality = kMedium_SkFilterQuality;
603     }
604 
605     const int maxTextureSize = proxy.fCaps->maxTextureSize();
606     if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
607         return 0;
608     }
609 
610     SkAutoPixmapStorage pixmap;
611     SkImageInfo info;
612     size_t pixelSize = 0;
613     if (!isScaled && this->peekPixels(&pixmap) && !pixmap.ctable()) {
614         info = pixmap.info();
615         pixelSize = SkAlign8(pixmap.getSafeSize());
616     } else {
617         // Here we're just using presence of data to know whether there is a codec behind the image.
618         // In the future we will access the cacherator and get the exact data that we want to (e.g.
619         // yuv planes) upload.
620         sk_sp<SkData> data(this->refEncoded());
621         if (!data && !this->peekPixels(nullptr)) {
622             return 0;
623         }
624         if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
625             // Generator backed image. Tweak info to trigger correct kind of decode.
626             SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
627                 dstColorSpace, proxy.fCaps.get());
628             info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
629                                                               scaledSize.height());
630         } else {
631             info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
632         }
633         if (kIndex_8_SkColorType == info.colorType()) {
634             // Force Index8 to be N32 instead. Index8 is unsupported in Ganesh.
635             info = info.makeColorType(kN32_SkColorType);
636         }
637         pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
638         if (fillMode) {
639             pixmap.alloc(info);
640             if (isScaled) {
641                 if (!this->scalePixels(pixmap, scaleFilterQuality,
642                                        SkImage::kDisallow_CachingHint)) {
643                     return 0;
644                 }
645             } else {
646                 if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
647                     return 0;
648                 }
649             }
650             SkASSERT(!pixmap.ctable());
651         }
652     }
653     int mipMapLevelCount = 1;
654     if (useMipMaps) {
655         // SkMipMap only deals with the mipmap levels it generates, which does
656         // not include the base level.
657         // That means it generates and holds levels 1-x instead of 0-x.
658         // So the total mipmap level count is 1 more than what
659         // SkMipMap::ComputeLevelCount returns.
660         mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
661 
662         // We already initialized pixelSize to the size of the base level.
663         // SkMipMap will generate the extra mipmap levels. Their sizes need to
664         // be added to the total.
665         // Index 0 here does not refer to the base mipmap level -- it is
666         // SkMipMap's first generated mipmap level (level 1).
667         for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
668              currentMipMapLevelIndex--) {
669             SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
670                                                          currentMipMapLevelIndex);
671             SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
672             pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
673         }
674     }
675     size_t size = 0;
676     size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
677     size += dtiSize;
678     size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
679     // We subtract 1 because DeferredTextureImage already includes the base
680     // level in its size
681     size_t pixelOffset = size;
682     size += pixelSize;
683     size_t colorSpaceOffset = 0;
684     size_t colorSpaceSize = 0;
685     if (info.colorSpace()) {
686         colorSpaceOffset = size;
687         colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
688         size += colorSpaceSize;
689     }
690     if (!fillMode) {
691         return size;
692     }
693     char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
694     char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
695     void* pixels = pixelsAsCharPtr;
696 
697     memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
698                                    pixmap.addr(), pixmap.getSafeSize());
699 
700     // If the context has sRGB support, and we're intending to render to a surface with an attached
701     // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
702     // aware mip-mapping.
703     SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
704     if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
705         info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
706         colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
707     }
708 
709     SkASSERT(info == pixmap.info());
710     size_t rowBytes = pixmap.rowBytes();
711     static_assert(std::is_standard_layout<DeferredTextureImage>::value,
712                   "offsetof, which we use below, requires the type have standard layout");
713     auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
714     FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
715     FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
716     int width = info.width();
717     FILL_MEMBER(dtiBufferFiller, fWidth, &width);
718     int height = info.height();
719     FILL_MEMBER(dtiBufferFiller, fHeight, &height);
720     SkColorType colorType = info.colorType();
721     FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
722     SkAlphaType alphaType = info.alphaType();
723     FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
724     FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
725     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
726            &pixels, sizeof(pixels));
727     memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
728            &rowBytes, sizeof(rowBytes));
729     if (colorSpaceSize) {
730         void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
731         FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
732         FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
733         info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
734     } else {
735         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
736                0, sizeof(DeferredTextureImage::fColorSpace));
737         memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
738                0, sizeof(DeferredTextureImage::fColorSpaceSize));
739     }
740 
741     // Fill in the mipmap levels if they exist
742     char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.getSafeSize());
743 
744     if (useMipMaps) {
745         static_assert(std::is_standard_layout<MipMapLevelData>::value,
746                       "offsetof, which we use below, requires the type have a standard layout");
747 
748         std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
749         // SkMipMap holds only the mipmap levels it generates.
750         // A programmer can use the data they provided to SkMipMap::Build as level 0.
751         // So the SkMipMap provides levels 1-x but it stores them in its own
752         // range 0-(x-1).
753         for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
754              generatedMipLevelIndex++) {
755             SkMipMap::Level mipLevel;
756             mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
757 
758             // Make sure the mipmap data is after the start of the buffer
759             SkASSERT(mipLevelPtr > bufferAsCharPtr);
760             // Make sure the mipmap data starts before the end of the buffer
761             SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
762             // Make sure the mipmap data ends before the end of the buffer
763             SkASSERT(mipLevelPtr + mipLevel.fPixmap.getSafeSize() <=
764                      bufferAsCharPtr + pixelOffset + pixelSize);
765 
766             // getSafeSize includes rowbyte padding except for the last row,
767             // right?
768 
769             memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.getSafeSize());
770 
771             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
772                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
773                    offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
774             size_t rowBytes = mipLevel.fPixmap.rowBytes();
775             memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
776                    sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
777                    offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
778 
779             mipLevelPtr += SkAlign8(mipLevel.fPixmap.getSafeSize());
780         }
781     }
782     return size;
783 }
784 
MakeFromDeferredTextureImageData(GrContext * context,const void * data,SkBudgeted budgeted)785 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
786                                                          SkBudgeted budgeted) {
787     if (!data) {
788         return nullptr;
789     }
790     const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
791 
792     if (!context || context->uniqueID() != dti->fContextUniqueID) {
793         return nullptr;
794     }
795     int mipLevelCount = dti->fMipMapLevelCount;
796     SkASSERT(mipLevelCount >= 1);
797     sk_sp<SkColorSpace> colorSpace;
798     if (dti->fColorSpaceSize) {
799         colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
800     }
801     SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
802                                          dti->fColorType, dti->fAlphaType, colorSpace);
803     if (mipLevelCount == 1) {
804         SkPixmap pixmap;
805         pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
806         sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy(context->resourceProvider(),
807                                                                  pixmap, budgeted));
808         if (!proxy) {
809             return nullptr;
810         }
811         return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
812                                        std::move(proxy), std::move(colorSpace), budgeted);
813     } else {
814         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
815         for (int i = 0; i < mipLevelCount; i++) {
816             texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
817             texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
818         }
819 
820         return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
821                                               mipLevelCount, SkBudgeted::kYes,
822                                               dti->fColorMode);
823     }
824 }
825 
826 ///////////////////////////////////////////////////////////////////////////////////////////////////
827 
MakeTextureFromMipMap(GrContext * ctx,const SkImageInfo & info,const GrMipLevel * texels,int mipLevelCount,SkBudgeted budgeted,SkDestinationSurfaceColorMode colorMode)828 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
829                                               const GrMipLevel* texels, int mipLevelCount,
830                                               SkBudgeted budgeted,
831                                               SkDestinationSurfaceColorMode colorMode) {
832     if (!ctx) {
833         return nullptr;
834     }
835     sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount,
836                                                              colorMode));
837     if (!proxy) {
838         return nullptr;
839     }
840 
841     SkASSERT(proxy->priv().isExact());
842     return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
843                                    info.alphaType(), std::move(proxy),
844                                    info.refColorSpace(), budgeted);
845 }
846 
onMakeColorSpace(sk_sp<SkColorSpace> colorSpace) const847 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> colorSpace) const {
848     sk_sp<SkColorSpace> srcSpace = fColorSpace ? fColorSpace : SkColorSpace::MakeSRGB();
849     auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), colorSpace.get());
850     if (!xform) {
851         return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
852     }
853 
854     sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeRenderTargetContext(
855         SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
856     if (!renderTargetContext) {
857         return nullptr;
858     }
859 
860     GrPaint paint;
861     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
862     paint.addColorTextureProcessor(fContext->resourceProvider(), fProxy, nullptr, SkMatrix::I());
863     paint.addColorFragmentProcessor(std::move(xform));
864 
865     const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
866 
867     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
868 
869     if (!renderTargetContext->accessRenderTarget()) {
870         return nullptr;
871     }
872 
873     // MDB: this call is okay bc we know 'renderTargetContext' was exact
874     return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
875                                    fAlphaType, renderTargetContext->asTextureProxyRef(),
876                                    std::move(colorSpace), fBudgeted);
877 
878 }
879