2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkCapabilities.h"
12 #include "src/core/SkAutoPixmapStorage.h"
13 #include "src/core/SkImagePriv.h"
14 #include "src/core/SkPaintPriv.h"
15 #include "src/image/SkImage_Base.h"
16 #include "src/image/SkRescaleAndReadPixels.h"
17 #include "src/image/SkSurface_Base.h"
20 #include "include/gpu/GrBackendSurface.h"
23 SkSurfaceProps::SkSurfaceProps() : fFlags(0), fPixelGeometry(kUnknown_SkPixelGeometry) {}
25 SkSurfaceProps::SkSurfaceProps(uint32_t flags, SkPixelGeometry pg)
26 : fFlags(flags), fPixelGeometry(pg)
29 SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps&) = default;
30 SkSurfaceProps& SkSurfaceProps::operator=(const SkSurfaceProps&) = default;
32 ///////////////////////////////////////////////////////////////////////////////
34 SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
35 : INHERITED(width, height, props) {
38 SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props)
39 : INHERITED(info, props) {
42 SkSurface_Base::~SkSurface_Base() {
43 // in case the canvas outsurvives us, we null the callback
45 fCachedCanvas->setSurfaceBase(nullptr);
49 as_IB(fCachedImage.get())->generatingSurfaceIsDeleted();
54 GrRecordingContext* SkSurface_Base::onGetRecordingContext() {
58 skgpu::graphite::Recorder* SkSurface_Base::onGetRecorder() {
63 GrBackendTexture SkSurface_Base::onGetBackendTexture(BackendHandleAccess) {
64 return GrBackendTexture(); // invalid
67 GrBackendRenderTarget SkSurface_Base::onGetBackendRenderTarget(BackendHandleAccess) {
68 return GrBackendRenderTarget(); // invalid
71 bool SkSurface_Base::onReplaceBackendTexture(const GrBackendTexture&,
72 GrSurfaceOrigin, ContentChangeMode,
79 void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
80 const SkSamplingOptions& sampling, const SkPaint* paint) {
81 auto image = this->makeImageSnapshot();
83 canvas->drawImage(image.get(), x, y, sampling, paint);
87 void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
88 const SkIRect& origSrcRect,
89 SkSurface::RescaleGamma rescaleGamma,
90 RescaleMode rescaleMode,
91 SkSurface::ReadPixelsCallback callback,
92 SkSurface::ReadPixelsContext context) {
96 if (this->peekPixels(&peek)) {
97 src.installPixels(peek);
98 srcRect = origSrcRect;
100 src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
102 if (!this->readPixels(src, origSrcRect.x(), origSrcRect.y())) {
103 callback(context, nullptr);
106 srcRect = SkIRect::MakeSize(src.dimensions());
108 return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback,
112 void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420(
113 SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
114 const SkISize& dstSize, RescaleGamma rescaleGamma, RescaleMode,
115 ReadPixelsCallback callback, ReadPixelsContext context) {
116 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
117 // call client's callback.
118 callback(context, nullptr);
121 bool SkSurface_Base::outstandingImageSnapshot() const {
122 return fCachedImage && !fCachedImage->unique();
125 bool SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
126 this->dirtyGenerationID();
128 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
131 // the surface may need to fork its backend, if its sharing it with
132 // the cached image. Note: we only call if there is an outstanding owner
133 // on the image (besides us).
134 bool unique = fCachedImage->unique();
136 if (!this->onCopyOnWrite(mode)) {
141 // regardless of copy-on-write, we must drop our cached image now, so
142 // that the next request will get our new contents.
143 fCachedImage.reset();
146 // Our content isn't held by any image now, so we can consider that content mutable.
147 // Raster surfaces need to be told it's safe to consider its pixels mutable again.
148 // We make this call after the ->unref() so the subclass can assert there are no images.
149 this->onRestoreBackingMutability();
151 } else if (kDiscard_ContentChangeMode == mode) {
157 uint32_t SkSurface_Base::newGenerationID() {
158 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
159 static std::atomic<uint32_t> nextID{1};
160 return nextID.fetch_add(1, std::memory_order_relaxed);
163 sk_sp<const SkCapabilities> SkSurface_Base::onCapabilities() {
164 return SkCapabilities::RasterBackend();
167 static SkSurface_Base* asSB(SkSurface* surface) {
168 return static_cast<SkSurface_Base*>(surface);
171 static const SkSurface_Base* asConstSB(const SkSurface* surface) {
172 return static_cast<const SkSurface_Base*>(surface);
175 ///////////////////////////////////////////////////////////////////////////////
177 SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props)
178 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height)
180 SkASSERT(fWidth > 0);
181 SkASSERT(fHeight > 0);
185 SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props)
186 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height())
188 SkASSERT(fWidth > 0);
189 SkASSERT(fHeight > 0);
193 SkImageInfo SkSurface::imageInfo() {
194 // TODO: do we need to go through canvas for this?
195 return this->getCanvas()->imageInfo();
198 uint32_t SkSurface::generationID() {
199 if (0 == fGenerationID) {
200 fGenerationID = asSB(this)->newGenerationID();
202 return fGenerationID;
205 void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
206 sk_ignore_unused_variable(asSB(this)->aboutToDraw(mode));
209 SkCanvas* SkSurface::getCanvas() {
210 return asSB(this)->getCachedCanvas();
213 sk_sp<const SkCapabilities> SkSurface::capabilities() {
214 return asSB(this)->onCapabilities();
217 sk_sp<SkImage> SkSurface::makeImageSnapshot() {
218 return asSB(this)->refCachedImage();
221 sk_sp<SkImage> SkSurface::makeImageSnapshot(const SkIRect& srcBounds) {
222 const SkIRect surfBounds = { 0, 0, fWidth, fHeight };
223 SkIRect bounds = srcBounds;
224 if (!bounds.intersect(surfBounds)) {
227 SkASSERT(!bounds.isEmpty());
228 if (bounds == surfBounds) {
229 return this->makeImageSnapshot();
231 return asSB(this)->onNewImageSnapshot(&bounds);
235 sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) {
236 return asSB(this)->onNewSurface(info);
239 sk_sp<SkSurface> SkSurface::makeSurface(int width, int height) {
240 return this->makeSurface(this->imageInfo().makeWH(width, height));
243 void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling,
244 const SkPaint* paint) {
245 asSB(this)->onDraw(canvas, x, y, sampling, paint);
248 bool SkSurface::peekPixels(SkPixmap* pmap) {
249 return this->getCanvas()->peekPixels(pmap);
252 bool SkSurface::readPixels(const SkPixmap& pm, int srcX, int srcY) {
253 return this->getCanvas()->readPixels(pm, srcX, srcY);
256 bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
257 int srcX, int srcY) {
258 return this->readPixels({dstInfo, dstPixels, dstRowBytes}, srcX, srcY);
261 bool SkSurface::readPixels(const SkBitmap& bitmap, int srcX, int srcY) {
263 return bitmap.peekPixels(&pm) && this->readPixels(pm, srcX, srcY);
266 void SkSurface::asyncRescaleAndReadPixels(const SkImageInfo& info,
267 const SkIRect& srcRect,
268 RescaleGamma rescaleGamma,
269 RescaleMode rescaleMode,
270 ReadPixelsCallback callback,
271 ReadPixelsContext context) {
272 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
273 !SkImageInfoIsValid(info)) {
274 callback(context, nullptr);
277 asSB(this)->onAsyncRescaleAndReadPixels(
278 info, srcRect, rescaleGamma, rescaleMode, callback, context);
281 void SkSurface::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
282 sk_sp<SkColorSpace> dstColorSpace,
283 const SkIRect& srcRect,
284 const SkISize& dstSize,
285 RescaleGamma rescaleGamma,
286 RescaleMode rescaleMode,
287 ReadPixelsCallback callback,
288 ReadPixelsContext context) {
289 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
290 (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
291 callback(context, nullptr);
294 asSB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
295 std::move(dstColorSpace),
304 void SkSurface::writePixels(const SkPixmap& pmap, int x, int y) {
305 if (pmap.addr() == nullptr || pmap.width() <= 0 || pmap.height() <= 0) {
309 const SkIRect srcR = SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height());
310 const SkIRect dstR = SkIRect::MakeWH(this->width(), this->height());
311 if (SkIRect::Intersects(srcR, dstR)) {
312 ContentChangeMode mode = kRetain_ContentChangeMode;
313 if (srcR.contains(dstR)) {
314 mode = kDiscard_ContentChangeMode;
316 if (!asSB(this)->aboutToDraw(mode)) {
319 asSB(this)->onWritePixels(pmap, x, y);
323 void SkSurface::writePixels(const SkBitmap& src, int x, int y) {
325 if (src.peekPixels(&pm)) {
326 this->writePixels(pm, x, y);
330 GrRecordingContext* SkSurface::recordingContext() {
331 return asSB(this)->onGetRecordingContext();
334 skgpu::graphite::Recorder* SkSurface::recorder() {
335 return asSB(this)->onGetRecorder();
338 bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
339 bool deleteSemaphoresAfterWait) {
340 return asSB(this)->onWait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait);
343 bool SkSurface::characterize(SkSurfaceCharacterization* characterization) const {
344 return asConstSB(this)->onCharacterize(characterization);
347 bool SkSurface::isCompatible(const SkSurfaceCharacterization& characterization) const {
348 return asConstSB(this)->onIsCompatible(characterization);
351 bool SkSurface::draw(sk_sp<const SkDeferredDisplayList> ddl, int xOffset, int yOffset) {
352 if (xOffset != 0 || yOffset != 0) {
353 return false; // the offsets currently aren't supported
356 return asSB(this)->onDraw(std::move(ddl), { xOffset, yOffset });
360 GrBackendTexture SkSurface::getBackendTexture(BackendHandleAccess access) {
361 return asSB(this)->onGetBackendTexture(access);
364 GrBackendRenderTarget SkSurface::getBackendRenderTarget(BackendHandleAccess access) {
365 return asSB(this)->onGetBackendRenderTarget(access);
368 bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture,
369 GrSurfaceOrigin origin, ContentChangeMode mode,
370 TextureReleaseProc textureReleaseProc,
371 ReleaseContext releaseContext) {
372 return asSB(this)->onReplaceBackendTexture(backendTexture, origin, mode, textureReleaseProc,
376 void SkSurface::resolveMSAA() {
377 asSB(this)->onResolveMSAA();
380 GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) {
381 return asSB(this)->onFlush(access, flushInfo, nullptr);
384 GrSemaphoresSubmitted SkSurface::flush(const GrFlushInfo& info,
385 const GrBackendSurfaceMutableState* newState) {
386 return asSB(this)->onFlush(BackendSurfaceAccess::kNoAccess, info, newState);
389 void SkSurface::flush() {
393 void SkSurface::flush() {} // Flush is a no-op for CPU surfaces
395 void SkSurface::flushAndSubmit(bool syncCpu) {}
397 // TODO(kjlubick, scroggo) Remove this once Android is updated.
398 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, SkBudgeted, const SkImageInfo&,
399 int, GrSurfaceOrigin, const SkSurfaceProps*, bool) {
404 //////////////////////////////////////////////////////////////////////////////////////
405 #include "include/utils/SkNoDrawCanvas.h"
407 class SkNullSurface : public SkSurface_Base {
409 SkNullSurface(int width, int height) : SkSurface_Base(width, height, nullptr) {}
412 SkCanvas* onNewCanvas() override {
413 return new SkNoDrawCanvas(this->width(), this->height());
415 sk_sp<SkSurface> onNewSurface(const SkImageInfo& info) override {
416 return MakeNull(info.width(), info.height());
418 sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
419 void onWritePixels(const SkPixmap&, int x, int y) override {}
420 void onDraw(SkCanvas*, SkScalar, SkScalar, const SkSamplingOptions&, const SkPaint*) override {}
421 bool onCopyOnWrite(ContentChangeMode) override { return true; }
422 sk_sp<const SkCapabilities> onCapabilities() override {
423 // Not really, but we have to return *something*
424 return SkCapabilities::RasterBackend();
428 sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) {
429 if (width < 1 || height < 1) {
432 return sk_sp<SkSurface>(new SkNullSurface(width, height));
435 //////////////////////////////////////////////////////////////////////////////////////