1ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
8ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
9ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
10ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
115088eb49fedac4180e2d5822e2636b3c6edeef9arobertphillips@google.com#include "SkGrPixelRef.h"
12ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org#include "GrContext.h"
13ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrTexture.h"
14ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org#include "SkGr.h"
15669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com#include "SkRect.h"
169c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
179c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com// since we call lockPixels recursively on fBitmap, we need a distinct mutex,
189c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com// to avoid deadlock with the default one provided by SkPixelRef.
191771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.comSK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
209c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
21bf790232f6d94b54239dbc210d8beee7411ca458reed@google.comSkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
22bf790232f6d94b54239dbc210d8beee7411ca458reed@google.com    : INHERITED(info, &gROLockPixelsPixelRefMutex) {}
239c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
24bf790232f6d94b54239dbc210d8beee7411ca458reed@google.comSkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
259c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
26d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.combool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
279c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    fBitmap.reset();
289c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com//    SkDebugf("---------- calling readpixels in support of lockpixels\n");
299c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    if (!this->onReadPixels(&fBitmap, NULL)) {
309c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com        SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
31d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com        return false;
329c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    }
339c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    fBitmap.lockPixels();
34d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    if (NULL == fBitmap.getPixels()) {
35d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com        return false;
36d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    }
37d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com
38d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    rec->fPixels = fBitmap.getPixels();
39d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    rec->fColorTable = NULL;
40d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    rec->fRowBytes = fBitmap.rowBytes();
41d0419b1fe781ed21d4aa0dc80df6b3e79ed37e46reed@google.com    return true;
429c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com}
439c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
449c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.comvoid SkROLockPixelsPixelRef::onUnlockPixels() {
459c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    fBitmap.unlockPixels();
469c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com}
479c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
489c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.combool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
499c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com    return false;
509c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com}
519c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com
529c49bc3e643c435677727c1c0904c4a7cb7a6907reed@google.com///////////////////////////////////////////////////////////////////////////////
53669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com
54e4538f5b46d70798e34eb078f5d5e76a59d02318reedstatic SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkColorType dstCT,
55eeef0cc49bf71e8b5e044d6a73b79cfe2b2c87b3commit-bot@chromium.org                                           const SkIRect* subset) {
56e4538f5b46d70798e34eb078f5d5e76a59d02318reed    if (NULL == texture || kUnknown_SkColorType == dstCT) {
57ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org        return NULL;
58ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    }
59ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    GrContext* context = texture->getContext();
60ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    if (NULL == context) {
61ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org        return NULL;
62ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    }
63ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    GrTextureDesc desc;
64ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org
65a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    SkIPoint pointStorage;
66a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    SkIPoint* topLeft;
67a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    if (subset != NULL) {
68a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
69a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        // Create a new texture that is the size of subset.
70a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        desc.fWidth = subset->width();
71a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        desc.fHeight = subset->height();
72a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        pointStorage.set(subset->x(), subset->y());
73a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        topLeft = &pointStorage;
74a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    } else {
75a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        desc.fWidth  = texture->width();
76a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        desc.fHeight = texture->height();
77a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com        topLeft = NULL;
78a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    }
79ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
80e4538f5b46d70798e34eb078f5d5e76a59d02318reed    desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType);
8196f5fa02e996e39179f2eb88d57e8ed6114b06c5skia.committer@gmail.com
82ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
83ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    if (NULL == dst) {
84ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org        return NULL;
85ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    }
86ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org
87a2a31928470dfb642880f6ab2e4d34b1c7f5d476scroggo@google.com    context->copyTexture(texture, dst->asRenderTarget(), topLeft);
88d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com
8941efe04af99b11440b6de39919f92bc9d1514f5crobertphillips@google.com    // TODO: figure out if this is responsible for Chrome canvas errors
9041efe04af99b11440b6de39919f92bc9d1514f5crobertphillips@google.com#if 0
91d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // The render texture we have created (to perform the copy) isn't fully
92d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // functional (since it doesn't have a stencil buffer). Release it here
93d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // so the caller doesn't try to render to it.
94d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // TODO: we can undo this release when dynamic stencil buffer attach/
95d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // detach has been implemented
96d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    dst->releaseRenderTarget();
9741efe04af99b11440b6de39919f92bc9d1514f5crobertphillips@google.com#endif
98d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com
99e4538f5b46d70798e34eb078f5d5e76a59d02318reed    SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType);
100bf790232f6d94b54239dbc210d8beee7411ca458reed@google.com    SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
101a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org    SkSafeUnref(dst);
102ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    return pixelRef;
103ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org}
104ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org
105ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
106ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org
107bf790232f6d94b54239dbc210d8beee7411ca458reed@google.comSkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
108bf790232f6d94b54239dbc210d8beee7411ca458reed@google.com                           bool transferCacheLock) : INHERITED(info) {
10961867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    // TODO: figure out if this is responsible for Chrome canvas errors
11061867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com#if 0
11161867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    // The GrTexture has a ref to the GrRenderTarget but not vice versa.
11261867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    // If the GrTexture exists take a ref to that (rather than the render
11361867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    // target)
11461867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    fSurface = surface->asTexture();
11561867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com#else
11661867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    fSurface = NULL;
11761867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com#endif
11861867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    if (NULL == fSurface) {
11961867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com        fSurface = surface;
12061867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    }
12161867875ef8083ca39a76acc8ffeedd2623d4b35reed@google.com    fUnlock = transferCacheLock;
122a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org    SkSafeRef(surface);
1238e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org
1248e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org    if (fSurface) {
1258e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org        SkASSERT(info.fWidth <= fSurface->width());
1268e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org        SkASSERT(info.fHeight <= fSurface->height());
1278e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org    }
128669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com}
129669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com
130d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.comSkGrPixelRef::~SkGrPixelRef() {
1318090e651fc1055e0a36f5f17c851faafda949b2cbsalomon@google.com    if (fUnlock) {
1328090e651fc1055e0a36f5f17c851faafda949b2cbsalomon@google.com        GrContext* context = fSurface->getContext();
133d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com        GrTexture* texture = fSurface->asTexture();
1348090e651fc1055e0a36f5f17c851faafda949b2cbsalomon@google.com        if (NULL != context && NULL != texture) {
1359fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com            context->unlockScratchTexture(texture);
1368090e651fc1055e0a36f5f17c851faafda949b2cbsalomon@google.com        }
1378090e651fc1055e0a36f5f17c851faafda949b2cbsalomon@google.com    }
138a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org    SkSafeUnref(fSurface);
139669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com}
140669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com
141b8d00db075b5ea09e353508a26ef5ced50722a6ccommit-bot@chromium.orgGrTexture* SkGrPixelRef::getTexture() {
142d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    if (NULL != fSurface) {
143b8d00db075b5ea09e353508a26ef5ced50722a6ccommit-bot@chromium.org        return fSurface->asTexture();
144669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com    }
145669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com    return NULL;
14650dfa0130b0705414df7ba7da9915139f6320b09reed@google.com}
147ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
148e4538f5b46d70798e34eb078f5d5e76a59d02318reedSkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) {
149d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    if (NULL == fSurface) {
150ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org        return NULL;
151ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org    }
152e4538f5b46d70798e34eb078f5d5e76a59d02318reed
153d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // Note that when copying a render-target-backed pixel ref, we
154d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // return a texture-backed pixel ref instead.  This is because
155d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // render-target pixel refs are usually created in conjunction with
156d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
157d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // independently of that texture.  Texture-backed pixel refs, on the other
158d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    // hand, own their GrTextures, and are thus self-contained.
159e4538f5b46d70798e34eb078f5d5e76a59d02318reed    return copyToTexturePixelRef(fSurface->asTexture(), dstCT, subset);
160ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org}
161ef843cdcd1be858fe55cc99ff134ffbd080c9a51senorblanco@chromium.org
162d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.combool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
163089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    if (NULL == fSurface || fSurface->wasDestroyed()) {
164669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com        return false;
165669fdc4ed8ed461a141cb97d0afdd9ef72a82be1bsalomon@google.com    }
166d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com
167d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    int left, top, width, height;
168d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    if (NULL != subset) {
169d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        left = subset->fLeft;
170d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        width = subset->width();
171d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        top = subset->fTop;
172d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        height = subset->height();
173d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    } else {
174d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        left = 0;
1758e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org        width = this->info().fWidth;
176d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com        top = 0;
1778e0993d8d8408e538d99229eabf710ad90d97259commit-bot@chromium.org        height = this->info().fHeight;
178d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    }
1799ebcac54635cde63110d73ad7c43d70772e7872freed@google.com    if (!dst->allocPixels(SkImageInfo::MakeN32Premul(width, height))) {
180009bcca7457b3711d48604df7547ffdb937fad50bsalomon@google.com        SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n");
181009bcca7457b3711d48604df7547ffdb937fad50bsalomon@google.com        return false;
182009bcca7457b3711d48604df7547ffdb937fad50bsalomon@google.com    }
183d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    SkAutoLockPixels al(*dst);
184d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    void* buffer = dst->getPixels();
185d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com    return fSurface->readPixels(left, top, width, height,
186fec0bc3fc13481f5bcb341ab2d2d695911f39bd4bsalomon@google.com                                kSkia8888_GrPixelConfig,
187d881bc194d7c24294029b5c08e6e549a9fd9b6f3robertphillips@google.com                                buffer, dst->rowBytes());
1884281d650934475fd50fdd61fab94421d7454e44dreed@google.com}
189