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
24SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
25
26bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
27    fBitmap.reset();
28//    SkDebugf("---------- calling readpixels in support of lockpixels\n");
29    if (!this->onReadPixels(&fBitmap, NULL)) {
30        SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
31        return false;
32    }
33    fBitmap.lockPixels();
34    if (NULL == fBitmap.getPixels()) {
35        return false;
36    }
37
38    rec->fPixels = fBitmap.getPixels();
39    rec->fColorTable = NULL;
40    rec->fRowBytes = fBitmap.rowBytes();
41    return true;
42}
43
44void SkROLockPixelsPixelRef::onUnlockPixels() {
45    fBitmap.unlockPixels();
46}
47
48bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
49    return false;
50}
51
52///////////////////////////////////////////////////////////////////////////////
53
54static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkColorType dstCT,
55                                           const SkIRect* subset) {
56    if (NULL == texture || kUnknown_SkColorType == dstCT) {
57        return NULL;
58    }
59    GrContext* context = texture->getContext();
60    if (NULL == context) {
61        return NULL;
62    }
63    GrTextureDesc desc;
64
65    SkIPoint pointStorage;
66    SkIPoint* topLeft;
67    if (subset != NULL) {
68        SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
69        // Create a new texture that is the size of subset.
70        desc.fWidth = subset->width();
71        desc.fHeight = subset->height();
72        pointStorage.set(subset->x(), subset->y());
73        topLeft = &pointStorage;
74    } else {
75        desc.fWidth  = texture->width();
76        desc.fHeight = texture->height();
77        topLeft = NULL;
78    }
79    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
80    desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType);
81
82    GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
83    if (NULL == dst) {
84        return NULL;
85    }
86
87    context->copyTexture(texture, dst->asRenderTarget(), topLeft);
88
89    // TODO: figure out if this is responsible for Chrome canvas errors
90#if 0
91    // The render texture we have created (to perform the copy) isn't fully
92    // functional (since it doesn't have a stencil buffer). Release it here
93    // so the caller doesn't try to render to it.
94    // TODO: we can undo this release when dynamic stencil buffer attach/
95    // detach has been implemented
96    dst->releaseRenderTarget();
97#endif
98
99    SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType);
100    SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
101    SkSafeUnref(dst);
102    return pixelRef;
103}
104
105///////////////////////////////////////////////////////////////////////////////
106
107SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
108                           bool transferCacheLock) : INHERITED(info) {
109    // TODO: figure out if this is responsible for Chrome canvas errors
110#if 0
111    // The GrTexture has a ref to the GrRenderTarget but not vice versa.
112    // If the GrTexture exists take a ref to that (rather than the render
113    // target)
114    fSurface = surface->asTexture();
115#else
116    fSurface = NULL;
117#endif
118    if (NULL == fSurface) {
119        fSurface = surface;
120    }
121    fUnlock = transferCacheLock;
122    SkSafeRef(surface);
123
124    if (fSurface) {
125        SkASSERT(info.fWidth <= fSurface->width());
126        SkASSERT(info.fHeight <= fSurface->height());
127    }
128}
129
130SkGrPixelRef::~SkGrPixelRef() {
131    if (fUnlock) {
132        GrContext* context = fSurface->getContext();
133        GrTexture* texture = fSurface->asTexture();
134        if (NULL != context && NULL != texture) {
135            context->unlockScratchTexture(texture);
136        }
137    }
138    SkSafeUnref(fSurface);
139}
140
141GrTexture* SkGrPixelRef::getTexture() {
142    if (NULL != fSurface) {
143        return fSurface->asTexture();
144    }
145    return NULL;
146}
147
148SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) {
149    if (NULL == fSurface) {
150        return NULL;
151    }
152
153    // Note that when copying a render-target-backed pixel ref, we
154    // return a texture-backed pixel ref instead.  This is because
155    // render-target pixel refs are usually created in conjunction with
156    // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
157    // independently of that texture.  Texture-backed pixel refs, on the other
158    // hand, own their GrTextures, and are thus self-contained.
159    return copyToTexturePixelRef(fSurface->asTexture(), dstCT, subset);
160}
161
162bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
163    if (NULL == fSurface || fSurface->wasDestroyed()) {
164        return false;
165    }
166
167    int left, top, width, height;
168    if (NULL != subset) {
169        left = subset->fLeft;
170        width = subset->width();
171        top = subset->fTop;
172        height = subset->height();
173    } else {
174        left = 0;
175        width = this->info().fWidth;
176        top = 0;
177        height = this->info().fHeight;
178    }
179    if (!dst->allocPixels(SkImageInfo::MakeN32Premul(width, height))) {
180        SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n");
181        return false;
182    }
183    SkAutoLockPixels al(*dst);
184    void* buffer = dst->getPixels();
185    return fSurface->readPixels(left, top, width, height,
186                                kSkia8888_GrPixelConfig,
187                                buffer, dst->rowBytes());
188}
189