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