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 "GrCaps.h"
9 #include "GrContext.h"
10 #include "GrDrawContext.h"
11 #include "GrImageIDTextureAdjuster.h"
12 #include "effects/GrYUVEffect.h"
13 #include "SkCanvas.h"
14 #include "SkBitmapCache.h"
15 #include "SkGpuDevice.h"
16 #include "SkGrPixelRef.h"
17 #include "SkGrPriv.h"
18 #include "SkImageFilter.h"
19 #include "SkImage_Gpu.h"
20 #include "SkPixelRef.h"
21 
SkImage_Gpu(int w,int h,uint32_t uniqueID,SkAlphaType at,GrTexture * tex,SkBudgeted budgeted)22 SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
23                          SkBudgeted budgeted)
24     : INHERITED(w, h, uniqueID)
25     , fTexture(SkRef(tex))
26     , fAlphaType(at)
27     , fBudgeted(budgeted)
28     , fAddedRasterVersionToCache(false)
29 {
30     SkASSERT(tex->width() == w);
31     SkASSERT(tex->height() == h);
32 }
33 
~SkImage_Gpu()34 SkImage_Gpu::~SkImage_Gpu() {
35     if (fAddedRasterVersionToCache.load()) {
36         SkNotifyBitmapGenIDIsStale(this->uniqueID());
37     }
38 }
39 
SkTextureImageApplyBudgetedDecision(SkImage * image)40 extern void SkTextureImageApplyBudgetedDecision(SkImage* image) {
41     if (as_IB(image)->getTexture()) {
42         ((SkImage_Gpu*)image)->applyBudgetDecision();
43     }
44 }
45 
make_info(int w,int h,bool isOpaque)46 static SkImageInfo make_info(int w, int h, bool isOpaque) {
47     return SkImageInfo::MakeN32(w, h, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
48 }
49 
getROPixels(SkBitmap * dst,CachingHint chint) const50 bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
51     if (SkBitmapCache::Find(this->uniqueID(), dst)) {
52         SkASSERT(dst->getGenerationID() == this->uniqueID());
53         SkASSERT(dst->isImmutable());
54         SkASSERT(dst->getPixels());
55         return true;
56     }
57 
58     if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->isOpaque()))) {
59         return false;
60     }
61     if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
62                               dst->getPixels(), dst->rowBytes())) {
63         return false;
64     }
65 
66     dst->pixelRef()->setImmutableWithID(this->uniqueID());
67     if (kAllow_CachingHint == chint) {
68         SkBitmapCache::Add(this->uniqueID(), *dst);
69         fAddedRasterVersionToCache.store(true);
70     }
71     return true;
72 }
73 
asBitmapForImageFilters(SkBitmap * bitmap) const74 bool SkImage_Gpu::asBitmapForImageFilters(SkBitmap* bitmap) const {
75     bitmap->setInfo(make_info(this->width(), this->height(), this->isOpaque()));
76     bitmap->setPixelRef(new SkGrPixelRef(bitmap->info(), fTexture))->unref();
77     bitmap->pixelRef()->setImmutableWithID(this->uniqueID());
78     return true;
79 }
80 
asTextureRef(GrContext * ctx,const GrTextureParams & params) const81 GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
82     return GrImageTextureAdjuster(as_IB(this)).refTextureSafeForParams(params, nullptr);
83 }
84 
isOpaque() const85 bool SkImage_Gpu::isOpaque() const {
86     return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
87 }
88 
apply_premul(const SkImageInfo & info,void * pixels,size_t rowBytes)89 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
90     switch (info.colorType()) {
91         case kRGBA_8888_SkColorType:
92         case kBGRA_8888_SkColorType:
93             break;
94         default:
95             return; // nothing to do
96     }
97 
98     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
99     // and in either case, the alpha-byte is always in the same place, so we can safely call
100     // SkPreMultiplyColor()
101     //
102     SkColor* row = (SkColor*)pixels;
103     for (int y = 0; y < info.height(); ++y) {
104         for (int x = 0; x < info.width(); ++x) {
105             row[x] = SkPreMultiplyColor(row[x]);
106         }
107     }
108 }
109 
onReadPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,int srcX,int srcY,CachingHint) const110 bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
111                                int srcX, int srcY, CachingHint) const {
112     GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(),
113                                                      info.profileType());
114     uint32_t flags = 0;
115     if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) {
116         // let the GPU perform this transformation for us
117         flags = GrContext::kUnpremul_PixelOpsFlag;
118     }
119     if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config,
120                               pixels, rowBytes, flags)) {
121         return false;
122     }
123     // do we have to manually fix-up the alpha channel?
124     //      src         dst
125     //      unpremul    premul      fix manually
126     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
127     // all other combos need to change.
128     //
129     // Should this be handled by Ganesh? todo:?
130     //
131     if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
132         apply_premul(info, pixels, rowBytes);
133     }
134     return true;
135 }
136 
onNewSubset(const SkIRect & subset) const137 SkImage* SkImage_Gpu::onNewSubset(const SkIRect& subset) const {
138     GrContext* ctx = fTexture->getContext();
139     GrSurfaceDesc desc = fTexture->desc();
140     desc.fWidth = subset.width();
141     desc.fHeight = subset.height();
142 
143     GrTexture* subTx = ctx->textureProvider()->createTexture(desc, fBudgeted);
144     if (!subTx) {
145         return nullptr;
146     }
147     ctx->copySurface(subTx, fTexture, subset, SkIPoint::Make(0, 0));
148     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, fAlphaType, subTx,
149                            fBudgeted);
150 }
151 
152 ///////////////////////////////////////////////////////////////////////////////////////////////////
153 
new_wrapped_texture_common(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,GrWrapOwnership ownership,SkImage::TextureReleaseProc releaseProc,SkImage::ReleaseContext releaseCtx)154 static SkImage* new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc,
155                                            SkAlphaType at, GrWrapOwnership ownership,
156                                            SkImage::TextureReleaseProc releaseProc,
157                                            SkImage::ReleaseContext releaseCtx) {
158     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
159         return nullptr;
160     }
161     SkAutoTUnref<GrTexture> tex(ctx->textureProvider()->wrapBackendTexture(desc, ownership));
162     if (!tex) {
163         return nullptr;
164     }
165     if (releaseProc) {
166         tex->setRelease(releaseProc, releaseCtx);
167     }
168 
169     const SkBudgeted budgeted = SkBudgeted::kNo;
170     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, at, tex, budgeted);
171 }
172 
NewFromTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at,TextureReleaseProc releaseP,ReleaseContext releaseC)173 SkImage* SkImage::NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, SkAlphaType at,
174                                  TextureReleaseProc releaseP, ReleaseContext releaseC) {
175     return new_wrapped_texture_common(ctx, desc, at, kBorrow_GrWrapOwnership, releaseP, releaseC);
176 }
177 
NewFromAdoptedTexture(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at)178 SkImage* SkImage::NewFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
179                                         SkAlphaType at) {
180     return new_wrapped_texture_common(ctx, desc, at, kAdopt_GrWrapOwnership, nullptr, nullptr);
181 }
182 
NewFromTextureCopy(GrContext * ctx,const GrBackendTextureDesc & desc,SkAlphaType at)183 SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& desc,
184                                      SkAlphaType at) {
185     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
186         return nullptr;
187     }
188 
189     SkAutoTUnref<GrTexture> src(ctx->textureProvider()->wrapBackendTexture(
190         desc, kBorrow_GrWrapOwnership));
191     if (!src) {
192         return nullptr;
193     }
194 
195     SkAutoTUnref<GrTexture> dst(GrDeepCopyTexture(src, SkBudgeted::kYes));
196     if (!dst) {
197         return nullptr;
198     }
199 
200     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, at, dst,
201                            SkBudgeted::kYes);
202 }
203 
NewFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace colorSpace,const GrBackendObject yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin)204 SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace,
205                                          const GrBackendObject yuvTextureHandles[3],
206                                          const SkISize yuvSizes[3],
207                                          GrSurfaceOrigin origin) {
208     const SkBudgeted budgeted = SkBudgeted::kYes;
209 
210     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 ||
211         yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0 ||
212         yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0) {
213         return nullptr;
214     }
215     static const GrPixelConfig kConfig = kAlpha_8_GrPixelConfig;
216     GrBackendTextureDesc yDesc;
217     yDesc.fConfig = kConfig;
218     yDesc.fOrigin = origin;
219     yDesc.fSampleCnt = 0;
220     yDesc.fTextureHandle = yuvTextureHandles[0];
221     yDesc.fWidth = yuvSizes[0].fWidth;
222     yDesc.fHeight = yuvSizes[0].fHeight;
223 
224     GrBackendTextureDesc uDesc;
225     uDesc.fConfig = kConfig;
226     uDesc.fOrigin = origin;
227     uDesc.fSampleCnt = 0;
228     uDesc.fTextureHandle = yuvTextureHandles[1];
229     uDesc.fWidth = yuvSizes[1].fWidth;
230     uDesc.fHeight = yuvSizes[1].fHeight;
231 
232     GrBackendTextureDesc vDesc;
233     vDesc.fConfig = kConfig;
234     vDesc.fOrigin = origin;
235     vDesc.fSampleCnt = 0;
236     vDesc.fTextureHandle = yuvTextureHandles[2];
237     vDesc.fWidth = yuvSizes[2].fWidth;
238     vDesc.fHeight = yuvSizes[2].fHeight;
239 
240     SkAutoTUnref<GrTexture> yTex(ctx->textureProvider()->wrapBackendTexture(
241         yDesc, kBorrow_GrWrapOwnership));
242     SkAutoTUnref<GrTexture> uTex(ctx->textureProvider()->wrapBackendTexture(
243         uDesc, kBorrow_GrWrapOwnership));
244     SkAutoTUnref<GrTexture> vTex(ctx->textureProvider()->wrapBackendTexture(
245         vDesc, kBorrow_GrWrapOwnership));
246     if (!yTex || !uTex || !vTex) {
247         return nullptr;
248     }
249 
250     GrSurfaceDesc dstDesc;
251     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
252     dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
253     dstDesc.fOrigin = origin;
254     dstDesc.fWidth = yuvSizes[0].fWidth;
255     dstDesc.fHeight = yuvSizes[0].fHeight;
256     dstDesc.fConfig = kRGBA_8888_GrPixelConfig;
257     dstDesc.fSampleCnt = 0;
258 
259     SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(dstDesc, SkBudgeted::kYes));
260     if (!dst) {
261         return nullptr;
262     }
263 
264     GrPaint paint;
265     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
266     paint.addColorFragmentProcessor(GrYUVEffect::CreateYUVToRGB(yTex, uTex, vTex, yuvSizes,
267                                                                 colorSpace))->unref();
268 
269     const SkRect rect = SkRect::MakeWH(SkIntToScalar(dstDesc.fWidth),
270                                        SkIntToScalar(dstDesc.fHeight));
271     SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(dst->asRenderTarget()));
272     if (!drawContext) {
273         return nullptr;
274     }
275 
276     drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect);
277     ctx->flushSurfaceWrites(dst);
278     return new SkImage_Gpu(dstDesc.fWidth, dstDesc.fHeight, kNeedNewImageUniqueID,
279                            kOpaque_SkAlphaType, dst, budgeted);
280 }
281 
create_image_from_maker(GrTextureMaker * maker,SkAlphaType at,uint32_t id)282 static SkImage* create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) {
283     SkAutoTUnref<GrTexture> texture(maker->refTextureForParams(GrTextureParams::ClampNoFilter()));
284     if (!texture) {
285         return nullptr;
286     }
287     return new SkImage_Gpu(texture->width(), texture->height(), id, at, texture,
288                            SkBudgeted::kNo);
289 }
290 
newTextureImage(GrContext * context) const291 SkImage* SkImage::newTextureImage(GrContext *context) const {
292     if (!context) {
293         return nullptr;
294     }
295     if (GrTexture* peek = as_IB(this)->peekTexture()) {
296         return peek->getContext() == context ? SkRef(const_cast<SkImage*>(this)) : nullptr;
297     }
298     // No way to check whether a image is premul or not?
299     SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
300 
301     if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
302         GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
303         return create_image_from_maker(&maker, at, this->uniqueID());
304     }
305     SkBitmap bmp;
306     if (!this->asLegacyBitmap(&bmp, kRO_LegacyBitmapMode)) {
307         return nullptr;
308     }
309     GrBitmapTextureMaker maker(context, bmp);
310     return create_image_from_maker(&maker, at, this->uniqueID());
311 }
312 
313 ///////////////////////////////////////////////////////////////////////////////////////////////////
314 
GrDeepCopyTexture(GrTexture * src,SkBudgeted budgeted)315 GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted budgeted) {
316     GrContext* ctx = src->getContext();
317 
318     GrSurfaceDesc desc = src->desc();
319     GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, nullptr, 0);
320     if (!dst) {
321         return nullptr;
322     }
323 
324     const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
325     const SkIPoint dstP = SkIPoint::Make(0, 0);
326     ctx->copySurface(dst, src, srcR, dstP);
327     ctx->flushSurfaceWrites(dst);
328     return dst;
329 }
330 
331