• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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