1 | /* |
2 | * Copyright 2012 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 | #include <atomic> |
9 | #include <cmath> |
10 | #include "include/core/SkCanvas.h" |
11 | #include "include/core/SkFontLCDConfig.h" |
12 | #include "include/gpu/GrBackendSurface.h" |
13 | #include "src/core/SkAutoPixmapStorage.h" |
14 | #include "src/core/SkImagePriv.h" |
15 | #include "src/image/SkRescaleAndReadPixels.h" |
16 | #include "src/image/SkSurface_Base.h" |
17 | |
18 | static SkPixelGeometry compute_default_geometry() { |
19 | SkFontLCDConfig::LCDOrder order = SkFontLCDConfig::GetSubpixelOrder(); |
20 | if (SkFontLCDConfig::kNONE_LCDOrder == order) { |
21 | return kUnknown_SkPixelGeometry; |
22 | } else { |
23 | // Bit0 is RGB(0), BGR(1) |
24 | // Bit1 is H(0), V(1) |
25 | const SkPixelGeometry gGeo[] = { |
26 | kRGB_H_SkPixelGeometry, |
27 | kBGR_H_SkPixelGeometry, |
28 | kRGB_V_SkPixelGeometry, |
29 | kBGR_V_SkPixelGeometry, |
30 | }; |
31 | int index = 0; |
32 | if (SkFontLCDConfig::kBGR_LCDOrder == order) { |
33 | index |= 1; |
34 | } |
35 | if (SkFontLCDConfig::kVertical_LCDOrientation == SkFontLCDConfig::GetSubpixelOrientation()){ |
36 | index |= 2; |
37 | } |
38 | return gGeo[index]; |
39 | } |
40 | } |
41 | |
42 | SkSurfaceProps::SkSurfaceProps() : fFlags(0), fPixelGeometry(kUnknown_SkPixelGeometry) {} |
43 | |
44 | SkSurfaceProps::SkSurfaceProps(InitType) : fFlags(0), fPixelGeometry(compute_default_geometry()) {} |
45 | |
46 | SkSurfaceProps::SkSurfaceProps(uint32_t flags, InitType) |
47 | : fFlags(flags) |
48 | , fPixelGeometry(compute_default_geometry()) |
49 | {} |
50 | |
51 | SkSurfaceProps::SkSurfaceProps(uint32_t flags, SkPixelGeometry pg) |
52 | : fFlags(flags), fPixelGeometry(pg) |
53 | {} |
54 | |
55 | SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps&) = default; |
56 | SkSurfaceProps& SkSurfaceProps::operator=(const SkSurfaceProps&) = default; |
57 | |
58 | /////////////////////////////////////////////////////////////////////////////// |
59 | |
60 | SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props) |
61 | : INHERITED(width, height, props) { |
62 | } |
63 | |
64 | SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props) |
65 | : INHERITED(info, props) { |
66 | } |
67 | |
68 | SkSurface_Base::~SkSurface_Base() { |
69 | // in case the canvas outsurvives us, we null the callback |
70 | if (fCachedCanvas) { |
71 | fCachedCanvas->setSurfaceBase(nullptr); |
72 | } |
73 | } |
74 | |
75 | GrContext* SkSurface_Base::onGetContext_deprecated() { |
76 | return nullptr; |
77 | } |
78 | |
79 | GrRecordingContext* SkSurface_Base::onGetRecordingContext() { |
80 | return nullptr; |
81 | } |
82 | |
83 | GrBackendTexture SkSurface_Base::onGetBackendTexture(BackendHandleAccess) { |
84 | return GrBackendTexture(); // invalid |
85 | } |
86 | |
87 | GrBackendRenderTarget SkSurface_Base::onGetBackendRenderTarget(BackendHandleAccess) { |
88 | return GrBackendRenderTarget(); // invalid |
89 | } |
90 | |
91 | bool SkSurface_Base::onReplaceBackendTexture(const GrBackendTexture&, |
92 | GrSurfaceOrigin, ContentChangeMode, |
93 | TextureReleaseProc, |
94 | ReleaseContext) { |
95 | return false; |
96 | } |
97 | |
98 | void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) { |
99 | auto image = this->makeImageSnapshot(); |
100 | if (image) { |
101 | canvas->drawImage(image, x, y, paint); |
102 | } |
103 | } |
104 | |
105 | void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info, |
106 | const SkIRect& origSrcRect, |
107 | SkSurface::RescaleGamma rescaleGamma, |
108 | SkFilterQuality rescaleQuality, |
109 | SkSurface::ReadPixelsCallback callback, |
110 | SkSurface::ReadPixelsContext context) { |
111 | SkBitmap src; |
112 | SkPixmap peek; |
113 | SkIRect srcRect; |
114 | if (this->peekPixels(&peek)) { |
115 | src.installPixels(peek); |
116 | srcRect = origSrcRect; |
117 | } else { |
118 | src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size())); |
119 | src.allocPixels(); |
120 | if (!this->readPixels(src, origSrcRect.x(), origSrcRect.y())) { |
121 | callback(context, nullptr); |
122 | return; |
123 | } |
124 | srcRect = SkIRect::MakeSize(src.dimensions()); |
125 | } |
126 | return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleQuality, callback, |
127 | context); |
128 | } |
129 | |
130 | void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420( |
131 | SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect, |
132 | const SkISize& dstSize, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality, |
133 | ReadPixelsCallback callback, ReadPixelsContext context) { |
134 | // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and |
135 | // call client's callback. |
136 | callback(context, nullptr); |
137 | } |
138 | |
139 | bool SkSurface_Base::outstandingImageSnapshot() const { |
140 | return fCachedImage && !fCachedImage->unique(); |
141 | } |
142 | |
143 | void SkSurface_Base::aboutToDraw(ContentChangeMode mode) { |
144 | this->dirtyGenerationID(); |
145 | |
146 | SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); |
147 | |
148 | if (fCachedImage) { |
149 | // the surface may need to fork its backend, if its sharing it with |
150 | // the cached image. Note: we only call if there is an outstanding owner |
151 | // on the image (besides us). |
152 | bool unique = fCachedImage->unique(); |
153 | if (!unique) { |
154 | this->onCopyOnWrite(mode); |
155 | } |
156 | |
157 | // regardless of copy-on-write, we must drop our cached image now, so |
158 | // that the next request will get our new contents. |
159 | fCachedImage.reset(); |
160 | |
161 | if (unique) { |
162 | // Our content isn't held by any image now, so we can consider that content mutable. |
163 | // Raster surfaces need to be told it's safe to consider its pixels mutable again. |
164 | // We make this call after the ->unref() so the subclass can assert there are no images. |
165 | this->onRestoreBackingMutability(); |
166 | } |
167 | } else if (kDiscard_ContentChangeMode == mode) { |
168 | this->onDiscard(); |
169 | } |
170 | } |
171 | |
172 | uint32_t SkSurface_Base::newGenerationID() { |
173 | SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); |
174 | static std::atomic<uint32_t> nextID{1}; |
175 | return nextID++; |
176 | } |
177 | |
178 | static SkSurface_Base* asSB(SkSurface* surface) { |
179 | return static_cast<SkSurface_Base*>(surface); |
180 | } |
181 | |
182 | static const SkSurface_Base* asConstSB(const SkSurface* surface) { |
183 | return static_cast<const SkSurface_Base*>(surface); |
184 | } |
185 | |
186 | /////////////////////////////////////////////////////////////////////////////// |
187 | |
188 | SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props) |
189 | : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height) |
190 | { |
191 | SkASSERT(fWidth > 0); |
192 | SkASSERT(fHeight > 0); |
193 | fGenerationID = 0; |
194 | } |
195 | |
196 | SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props) |
197 | : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height()) |
198 | { |
199 | SkASSERT(fWidth > 0); |
200 | SkASSERT(fHeight > 0); |
201 | fGenerationID = 0; |
202 | } |
203 | |
204 | SkImageInfo SkSurface::imageInfo() { |
205 | // TODO: do we need to go through canvas for this? |
206 | return this->getCanvas()->imageInfo(); |
207 | } |
208 | |
209 | uint32_t SkSurface::generationID() { |
210 | if (0 == fGenerationID) { |
211 | fGenerationID = asSB(this)->newGenerationID(); |
212 | } |
213 | return fGenerationID; |
214 | } |
215 | |
216 | void SkSurface::notifyContentWillChange(ContentChangeMode mode) { |
217 | asSB(this)->aboutToDraw(mode); |
218 | } |
219 | |
220 | SkCanvas* SkSurface::getCanvas() { |
221 | return asSB(this)->getCachedCanvas(); |
222 | } |
223 | |
224 | sk_sp<SkImage> SkSurface::makeImageSnapshot() { |
225 | return asSB(this)->refCachedImage(); |
226 | } |
227 | |
228 | sk_sp<SkImage> SkSurface::makeImageSnapshot(const SkIRect& srcBounds) { |
229 | const SkIRect surfBounds = { 0, 0, fWidth, fHeight }; |
230 | SkIRect bounds = srcBounds; |
231 | if (!bounds.intersect(surfBounds)) { |
232 | return nullptr; |
233 | } |
234 | SkASSERT(!bounds.isEmpty()); |
235 | if (bounds == surfBounds) { |
236 | return this->makeImageSnapshot(); |
237 | } else { |
238 | return asSB(this)->onNewImageSnapshot(&bounds); |
239 | } |
240 | } |
241 | |
242 | sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) { |
243 | return asSB(this)->onNewSurface(info); |
244 | } |
245 | |
246 | sk_sp<SkSurface> SkSurface::makeSurface(int width, int height) { |
247 | return this->makeSurface(this->imageInfo().makeWH(width, height)); |
248 | } |
249 | |
250 | void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y, |
251 | const SkPaint* paint) { |
252 | return asSB(this)->onDraw(canvas, x, y, paint); |
253 | } |
254 | |
255 | bool SkSurface::peekPixels(SkPixmap* pmap) { |
256 | return this->getCanvas()->peekPixels(pmap); |
257 | } |
258 | |
259 | bool SkSurface::readPixels(const SkPixmap& pm, int srcX, int srcY) { |
260 | return this->getCanvas()->readPixels(pm, srcX, srcY); |
261 | } |
262 | |
263 | bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, |
264 | int srcX, int srcY) { |
265 | return this->readPixels({dstInfo, dstPixels, dstRowBytes}, srcX, srcY); |
266 | } |
267 | |
268 | bool SkSurface::readPixels(const SkBitmap& bitmap, int srcX, int srcY) { |
269 | SkPixmap pm; |
270 | return bitmap.peekPixels(&pm) && this->readPixels(pm, srcX, srcY); |
271 | } |
272 | |
273 | void SkSurface::asyncRescaleAndReadPixels(const SkImageInfo& info, |
274 | const SkIRect& srcRect, |
275 | RescaleGamma rescaleGamma, |
276 | SkFilterQuality rescaleQuality, |
277 | ReadPixelsCallback callback, |
278 | ReadPixelsContext context) { |
279 | if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || |
280 | !SkImageInfoIsValid(info)) { |
281 | callback(context, nullptr); |
282 | return; |
283 | } |
284 | asSB(this)->onAsyncRescaleAndReadPixels( |
285 | info, srcRect, rescaleGamma, rescaleQuality, callback, context); |
286 | } |
287 | |
288 | void SkSurface::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, |
289 | sk_sp<SkColorSpace> dstColorSpace, |
290 | const SkIRect& srcRect, |
291 | const SkISize& dstSize, |
292 | RescaleGamma rescaleGamma, |
293 | SkFilterQuality rescaleQuality, |
294 | ReadPixelsCallback callback, |
295 | ReadPixelsContext context) { |
296 | if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() || |
297 | (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) { |
298 | callback(context, nullptr); |
299 | return; |
300 | } |
301 | asSB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace, |
302 | std::move(dstColorSpace), |
303 | srcRect, |
304 | dstSize, |
305 | rescaleGamma, |
306 | rescaleQuality, |
307 | callback, |
308 | context); |
309 | } |
310 | |
311 | void SkSurface::writePixels(const SkPixmap& pmap, int x, int y) { |
312 | if (pmap.addr() == nullptr || pmap.width() <= 0 || pmap.height() <= 0) { |
313 | return; |
314 | } |
315 | |
316 | const SkIRect srcR = SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height()); |
317 | const SkIRect dstR = SkIRect::MakeWH(this->width(), this->height()); |
318 | if (SkIRect::Intersects(srcR, dstR)) { |
319 | ContentChangeMode mode = kRetain_ContentChangeMode; |
320 | if (srcR.contains(dstR)) { |
321 | mode = kDiscard_ContentChangeMode; |
322 | } |
323 | asSB(this)->aboutToDraw(mode); |
324 | asSB(this)->onWritePixels(pmap, x, y); |
325 | } |
326 | } |
327 | |
328 | void SkSurface::writePixels(const SkBitmap& src, int x, int y) { |
329 | SkPixmap pm; |
330 | if (src.peekPixels(&pm)) { |
331 | this->writePixels(pm, x, y); |
332 | } |
333 | } |
334 | |
335 | GrContext* SkSurface::getContext() { |
336 | return asSB(this)->onGetContext_deprecated(); |
337 | } |
338 | |
339 | GrRecordingContext* SkSurface::recordingContext() { |
340 | return asSB(this)->onGetRecordingContext(); |
341 | } |
342 | |
343 | GrBackendTexture SkSurface::getBackendTexture(BackendHandleAccess access) { |
344 | return asSB(this)->onGetBackendTexture(access); |
345 | } |
346 | |
347 | GrBackendRenderTarget SkSurface::getBackendRenderTarget(BackendHandleAccess access) { |
348 | return asSB(this)->onGetBackendRenderTarget(access); |
349 | } |
350 | |
351 | bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture, |
352 | GrSurfaceOrigin origin, ContentChangeMode mode, |
353 | TextureReleaseProc textureReleaseProc, |
354 | ReleaseContext releaseContext) { |
355 | return asSB(this)->onReplaceBackendTexture(backendTexture, origin, mode, textureReleaseProc, |
356 | releaseContext); |
357 | } |
358 | |
359 | GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) { |
360 | return asSB(this)->onFlush(access, flushInfo, nullptr); |
361 | } |
362 | |
363 | GrSemaphoresSubmitted SkSurface::flush(const GrFlushInfo& info, |
364 | const GrBackendSurfaceMutableState* newState) { |
365 | return asSB(this)->onFlush(BackendSurfaceAccess::kNoAccess, info, newState); |
366 | } |
367 | |
368 | bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores, |
369 | bool deleteSemaphoresAfterWait) { |
370 | return asSB(this)->onWait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait); |
371 | } |
372 | |
373 | bool SkSurface::characterize(SkSurfaceCharacterization* characterization) const { |
374 | return asConstSB(this)->onCharacterize(characterization); |
375 | } |
376 | |
377 | bool SkSurface::isCompatible(const SkSurfaceCharacterization& characterization) const { |
378 | return asConstSB(this)->onIsCompatible(characterization); |
379 | } |
380 | |
381 | bool SkSurface::draw(sk_sp<const SkDeferredDisplayList> ddl) { |
382 | return asSB(this)->onDraw(std::move(ddl)); |
383 | } |
384 | |
385 | ////////////////////////////////////////////////////////////////////////////////////// |
386 | #include "include/utils/SkNoDrawCanvas.h" |
387 | |
388 | class SkNullSurface : public SkSurface_Base { |
389 | public: |
390 | SkNullSurface(int width, int height) : SkSurface_Base(width, height, nullptr) {} |
391 | |
392 | protected: |
393 | SkCanvas* onNewCanvas() override { |
394 | return new SkNoDrawCanvas(this->width(), this->height()); |
395 | } |
396 | sk_sp<SkSurface> onNewSurface(const SkImageInfo& info) override { |
397 | return MakeNull(info.width(), info.height()); |
398 | } |
399 | sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; } |
400 | void onWritePixels(const SkPixmap&, int x, int y) override {} |
401 | void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {} |
402 | void onCopyOnWrite(ContentChangeMode) override {} |
403 | }; |
404 | |
405 | sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) { |
406 | if (width < 1 || height < 1) { |
407 | return nullptr; |
408 | } |
409 | return sk_sp<SkSurface>(new SkNullSurface(width, height)); |
410 | } |
411 | |
412 | ////////////////////////////////////////////////////////////////////////////////////// |
413 | |
414 | #if !SK_SUPPORT_GPU |
415 | |
416 | sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, SkBudgeted, const SkImageInfo&, |
417 | int, GrSurfaceOrigin, const SkSurfaceProps*, bool) { |
418 | return nullptr; |
419 | } |
420 | |
421 | sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, const SkSurfaceCharacterization&, |
422 | SkBudgeted) { |
423 | return nullptr; |
424 | } |
425 | |
426 | sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext*, const GrBackendTexture&, |
427 | GrSurfaceOrigin origin, int sampleCnt, |
428 | SkColorType, sk_sp<SkColorSpace>, |
429 | const SkSurfaceProps*, |
430 | TextureReleaseProc, ReleaseContext) { |
431 | return nullptr; |
432 | } |
433 | |
434 | sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext*, |
435 | const GrBackendRenderTarget&, |
436 | GrSurfaceOrigin origin, |
437 | SkColorType, |
438 | sk_sp<SkColorSpace>, |
439 | const SkSurfaceProps*, |
440 | RenderTargetReleaseProc, ReleaseContext) { |
441 | return nullptr; |
442 | } |
443 | |
444 | void SkSurface::flushAndSubmit() { |
445 | this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo()); |
446 | } |
447 | |
448 | #endif |
449 | |