Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / SkGrPixelRef.cpp
1
2 /*
3  * Copyright 2010 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9
10
11 #include "SkGrPixelRef.h"
12
13 #include "GrContext.h"
14 #include "GrTexture.h"
15 #include "SkBitmapCache.h"
16 #include "SkGr.h"
17 #include "SkRect.h"
18
19 // since we call lockPixels recursively on fBitmap, we need a distinct mutex,
20 // to avoid deadlock with the default one provided by SkPixelRef.
21 SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
22
23 SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
24     : INHERITED(info, &gROLockPixelsPixelRefMutex) {}
25
26 SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
27
28 bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
29     fBitmap.reset();
30 //    SkDebugf("---------- calling readpixels in support of lockpixels\n");
31     if (!this->onReadPixels(&fBitmap, NULL)) {
32         SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
33         return false;
34     }
35     fBitmap.lockPixels();
36     if (NULL == fBitmap.getPixels()) {
37         return false;
38     }
39
40     rec->fPixels = fBitmap.getPixels();
41     rec->fColorTable = NULL;
42     rec->fRowBytes = fBitmap.rowBytes();
43     return true;
44 }
45
46 void SkROLockPixelsPixelRef::onUnlockPixels() {
47     fBitmap.unlockPixels();
48 }
49
50 bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
51     return false;
52 }
53
54 ///////////////////////////////////////////////////////////////////////////////
55
56 static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorType dstCT,
57                                            const SkIRect* subset) {
58     if (NULL == texture || kUnknown_SkColorType == dstCT) {
59         return NULL;
60     }
61     GrContext* context = texture->getContext();
62     if (NULL == context) {
63         return NULL;
64     }
65     GrTextureDesc desc;
66
67     SkIPoint pointStorage;
68     SkIPoint* topLeft;
69     if (subset != NULL) {
70         SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
71         // Create a new texture that is the size of subset.
72         desc.fWidth = subset->width();
73         desc.fHeight = subset->height();
74         pointStorage.set(subset->x(), subset->y());
75         topLeft = &pointStorage;
76     } else {
77         desc.fWidth  = texture->width();
78         desc.fHeight = texture->height();
79         topLeft = NULL;
80     }
81     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
82     desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType);
83
84     GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
85     if (NULL == dst) {
86         return NULL;
87     }
88
89     context->copyTexture(texture, dst->asRenderTarget(), topLeft);
90
91     // Blink is relying on the above copy being sent to GL immediately in the case when the source
92     // is a WebGL canvas backing store. We could have a TODO to remove this flush, but we have a
93     // larger TODO to remove SkGrPixelRef entirely.
94     context->flush();
95
96     SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType);
97     SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
98     SkSafeUnref(dst);
99     return pixelRef;
100 }
101
102 ///////////////////////////////////////////////////////////////////////////////
103
104 SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
105                            bool transferCacheLock) : INHERITED(info) {
106     // For surfaces that are both textures and render targets, the texture owns the
107     // render target but not vice versa. So we ref the texture to keep both alive for
108     // the lifetime of this pixel ref.
109     fSurface = SkSafeRef(surface->asTexture());
110     if (NULL == fSurface) {
111         fSurface = SkSafeRef(surface);
112     }
113     fUnlock = transferCacheLock;
114
115     if (fSurface) {
116         SkASSERT(info.width() <= fSurface->width());
117         SkASSERT(info.height() <= fSurface->height());
118     }
119 }
120
121 SkGrPixelRef::~SkGrPixelRef() {
122     if (fUnlock) {
123         GrContext* context = fSurface->getContext();
124         GrTexture* texture = fSurface->asTexture();
125         if (context && texture) {
126             context->unlockScratchTexture(texture);
127         }
128     }
129     SkSafeUnref(fSurface);
130 }
131
132 GrTexture* SkGrPixelRef::getTexture() {
133     if (fSurface) {
134         return fSurface->asTexture();
135     }
136     return NULL;
137 }
138
139 SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) {
140     if (NULL == fSurface) {
141         return NULL;
142     }
143
144     // Note that when copying a render-target-backed pixel ref, we
145     // return a texture-backed pixel ref instead.  This is because
146     // render-target pixel refs are usually created in conjunction with
147     // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
148     // independently of that texture.  Texture-backed pixel refs, on the other
149     // hand, own their GrTextures, and are thus self-contained.
150     return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, subset);
151 }
152
153 static bool tryAllocBitmapPixels(SkBitmap* bitmap) {
154     SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
155     if (NULL != allocator) {
156         return allocator->allocPixelRef(bitmap, 0);
157     } else {
158         // DiscardableMemory is not available, fallback to default allocator
159         return bitmap->tryAllocPixels();
160     }
161 }
162
163 bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
164     if (NULL == fSurface || fSurface->wasDestroyed()) {
165         return false;
166     }
167
168     SkIRect bounds;
169     if (subset) {
170         bounds = *subset;
171     } else {
172         bounds = SkIRect::MakeWH(this->info().width(), this->info().height());
173     }
174
175     //Check the cache
176     if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) {
177         //Cache miss
178
179         SkBitmap cachedBitmap;
180         cachedBitmap.setInfo(this->info().makeWH(bounds.width(), bounds.height()));
181
182         // If we can't alloc the pixels, then fail
183         if (!tryAllocBitmapPixels(&cachedBitmap)) {
184             return false;
185         }
186
187         // Try to read the pixels from the surface
188         void* buffer = cachedBitmap.getPixels();
189         bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop,
190                                 bounds.width(), bounds.height(),
191                                 kSkia8888_GrPixelConfig,
192                                 buffer, cachedBitmap.rowBytes());
193
194         if (!readPixelsOk) {
195             return false;
196         }
197
198         // If we are here, pixels were read correctly from the surface.
199         cachedBitmap.setImmutable();
200         //Add to the cache
201         SkBitmapCache::Add(this->getGenerationID(), bounds, cachedBitmap);
202
203         dst->swap(cachedBitmap);
204     }
205
206     return true;
207
208 }