blob: 081c09f91c200872cf5d8aa3a38c6e28d0af5760 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
robertphillips@google.com5088eb42012-06-28 20:59:13 +000011#include "SkGrPixelRef.h"
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000012#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrTexture.h"
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000014#include "SkGr.h"
bsalomon@google.com669fdc42011-04-05 17:08:27 +000015#include "SkRect.h"
reed@google.com9c49bc32011-07-07 13:42:37 +000016
17// since we call lockPixels recursively on fBitmap, we need a distinct mutex,
18// to avoid deadlock with the default one provided by SkPixelRef.
digit@google.com1771cbf2012-01-26 21:26:40 +000019SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
reed@google.com9c49bc32011-07-07 13:42:37 +000020
21SkROLockPixelsPixelRef::SkROLockPixelsPixelRef() : INHERITED(&gROLockPixelsPixelRefMutex) {
22}
23
24SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {
25}
26
27void* SkROLockPixelsPixelRef::onLockPixels(SkColorTable** ctable) {
28 if (ctable) {
29 *ctable = NULL;
30 }
31 fBitmap.reset();
32// SkDebugf("---------- calling readpixels in support of lockpixels\n");
33 if (!this->onReadPixels(&fBitmap, NULL)) {
34 SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
35 return NULL;
36 }
37 fBitmap.lockPixels();
38 return fBitmap.getPixels();
39}
40
41void SkROLockPixelsPixelRef::onUnlockPixels() {
42 fBitmap.unlockPixels();
43}
44
45bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
46 return false;
47}
48
49///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com669fdc42011-04-05 17:08:27 +000050
scroggo@google.coma2a31922012-12-07 19:14:45 +000051static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dstConfig,
52 const SkIRect* subset) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000053 if (NULL == texture) {
54 return NULL;
55 }
56 GrContext* context = texture->getContext();
57 if (NULL == context) {
58 return NULL;
59 }
60 GrTextureDesc desc;
61
scroggo@google.coma2a31922012-12-07 19:14:45 +000062 SkIPoint pointStorage;
63 SkIPoint* topLeft;
64 if (subset != NULL) {
65 SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
66 // Create a new texture that is the size of subset.
67 desc.fWidth = subset->width();
68 desc.fHeight = subset->height();
69 pointStorage.set(subset->x(), subset->y());
70 topLeft = &pointStorage;
71 } else {
72 desc.fWidth = texture->width();
73 desc.fHeight = texture->height();
74 topLeft = NULL;
75 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000076 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
rileya@google.com24f3ad12012-07-18 21:47:40 +000077 desc.fConfig = SkBitmapConfig2GrPixelConfig(dstConfig);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000078
79 GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
80 if (NULL == dst) {
81 return NULL;
82 }
83
scroggo@google.coma2a31922012-12-07 19:14:45 +000084 context->copyTexture(texture, dst->asRenderTarget(), topLeft);
robertphillips@google.comd881bc12012-06-28 20:02:39 +000085
robertphillips@google.com41efe042012-06-29 20:55:14 +000086 // TODO: figure out if this is responsible for Chrome canvas errors
87#if 0
robertphillips@google.comd881bc12012-06-28 20:02:39 +000088 // The render texture we have created (to perform the copy) isn't fully
89 // functional (since it doesn't have a stencil buffer). Release it here
90 // so the caller doesn't try to render to it.
91 // TODO: we can undo this release when dynamic stencil buffer attach/
92 // detach has been implemented
93 dst->releaseRenderTarget();
robertphillips@google.com41efe042012-06-29 20:55:14 +000094#endif
robertphillips@google.comd881bc12012-06-28 20:02:39 +000095
tomhudson@google.comc377baf2012-07-09 20:17:56 +000096 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (dst));
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000097 GrSafeUnref(dst);
98 return pixelRef;
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
bsalomon@google.com8090e652012-08-28 15:07:11 +0000103SkGrPixelRef::SkGrPixelRef(GrSurface* surface, bool transferCacheLock) {
robertphillips@google.com41efe042012-06-29 20:55:14 +0000104 // TODO: figure out if this is responsible for Chrome canvas errors
105#if 0
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000106 // The GrTexture has a ref to the GrRenderTarget but not vice versa.
107 // If the GrTexture exists take a ref to that (rather than the render
108 // target)
109 fSurface = surface->asTexture();
robertphillips@google.com41efe042012-06-29 20:55:14 +0000110#else
111 fSurface = NULL;
112#endif
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000113 if (NULL == fSurface) {
114 fSurface = surface;
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000115 }
bsalomon@google.com8090e652012-08-28 15:07:11 +0000116 fUnlock = transferCacheLock;
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000117 GrSafeRef(surface);
reed@google.com50dfa012011-04-01 19:05:36 +0000118}
reed@google.comac10a2d2010-12-22 21:39:39 +0000119
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000120SkGrPixelRef::~SkGrPixelRef() {
bsalomon@google.com8090e652012-08-28 15:07:11 +0000121 if (fUnlock) {
122 GrContext* context = fSurface->getContext();
robertphillips@google.comd07cb0c2012-08-30 19:22:29 +0000123 GrTexture* texture = fSurface->asTexture();
bsalomon@google.com8090e652012-08-28 15:07:11 +0000124 if (NULL != context && NULL != texture) {
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000125 context->unlockScratchTexture(texture);
bsalomon@google.com8090e652012-08-28 15:07:11 +0000126 }
127 }
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000128 GrSafeUnref(fSurface);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000129}
130
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000131SkGpuTexture* SkGrPixelRef::getTexture() {
132 if (NULL != fSurface) {
133 return (SkGpuTexture*) fSurface->asTexture();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000134 }
135 return NULL;
136}
137
scroggo@google.coma2a31922012-12-07 19:14:45 +0000138SkPixelRef* SkGrPixelRef::deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) {
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000139 if (NULL == fSurface) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000140 return NULL;
141 }
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000142
143 // Note that when copying a render-target-backed pixel ref, we
144 // return a texture-backed pixel ref instead. This is because
145 // render-target pixel refs are usually created in conjunction with
146 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
147 // independently of that texture. Texture-backed pixel refs, on the other
148 // hand, own their GrTextures, and are thus self-contained.
scroggo@google.coma2a31922012-12-07 19:14:45 +0000149 return copyToTexturePixelRef(fSurface->asTexture(), dstConfig, subset);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000150}
151
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000152bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
153 if (NULL == fSurface || !fSurface->isValid()) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000154 return false;
155 }
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000156
157 int left, top, width, height;
158 if (NULL != subset) {
159 left = subset->fLeft;
160 width = subset->width();
161 top = subset->fTop;
162 height = subset->height();
163 } else {
164 left = 0;
165 width = fSurface->width();
166 top = 0;
167 height = fSurface->height();
168 }
169 dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
bsalomon@google.com009bcca2012-12-18 21:40:08 +0000170 if (!dst->allocPixels()) {
171 SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n");
172 return false;
173 }
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000174 SkAutoLockPixels al(*dst);
175 void* buffer = dst->getPixels();
176 return fSurface->readPixels(left, top, width, height,
177 kSkia8888_PM_GrPixelConfig,
178 buffer, dst->rowBytes());
reed@google.com4281d652011-04-08 18:54:20 +0000179}
reed@google.com9c49bc32011-07-07 13:42:37 +0000180