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