OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2010 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 | |
9 | |
10 #include "SkGrPixelRef.h" | |
11 | |
12 #include "GrContext.h" | |
13 #include "GrTexture.h" | |
14 #include "GrTexturePriv.h" | |
15 #include "SkBitmapCache.h" | |
16 #include "SkGr.h" | |
17 #include "SkRect.h" | |
18 | |
19 SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) | |
20 : INHERITED(info) {} | |
21 | |
22 SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} | |
23 | |
24 bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) { | |
25 fBitmap.reset(); | |
26 // SkDebugf("---------- calling readpixels in support of lockpixels\n"); | |
27 if (!this->onReadPixels(&fBitmap, this->info().colorType(), nullptr)) { | |
28 SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); | |
29 return false; | |
30 } | |
31 fBitmap.lockPixels(); | |
32 if (nullptr == fBitmap.getPixels()) { | |
33 return false; | |
34 } | |
35 | |
36 rec->fPixels = fBitmap.getPixels(); | |
37 rec->fColorTable = nullptr; | |
38 rec->fRowBytes = fBitmap.rowBytes(); | |
39 return true; | |
40 } | |
41 | |
42 void SkROLockPixelsPixelRef::onUnlockPixels() { | |
43 fBitmap.unlockPixels(); | |
44 } | |
45 | |
46 bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const { | |
47 return false; | |
48 } | |
49 | |
50 /////////////////////////////////////////////////////////////////////////////// | |
51 | |
52 static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorTyp
e dstCT, | |
53 SkColorSpace* dstCS, const SkI
Rect* subset) { | |
54 if (nullptr == texture || kUnknown_SkColorType == dstCT) { | |
55 return nullptr; | |
56 } | |
57 GrContext* context = texture->getContext(); | |
58 if (nullptr == context) { | |
59 return nullptr; | |
60 } | |
61 GrSurfaceDesc desc; | |
62 | |
63 SkIRect srcRect; | |
64 | |
65 if (!subset) { | |
66 desc.fWidth = texture->width(); | |
67 desc.fHeight = texture->height(); | |
68 srcRect = SkIRect::MakeWH(texture->width(), texture->height()); | |
69 } else { | |
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 srcRect = *subset; | |
75 } | |
76 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
77 desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType, dstCS,
*context->caps()); | |
78 desc.fIsMipMapped = false; | |
79 | |
80 GrTexture* dst = context->textureProvider()->createTexture(desc, SkBudgeted:
:kNo, nullptr, 0); | |
81 if (nullptr == dst) { | |
82 return nullptr; | |
83 } | |
84 | |
85 // Blink is relying on the above copy being sent to GL immediately in the ca
se when the source | |
86 // is a WebGL canvas backing store. We could have a TODO to remove this flus
h, but we have | |
87 // a larger TODO to remove SkGrPixelRef entirely. | |
88 context->copySurface(dst, texture, srcRect, SkIPoint::Make(0,0)); | |
89 context->flushSurfaceWrites(dst); | |
90 | |
91 SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPrem
ul_SkAlphaType, | |
92 sk_ref_sp(dstCS)); | |
93 SkGrPixelRef* pixelRef = new SkGrPixelRef(info, dst); | |
94 SkSafeUnref(dst); | |
95 return pixelRef; | |
96 } | |
97 | |
98 /////////////////////////////////////////////////////////////////////////////// | |
99 | |
100 SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface) : INHERI
TED(info) { | |
101 // For surfaces that are both textures and render targets, the texture owns
the | |
102 // render target but not vice versa. So we ref the texture to keep both aliv
e for | |
103 // the lifetime of this pixel ref. | |
104 fSurface = SkSafeRef(surface->asTexture()); | |
105 if (nullptr == fSurface) { | |
106 fSurface = SkSafeRef(surface); | |
107 } | |
108 | |
109 if (fSurface) { | |
110 SkASSERT(info.width() <= fSurface->width()); | |
111 SkASSERT(info.height() <= fSurface->height()); | |
112 } | |
113 } | |
114 | |
115 SkGrPixelRef::~SkGrPixelRef() { | |
116 SkSafeUnref(fSurface); | |
117 } | |
118 | |
119 GrTexture* SkGrPixelRef::getTexture() { | |
120 if (fSurface) { | |
121 return fSurface->asTexture(); | |
122 } | |
123 return nullptr; | |
124 } | |
125 | |
126 void SkGrPixelRef::onNotifyPixelsChanged() { | |
127 GrTexture* texture = this->getTexture(); | |
128 if (texture) { | |
129 texture->texturePriv().dirtyMipMaps(true); | |
130 } | |
131 } | |
132 | |
133 SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, SkColorSpace* dstCS, const
SkIRect* subset) { | |
134 if (nullptr == fSurface) { | |
135 return nullptr; | |
136 } | |
137 | |
138 // Note that when copying a render-target-backed pixel ref, we | |
139 // return a texture-backed pixel ref instead. This is because | |
140 // render-target pixel refs are usually created in conjunction with | |
141 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live | |
142 // independently of that texture. Texture-backed pixel refs, on the other | |
143 // hand, own their GrTextures, and are thus self-contained. | |
144 return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, dstCS, sub
set); | |
145 } | |
146 | |
147 static bool tryAllocBitmapPixels(SkBitmap* bitmap) { | |
148 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator(); | |
149 if (nullptr != allocator) { | |
150 return allocator->allocPixelRef(bitmap, 0); | |
151 } else { | |
152 // DiscardableMemory is not available, fallback to default allocator | |
153 return bitmap->tryAllocPixels(); | |
154 } | |
155 } | |
156 | |
157 bool SkGrPixelRef::onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIR
ect* subset) { | |
158 if (nullptr == fSurface || fSurface->wasDestroyed()) { | |
159 return false; | |
160 } | |
161 | |
162 GrPixelConfig config; | |
163 if (kRGBA_8888_SkColorType == colorType) { | |
164 config = kRGBA_8888_GrPixelConfig; | |
165 } else if (kBGRA_8888_SkColorType == colorType) { | |
166 config = kBGRA_8888_GrPixelConfig; | |
167 } else { | |
168 return false; | |
169 } | |
170 | |
171 SkIRect bounds; | |
172 if (subset) { | |
173 bounds = *subset; | |
174 } else { | |
175 bounds = SkIRect::MakeWH(this->info().width(), this->info().height()); | |
176 } | |
177 | |
178 //Check the cache | |
179 if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) { | |
180 //Cache miss | |
181 | |
182 SkBitmap cachedBitmap; | |
183 cachedBitmap.setInfo(SkImageInfo::Make(bounds.width(), bounds.height(),
colorType, | |
184 this->info().alphaType(), | |
185 sk_ref_sp(this->info().colorSpace
()))); | |
186 | |
187 // If we can't alloc the pixels, then fail | |
188 if (!tryAllocBitmapPixels(&cachedBitmap)) { | |
189 return false; | |
190 } | |
191 | |
192 // Try to read the pixels from the surface | |
193 void* buffer = cachedBitmap.getPixels(); | |
194 bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop, | |
195 bounds.width(), bounds.height(), | |
196 config, buffer, cachedBitmap.rowBytes()); | |
197 | |
198 if (!readPixelsOk) { | |
199 return false; | |
200 } | |
201 | |
202 // If we are here, pixels were read correctly from the surface. | |
203 cachedBitmap.setImmutable(); | |
204 //Add to the cache | |
205 SkBitmapCache::Add(this, bounds, cachedBitmap); | |
206 | |
207 dst->swap(cachedBitmap); | |
208 } | |
209 | |
210 return true; | |
211 | |
212 } | |
OLD | NEW |