SkGrPixelRef.cpp revision 473f0aa2bb218e50fce5e19063f8c8fdaf57fad4
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#include "GrContext.h"
13#include "GrTexture.h"
14#include "SkGr.h"
15#include "SkRect.h"
16
17// since we call lockPixels recursively on fBitmap, we need a distinct mutex,
18// to avoid deadlock with the default one provided by SkPixelRef.
19SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
20
21SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
22    : INHERITED(info, &gROLockPixelsPixelRefMutex) {
23}
24
25SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {
26}
27
28bool 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
46void SkROLockPixelsPixelRef::onUnlockPixels() {
47    fBitmap.unlockPixels();
48}
49
50bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
51    return false;
52}
53
54///////////////////////////////////////////////////////////////////////////////
55
56static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dstConfig,
57                                           const SkIRect* subset) {
58    if (NULL == texture) {
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 = SkBitmapConfig2GrPixelConfig(dstConfig);
83
84    SkImageInfo info;
85    if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) {
86        return NULL;
87    }
88    info.fWidth = desc.fWidth;
89    info.fHeight = desc.fHeight;
90    info.fAlphaType = kPremul_SkAlphaType;
91
92    GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
93    if (NULL == dst) {
94        return NULL;
95    }
96
97    context->copyTexture(texture, dst->asRenderTarget(), topLeft);
98
99    // TODO: figure out if this is responsible for Chrome canvas errors
100#if 0
101    // The render texture we have created (to perform the copy) isn't fully
102    // functional (since it doesn't have a stencil buffer). Release it here
103    // so the caller doesn't try to render to it.
104    // TODO: we can undo this release when dynamic stencil buffer attach/
105    // detach has been implemented
106    dst->releaseRenderTarget();
107#endif
108
109    SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
110    SkSafeUnref(dst);
111    return pixelRef;
112}
113
114///////////////////////////////////////////////////////////////////////////////
115
116SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
117                           bool transferCacheLock)
118    : INHERITED(info)
119{
120    // TODO: figure out if this is responsible for Chrome canvas errors
121#if 0
122    // The GrTexture has a ref to the GrRenderTarget but not vice versa.
123    // If the GrTexture exists take a ref to that (rather than the render
124    // target)
125    fSurface = surface->asTexture();
126#else
127    fSurface = NULL;
128#endif
129    if (NULL == fSurface) {
130        fSurface = surface;
131    }
132    fUnlock = transferCacheLock;
133    SkSafeRef(surface);
134}
135
136SkGrPixelRef::~SkGrPixelRef() {
137    if (fUnlock) {
138        GrContext* context = fSurface->getContext();
139        GrTexture* texture = fSurface->asTexture();
140        if (NULL != context && NULL != texture) {
141            context->unlockScratchTexture(texture);
142        }
143    }
144    SkSafeUnref(fSurface);
145}
146
147GrTexture* SkGrPixelRef::getTexture() {
148    if (NULL != fSurface) {
149        return fSurface->asTexture();
150    }
151    return NULL;
152}
153
154SkPixelRef* SkGrPixelRef::deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) {
155    if (NULL == fSurface) {
156        return NULL;
157    }
158
159    // Note that when copying a render-target-backed pixel ref, we
160    // return a texture-backed pixel ref instead.  This is because
161    // render-target pixel refs are usually created in conjunction with
162    // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
163    // independently of that texture.  Texture-backed pixel refs, on the other
164    // hand, own their GrTextures, and are thus self-contained.
165    return copyToTexturePixelRef(fSurface->asTexture(), dstConfig, subset);
166}
167
168bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
169    if (NULL == fSurface || !fSurface->isValid()) {
170        return false;
171    }
172
173    int left, top, width, height;
174    if (NULL != subset) {
175        left = subset->fLeft;
176        width = subset->width();
177        top = subset->fTop;
178        height = subset->height();
179    } else {
180        left = 0;
181        width = fSurface->width();
182        top = 0;
183        height = fSurface->height();
184    }
185    dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
186    if (!dst->allocPixels()) {
187        SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n");
188        return false;
189    }
190    SkAutoLockPixels al(*dst);
191    void* buffer = dst->getPixels();
192    return fSurface->readPixels(left, top, width, height,
193                                kSkia8888_GrPixelConfig,
194                                buffer, dst->rowBytes());
195}
196