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