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