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 "include/core/SkFontLCDConfig.h"
12#include "include/gpu/GrBackendSurface.h"
13#include "src/core/SkAutoPixmapStorage.h"
14#include "src/core/SkImagePriv.h"
15#include "src/image/SkSurface_Base.h"
16
17static SkPixelGeometry compute_default_geometry() {
18 SkFontLCDConfig::LCDOrder order = SkFontLCDConfig::GetSubpixelOrder();
19 if (SkFontLCDConfig::kNONE_LCDOrder == order) {
20 return kUnknown_SkPixelGeometry;
21 } else {
22 // Bit0 is RGB(0), BGR(1)
23 // Bit1 is H(0), V(1)
24 const SkPixelGeometry gGeo[] = {
25 kRGB_H_SkPixelGeometry,
26 kBGR_H_SkPixelGeometry,
27 kRGB_V_SkPixelGeometry,
28 kBGR_V_SkPixelGeometry,
29 };
30 int index = 0;
31 if (SkFontLCDConfig::kBGR_LCDOrder == order) {
32 index |= 1;
33 }
34 if (SkFontLCDConfig::kVertical_LCDOrientation == SkFontLCDConfig::GetSubpixelOrientation()){
35 index |= 2;
36 }
37 return gGeo[index];
38 }
39}
40
41SkSurfaceProps::SkSurfaceProps() : fFlags(0), fPixelGeometry(kUnknown_SkPixelGeometry) {}
42
43SkSurfaceProps::SkSurfaceProps(InitType) : fFlags(0), fPixelGeometry(compute_default_geometry()) {}
44
45SkSurfaceProps::SkSurfaceProps(uint32_t flags, InitType)
46 : fFlags(flags)
47 , fPixelGeometry(compute_default_geometry())
48{}
49
50SkSurfaceProps::SkSurfaceProps(uint32_t flags, SkPixelGeometry pg)
51 : fFlags(flags), fPixelGeometry(pg)
52{}
53
54SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps&) = default;
55SkSurfaceProps& SkSurfaceProps::operator=(const SkSurfaceProps&) = default;
56
57///////////////////////////////////////////////////////////////////////////////
58
59SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
60 : INHERITED(width, height, props) {
61}
62
63SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props)
64 : INHERITED(info, props) {
65}
66
67SkSurface_Base::~SkSurface_Base() {
68 // in case the canvas outsurvives us, we null the callback
69 if (fCachedCanvas) {
70 fCachedCanvas->setSurfaceBase(nullptr);
71 }
72}
73
74GrBackendTexture SkSurface_Base::onGetBackendTexture(BackendHandleAccess) {
75 return GrBackendTexture(); // invalid
76}
77
78GrBackendRenderTarget SkSurface_Base::onGetBackendRenderTarget(BackendHandleAccess) {
79 return GrBackendRenderTarget(); // invalid
80}
81
82bool SkSurface_Base::onReplaceBackendTexture(const GrBackendTexture&,
83 GrSurfaceOrigin, ContentChangeMode,
84 TextureReleaseProc,
85 ReleaseContext) {
86 return false;
87}
88
89void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
90 auto image = this->makeImageSnapshot();
91 if (image) {
92 canvas->drawImage(image, x, y, paint);
93 }
94}
95
96void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info, const SkIRect& srcRect,
97 SkSurface::RescaleGamma rescaleGamma,
98 SkFilterQuality rescaleQuality,
99 SkSurface::ReadPixelsCallback callback,
100 SkSurface::ReadPixelsContext context) {
101 int srcW = srcRect.width();
102 int srcH = srcRect.height();
103 float sx = (float)info.width() / srcW;
104 float sy = (float)info.height() / srcH;
105 // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
106 int stepsX;
107 int stepsY;
108 if (rescaleQuality > kNone_SkFilterQuality) {
109 stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
110 : std::floor(std::log2f(sx)));
111 stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
112 : std::floor(std::log2f(sy)));
113 } else {
114 stepsX = sx != 1.f;
115 stepsY = sy != 1.f;
116 }
117
118 SkPaint paint;
119 paint.setBlendMode(SkBlendMode::kSrc);
120 if (stepsX < 0 || stepsY < 0) {
121 // Don't trigger MIP generation. We don't currently have a way to trigger bicubic for
122 // downscaling draws.
123 rescaleQuality = std::min(rescaleQuality, kLow_SkFilterQuality);
124 }
125 paint.setFilterQuality(rescaleQuality);
126 sk_sp<SkSurface> src(SkRef(this));
127 int srcX = srcRect.fLeft;
128 int srcY = srcRect.fTop;
129 SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
130 // Assume we should ignore the rescale linear request if the surface has no color space since
131 // it's unclear how we'd linearize from an unknown color space.
132 if (rescaleGamma == SkSurface::RescaleGamma::kLinear &&
133 this->getCanvas()->imageInfo().colorSpace() &&
134 !this->getCanvas()->imageInfo().colorSpace()->gammaIsLinear()) {
135 auto cs = this->getCanvas()->imageInfo().colorSpace()->makeLinearGamma();
136 // Promote to F16 color type to preserve precision.
137 auto ii = SkImageInfo::Make(srcW, srcH, kRGBA_F16_SkColorType,
138 this->getCanvas()->imageInfo().alphaType(), std::move(cs));
139 auto linearSurf = this->makeSurface(ii);
140 if (!linearSurf) {
141 // Maybe F16 isn't supported? Try again with original color type.
142 ii = ii.makeColorType(this->getCanvas()->imageInfo().colorType());
143 linearSurf = this->makeSurface(ii);
144 if (!linearSurf) {
145 callback(context, nullptr);
146 return;
147 }
148 }
149 this->draw(linearSurf->getCanvas(), -srcX, -srcY, &paint);
150 src = std::move(linearSurf);
151 srcX = 0;
152 srcY = 0;
153 constraint = SkCanvas::kFast_SrcRectConstraint;
154 }
155 while (stepsX || stepsY) {
156 int nextW = info.width();
157 int nextH = info.height();
158 if (stepsX < 0) {
159 nextW = info.width() << (-stepsX - 1);
160 stepsX++;
161 } else if (stepsX != 0) {
162 if (stepsX > 1) {
163 nextW = srcW * 2;
164 }
165 --stepsX;
166 }
167 if (stepsY < 0) {
168 nextH = info.height() << (-stepsY - 1);
169 stepsY++;
170 } else if (stepsY != 0) {
171 if (stepsY > 1) {
172 nextH = srcH * 2;
173 }
174 --stepsY;
175 }
176 auto ii = src->getCanvas()->imageInfo().makeWH(nextW, nextH);
177 if (!stepsX && !stepsY) {
178 // Might as well fold conversion to final info in the last step.
179 ii = info;
180 }
181 auto next = this->makeSurface(ii);
182 if (!next) {
183 callback(context, nullptr);
184 return;
185 }
186 next->getCanvas()->drawImageRect(
187 src->makeImageSnapshot(), SkIRect::MakeXYWH(srcX, srcY, srcW, srcH),
188 SkRect::MakeWH((float)nextW, (float)nextH), &paint, constraint);
189 src = std::move(next);
190 srcX = srcY = 0;
191 srcW = nextW;
192 srcH = nextH;
193 constraint = SkCanvas::kFast_SrcRectConstraint;
194 }
195
196 size_t rowBytes = info.minRowBytes();
197 std::unique_ptr<char[]> data(new char[info.height() * rowBytes]);
198 SkPixmap pm(info, data.get(), rowBytes);
199 if (src->readPixels(pm, srcX, srcY)) {
200 class Result : public AsyncReadResult {
201 public:
202 Result(std::unique_ptr<const char[]> data, size_t rowBytes)
203 : fData(std::move(data)), fRowBytes(rowBytes) {}
204 int count() const override { return 1; }
205 const void* data(int i) const override { return fData.get(); }
206 size_t rowBytes(int i) const override { return fRowBytes; }
207
208 private:
209 std::unique_ptr<const char[]> fData;
210 size_t fRowBytes;
211 };
212 callback(context, std::make_unique<Result>(std::move(data), rowBytes));
213 } else {
214 callback(context, nullptr);
215 }
216}
217
218void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420(
219 SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
220 const SkISize& dstSize, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
221 ReadPixelsCallback callback, ReadPixelsContext context) {
222 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
223 // call client's callback.
224 callback(context, nullptr);
225}
226
227bool SkSurface_Base::outstandingImageSnapshot() const {
228 return fCachedImage && !fCachedImage->unique();
229}
230
231void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
232 this->dirtyGenerationID();
233
234 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
235
236 if (fCachedImage) {
237 // the surface may need to fork its backend, if its sharing it with
238 // the cached image. Note: we only call if there is an outstanding owner
239 // on the image (besides us).
240 bool unique = fCachedImage->unique();
241 if (!unique) {
242 this->onCopyOnWrite(mode);
243 }
244
245 // regardless of copy-on-write, we must drop our cached image now, so
246 // that the next request will get our new contents.
247 fCachedImage.reset();
248
249 if (unique) {
250 // Our content isn't held by any image now, so we can consider that content mutable.
251 // Raster surfaces need to be told it's safe to consider its pixels mutable again.
252 // We make this call after the ->unref() so the subclass can assert there are no images.
253 this->onRestoreBackingMutability();
254 }
255 } else if (kDiscard_ContentChangeMode == mode) {
256 this->onDiscard();
257 }
258}
259
260uint32_t SkSurface_Base::newGenerationID() {
261 SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
262 static std::atomic<uint32_t> nextID{1};
263 return nextID++;
264}
265
266static SkSurface_Base* asSB(SkSurface* surface) {
267 return static_cast<SkSurface_Base*>(surface);
268}
269
270static const SkSurface_Base* asConstSB(const SkSurface* surface) {
271 return static_cast<const SkSurface_Base*>(surface);
272}
273
274///////////////////////////////////////////////////////////////////////////////
275
276SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props)
277 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height)
278{
279 SkASSERT(fWidth > 0);
280 SkASSERT(fHeight > 0);
281 fGenerationID = 0;
282}
283
284SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props)
285 : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height())
286{
287 SkASSERT(fWidth > 0);
288 SkASSERT(fHeight > 0);
289 fGenerationID = 0;
290}
291
292SkImageInfo SkSurface::imageInfo() {
293 // TODO: do we need to go through canvas for this?
294 return this->getCanvas()->imageInfo();
295}
296
297uint32_t SkSurface::generationID() {
298 if (0 == fGenerationID) {
299 fGenerationID = asSB(this)->newGenerationID();
300 }
301 return fGenerationID;
302}
303
304void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
305 asSB(this)->aboutToDraw(mode);
306}
307
308SkCanvas* SkSurface::getCanvas() {
309 return asSB(this)->getCachedCanvas();
310}
311
312sk_sp<SkImage> SkSurface::makeImageSnapshot() {
313 return asSB(this)->refCachedImage();
314}
315
316sk_sp<SkImage> SkSurface::makeImageSnapshot(const SkIRect& srcBounds) {
317 const SkIRect surfBounds = { 0, 0, fWidth, fHeight };
318 SkIRect bounds = srcBounds;
319 if (!bounds.intersect(surfBounds)) {
320 return nullptr;
321 }
322 SkASSERT(!bounds.isEmpty());
323 if (bounds == surfBounds) {
324 return this->makeImageSnapshot();
325 } else {
326 return asSB(this)->onNewImageSnapshot(&bounds);
327 }
328}
329
330sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) {
331 return asSB(this)->onNewSurface(info);
332}
333
334sk_sp<SkSurface> SkSurface::makeSurface(int width, int height) {
335 return this->makeSurface(this->imageInfo().makeWH(width, height));
336}
337
338void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
339 const SkPaint* paint) {
340 return asSB(this)->onDraw(canvas, x, y, paint);
341}
342
343bool SkSurface::peekPixels(SkPixmap* pmap) {
344 return this->getCanvas()->peekPixels(pmap);
345}
346
347bool SkSurface::readPixels(const SkPixmap& pm, int srcX, int srcY) {
348 return this->getCanvas()->readPixels(pm, srcX, srcY);
349}
350
351bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
352 int srcX, int srcY) {
353 return this->readPixels({dstInfo, dstPixels, dstRowBytes}, srcX, srcY);
354}
355
356bool SkSurface::readPixels(const SkBitmap& bitmap, int srcX, int srcY) {
357 SkPixmap pm;
358 return bitmap.peekPixels(&pm) && this->readPixels(pm, srcX, srcY);
359}
360
361void SkSurface::asyncRescaleAndReadPixels(const SkImageInfo& info,
362 const SkIRect& srcRect,
363 RescaleGamma rescaleGamma,
364 SkFilterQuality rescaleQuality,
365 ReadPixelsCallback callback,
366 ReadPixelsContext context) {
367 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
368 !SkImageInfoIsValid(info)) {
369 callback(context, nullptr);
370 return;
371 }
372 asSB(this)->onAsyncRescaleAndReadPixels(
373 info, srcRect, rescaleGamma, rescaleQuality, callback, context);
374}
375
376void SkSurface::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
377 sk_sp<SkColorSpace> dstColorSpace,
378 const SkIRect& srcRect,
379 const SkISize& dstSize,
380 RescaleGamma rescaleGamma,
381 SkFilterQuality rescaleQuality,
382 ReadPixelsCallback callback,
383 ReadPixelsContext context) {
384 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
385 (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
386 callback(context, nullptr);
387 return;
388 }
389 asSB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
390 std::move(dstColorSpace),
391 srcRect,
392 dstSize,
393 rescaleGamma,
394 rescaleQuality,
395 callback,
396 context);
397}
398
399void SkSurface::writePixels(const SkPixmap& pmap, int x, int y) {
400 if (pmap.addr() == nullptr || pmap.width() <= 0 || pmap.height() <= 0) {
401 return;
402 }
403
404 const SkIRect srcR = SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height());
405 const SkIRect dstR = SkIRect::MakeWH(this->width(), this->height());
406 if (SkIRect::Intersects(srcR, dstR)) {
407 ContentChangeMode mode = kRetain_ContentChangeMode;
408 if (srcR.contains(dstR)) {
409 mode = kDiscard_ContentChangeMode;
410 }
411 asSB(this)->aboutToDraw(mode);
412 asSB(this)->onWritePixels(pmap, x, y);
413 }
414}
415
416void SkSurface::writePixels(const SkBitmap& src, int x, int y) {
417 SkPixmap pm;
418 if (src.peekPixels(&pm)) {
419 this->writePixels(pm, x, y);
420 }
421}
422
423GrBackendTexture SkSurface::getBackendTexture(BackendHandleAccess access) {
424 return asSB(this)->onGetBackendTexture(access);
425}
426
427GrBackendRenderTarget SkSurface::getBackendRenderTarget(BackendHandleAccess access) {
428 return asSB(this)->onGetBackendRenderTarget(access);
429}
430
431bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture,
432 GrSurfaceOrigin origin, ContentChangeMode mode,
433 TextureReleaseProc textureReleaseProc,
434 ReleaseContext releaseContext) {
435 return asSB(this)->onReplaceBackendTexture(backendTexture, origin, mode, textureReleaseProc,
436 releaseContext);
437}
438
439void SkSurface::flush() {
440 this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
441}
442
443GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) {
444 return asSB(this)->onFlush(access, flushInfo);
445}
446
447GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, GrFlushFlags flags,
448 int numSemaphores, GrBackendSemaphore signalSemaphores[],
449 GrGpuFinishedProc finishedProc,
450 GrGpuFinishedContext finishedContext) {
451 GrFlushInfo info;
452 info.fFlags = flags;
453 info.fNumSemaphores = numSemaphores;
454 info.fSignalSemaphores = signalSemaphores;
455 info.fFinishedProc = finishedProc;
456 info.fFinishedContext = finishedContext;
457 return this->flush(access, info);
458}
459
460GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, FlushFlags flags,
461 int numSemaphores, GrBackendSemaphore signalSemaphores[]) {
462 GrFlushFlags grFlags = flags == kSyncCpu_FlushFlag ? kSyncCpu_GrFlushFlag : kNone_GrFlushFlags;
463 GrFlushInfo info;
464 info.fFlags = grFlags;
465 info.fNumSemaphores = numSemaphores;
466 info.fSignalSemaphores = signalSemaphores;
467 return this->flush(access, info);
468}
469
470GrSemaphoresSubmitted SkSurface::flushAndSignalSemaphores(int numSemaphores,
471 GrBackendSemaphore signalSemaphores[]) {
472 GrFlushInfo info;
473 info.fNumSemaphores = numSemaphores;
474 info.fSignalSemaphores = signalSemaphores;
475 return this->flush(BackendSurfaceAccess::kNoAccess, info);
476}
477
478bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
479 return asSB(this)->onWait(numSemaphores, waitSemaphores);
480}
481
482bool SkSurface::characterize(SkSurfaceCharacterization* characterization) const {
483 return asConstSB(this)->onCharacterize(characterization);
484}
485
486bool SkSurface::isCompatible(const SkSurfaceCharacterization& characterization) const {
487 return asConstSB(this)->onIsCompatible(characterization);
488}
489
490bool SkSurface::draw(SkDeferredDisplayList* ddl) {
491 return asSB(this)->onDraw(ddl);
492}
493
494//////////////////////////////////////////////////////////////////////////////////////
495#include "include/utils/SkNoDrawCanvas.h"
496
497class SkNullSurface : public SkSurface_Base {
498public:
499 SkNullSurface(int width, int height) : SkSurface_Base(width, height, nullptr) {}
500
501protected:
502 SkCanvas* onNewCanvas() override {
503 return new SkNoDrawCanvas(this->width(), this->height());
504 }
505 sk_sp<SkSurface> onNewSurface(const SkImageInfo& info) override {
506 return MakeNull(info.width(), info.height());
507 }
508 sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
509 void onWritePixels(const SkPixmap&, int x, int y) override {}
510 void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {}
511 void onCopyOnWrite(ContentChangeMode) override {}
512};
513
514sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) {
515 if (width < 1 || height < 1) {
516 return nullptr;
517 }
518 return sk_sp<SkSurface>(new SkNullSurface(width, height));
519}
520
521//////////////////////////////////////////////////////////////////////////////////////
522
523#if !SK_SUPPORT_GPU
524
525sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, int,
526 GrSurfaceOrigin, const SkSurfaceProps*, bool) {
527 return nullptr;
528}
529
530sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext*, const SkSurfaceCharacterization&,
531 SkBudgeted) {
532 return nullptr;
533}
534
535sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext*, const GrBackendTexture&,
536 GrSurfaceOrigin origin, int sampleCnt,
537 SkColorType, sk_sp<SkColorSpace>,
538 const SkSurfaceProps*,
539 TextureReleaseProc, ReleaseContext) {
540 return nullptr;
541}
542
543sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext*,
544 const GrBackendRenderTarget&,
545 GrSurfaceOrigin origin,
546 SkColorType,
547 sk_sp<SkColorSpace>,
548 const SkSurfaceProps*,
549 RenderTargetReleaseProc, ReleaseContext) {
550 return nullptr;
551}
552
553sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext*,
554 const GrBackendTexture&,
555 GrSurfaceOrigin origin,
556 int sampleCnt,
557 SkColorType,
558 sk_sp<SkColorSpace>,
559 const SkSurfaceProps*) {
560 return nullptr;
561}
562
563#endif
564