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