Reland "Avoid crash when surface CoW allocation fails"
On low memory machines a common cause of crashes is when a draw
operation requires a large layer (or many large layers) because an
implementation of SkSurface_Base::onCopyOnWrite does not actually have
the resources available to do the copy when required by a draw. Allow
this method to fail and percolate up the call chain so that the draw
simply does not happen instead of crashing.
It appears some users are creating their own subclasses of
SkSurface_Base for their tests. Add SK_SURFACE_COPY_ON_WRITE_CRASHES to
keep the old crashy behavior until they can be updated.
Bug: chromium:1116362
Revert: 5b19ebe0c5
.
Revert-Change-Id: I2873589f996ded9c9fd6d27b19155ca18d5b5326
Revert-Reviewed-on: https://skia-review.googlesource.com/c/skia/+/463956
Change-Id: Id06d1e6d3aacb409a3b00b9a862bd8ddd1aaa22f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/464456
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
f2d016f12e
commit
4b38d9c437
@ -36,6 +36,10 @@ sk_sp<SkImage> Surface_Graphite::onNewImageSnapshot(const SkIRect* subset) {
|
|||||||
|
|
||||||
void Surface_Graphite::onWritePixels(const SkPixmap&, int x, int y) {}
|
void Surface_Graphite::onWritePixels(const SkPixmap&, int x, int y) {}
|
||||||
|
|
||||||
void Surface_Graphite::onCopyOnWrite(ContentChangeMode) {}
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
|
void Surface_Graphite::onCopyOnWrite(ContentChangeMode) { }
|
||||||
|
#else
|
||||||
|
bool Surface_Graphite::onCopyOnWrite(ContentChangeMode) { return true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace skgpu
|
} // namespace skgpu
|
||||||
|
@ -23,7 +23,11 @@ public:
|
|||||||
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
|
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
|
||||||
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
|
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
|
||||||
void onWritePixels(const SkPixmap&, int x, int y) override;
|
void onWritePixels(const SkPixmap&, int x, int y) override;
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void onCopyOnWrite(ContentChangeMode) override;
|
void onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#else
|
||||||
|
bool onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sk_sp<Device> fDevice;
|
sk_sp<Device> fDevice;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#define SK_SUPPORT_LEGACY_GETTOTALMATRIX
|
#define SK_SUPPORT_LEGACY_GETTOTALMATRIX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class AutoLayerForImageFilter;
|
||||||
class GrBackendRenderTarget;
|
class GrBackendRenderTarget;
|
||||||
class GrRecordingContext;
|
class GrRecordingContext;
|
||||||
class SkBaseDevice;
|
class SkBaseDevice;
|
||||||
@ -63,6 +64,10 @@ class SkSurface_Base;
|
|||||||
class SkTextBlob;
|
class SkTextBlob;
|
||||||
class SkVertices;
|
class SkVertices;
|
||||||
|
|
||||||
|
namespace skstd {
|
||||||
|
template<typename T> class optional;
|
||||||
|
}
|
||||||
|
|
||||||
/** \class SkCanvas
|
/** \class SkCanvas
|
||||||
SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed.
|
SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed.
|
||||||
SkCanvas contains a stack of SkMatrix and clip values.
|
SkCanvas contains a stack of SkMatrix and clip values.
|
||||||
@ -2283,8 +2288,21 @@ private:
|
|||||||
|
|
||||||
// notify our surface (if we have one) that we are about to draw, so it
|
// notify our surface (if we have one) that we are about to draw, so it
|
||||||
// can perform copy-on-write or invalidate any cached images
|
// can perform copy-on-write or invalidate any cached images
|
||||||
void predrawNotify(bool willOverwritesEntireSurface = false);
|
// returns false if the copy failed
|
||||||
void predrawNotify(const SkRect* rect, const SkPaint* paint, ShaderOverrideOpacity);
|
bool SK_WARN_UNUSED_RESULT predrawNotify(bool willOverwritesEntireSurface = false);
|
||||||
|
bool SK_WARN_UNUSED_RESULT predrawNotify(const SkRect*, const SkPaint*, ShaderOverrideOpacity);
|
||||||
|
|
||||||
|
enum class CheckForOverwrite : bool {
|
||||||
|
kNo = false,
|
||||||
|
kYes = true
|
||||||
|
};
|
||||||
|
// call the appropriate predrawNotify and create a layer if needed.
|
||||||
|
skstd::optional<AutoLayerForImageFilter> aboutToDraw(
|
||||||
|
SkCanvas* canvas,
|
||||||
|
const SkPaint& paint,
|
||||||
|
const SkRect* rawBounds = nullptr,
|
||||||
|
CheckForOverwrite = CheckForOverwrite::kNo,
|
||||||
|
ShaderOverrideOpacity = kNone_ShaderOverrideOpacity);
|
||||||
|
|
||||||
// The bottom-most device in the stack, only changed by init(). Image properties and the final
|
// The bottom-most device in the stack, only changed by init(). Image properties and the final
|
||||||
// canvas pixels are determined by this device.
|
// canvas pixels are determined by this device.
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "include/core/SkTextBlob.h"
|
#include "include/core/SkTextBlob.h"
|
||||||
#include "include/core/SkVertices.h"
|
#include "include/core/SkVertices.h"
|
||||||
#include "include/effects/SkRuntimeEffect.h"
|
#include "include/effects/SkRuntimeEffect.h"
|
||||||
|
#include "include/private/SkTOptional.h"
|
||||||
#include "include/private/SkTo.h"
|
#include "include/private/SkTo.h"
|
||||||
#include "include/utils/SkNoDrawCanvas.h"
|
#include "include/utils/SkNoDrawCanvas.h"
|
||||||
#include "src/core/SkArenaAlloc.h"
|
#include "src/core/SkArenaAlloc.h"
|
||||||
@ -155,15 +156,18 @@ bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* pa
|
|||||||
#define dec_canvas()
|
#define dec_canvas()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
|
bool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
|
||||||
if (fSurfaceBase) {
|
if (fSurfaceBase) {
|
||||||
fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
|
if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
|
||||||
? SkSurface::kDiscard_ContentChangeMode
|
? SkSurface::kDiscard_ContentChangeMode
|
||||||
: SkSurface::kRetain_ContentChangeMode);
|
: SkSurface::kRetain_ContentChangeMode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
|
bool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
|
||||||
ShaderOverrideOpacity overrideOpacity) {
|
ShaderOverrideOpacity overrideOpacity) {
|
||||||
if (fSurfaceBase) {
|
if (fSurfaceBase) {
|
||||||
SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
|
SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
|
||||||
@ -176,21 +180,15 @@ void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
|
|||||||
mode = SkSurface::kDiscard_ContentChangeMode;
|
mode = SkSurface::kDiscard_ContentChangeMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fSurfaceBase->aboutToDraw(mode);
|
if (!fSurfaceBase->aboutToDraw(mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
enum class CheckForOverwrite : bool {
|
|
||||||
kNo = false,
|
|
||||||
kYes = true
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
SkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device,
|
SkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device,
|
||||||
sk_sp<SkImageFilter> imageFilter,
|
sk_sp<SkImageFilter> imageFilter,
|
||||||
const SkPaint& paint)
|
const SkPaint& paint)
|
||||||
@ -304,21 +302,12 @@ public:
|
|||||||
// Draw functions should use layer->paint() instead of the passed-in paint.
|
// Draw functions should use layer->paint() instead of the passed-in paint.
|
||||||
AutoLayerForImageFilter(SkCanvas* canvas,
|
AutoLayerForImageFilter(SkCanvas* canvas,
|
||||||
const SkPaint& paint,
|
const SkPaint& paint,
|
||||||
const SkRect* rawBounds = nullptr,
|
const SkRect* rawBounds = nullptr)
|
||||||
CheckForOverwrite checkOverwrite = CheckForOverwrite::kNo,
|
|
||||||
SkCanvas::ShaderOverrideOpacity overrideOpacity =
|
|
||||||
SkCanvas::kNone_ShaderOverrideOpacity)
|
|
||||||
: fPaint(paint)
|
: fPaint(paint)
|
||||||
, fCanvas(canvas)
|
, fCanvas(canvas)
|
||||||
, fTempLayerForImageFilter(false) {
|
, fTempLayerForImageFilter(false) {
|
||||||
SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
|
SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
|
||||||
|
|
||||||
if (checkOverwrite == CheckForOverwrite::kYes) {
|
|
||||||
canvas->predrawNotify(rawBounds, &fPaint, overrideOpacity);
|
|
||||||
} else {
|
|
||||||
canvas->predrawNotify();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) {
|
if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) {
|
||||||
// The draw paint has an image filter that couldn't be simplified to an equivalent
|
// The draw paint has an image filter that couldn't be simplified to an equivalent
|
||||||
// color filter, so we have to inject an automatic saveLayer().
|
// color filter, so we have to inject an automatic saveLayer().
|
||||||
@ -344,6 +333,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete;
|
||||||
|
AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete;
|
||||||
|
AutoLayerForImageFilter(AutoLayerForImageFilter&&) = default;
|
||||||
|
AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&) = default;
|
||||||
|
|
||||||
~AutoLayerForImageFilter() {
|
~AutoLayerForImageFilter() {
|
||||||
if (fTempLayerForImageFilter) {
|
if (fTempLayerForImageFilter) {
|
||||||
fCanvas->internalRestore();
|
fCanvas->internalRestore();
|
||||||
@ -361,6 +355,25 @@ private:
|
|||||||
SkDEBUGCODE(int fSaveCount;)
|
SkDEBUGCODE(int fSaveCount;)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
skstd::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw(
|
||||||
|
SkCanvas* canvas,
|
||||||
|
const SkPaint& paint,
|
||||||
|
const SkRect* rawBounds,
|
||||||
|
CheckForOverwrite checkOverwrite,
|
||||||
|
ShaderOverrideOpacity overrideOpacity)
|
||||||
|
{
|
||||||
|
if (checkOverwrite == CheckForOverwrite::kYes) {
|
||||||
|
if (!this->predrawNotify(rawBounds, &paint, overrideOpacity)) {
|
||||||
|
return skstd::nullopt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!this->predrawNotify()) {
|
||||||
|
return skstd::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return skstd::optional<AutoLayerForImageFilter>(canvas, paint, rawBounds);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
|
void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
|
||||||
@ -545,9 +558,10 @@ bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tell our owning surface to bump its generation ID.
|
// Tell our owning surface to bump its generation ID.
|
||||||
const bool completeOverwrite =
|
const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions();
|
||||||
srcRect.size() == SkISize::Make(device->width(), device->height());
|
if (!this->predrawNotify(completeOverwrite)) {
|
||||||
this->predrawNotify(completeOverwrite);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// This can still fail, most notably in the case of a invalid color type or alpha type
|
// This can still fail, most notably in the case of a invalid color type or alpha type
|
||||||
// conversion. We could pull those checks into this function and avoid the unnecessary
|
// conversion. We could pull those checks into this function and avoid the unnecessary
|
||||||
@ -1210,21 +1224,21 @@ void SkCanvas::internalRestore() {
|
|||||||
|
|
||||||
// Don't go through AutoLayerForImageFilter since device draws are so closely tied to
|
// Don't go through AutoLayerForImageFilter since device draws are so closely tied to
|
||||||
// internalSaveLayer and internalRestore.
|
// internalSaveLayer and internalRestore.
|
||||||
this->predrawNotify();
|
if (this->predrawNotify()) {
|
||||||
|
SkBaseDevice* dstDev = this->topDevice();
|
||||||
SkBaseDevice* dstDev = this->topDevice();
|
if (layer->fImageFilter) {
|
||||||
if (layer->fImageFilter) {
|
this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src
|
||||||
this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src
|
dstDev, // dst
|
||||||
dstDev, // dst
|
layer->fImageFilter.get(),
|
||||||
layer->fImageFilter.get(),
|
layer->fPaint,
|
||||||
layer->fPaint,
|
DeviceCompatibleWithFilter::kYes);
|
||||||
DeviceCompatibleWithFilter::kYes);
|
} else {
|
||||||
} else {
|
// NOTE: We don't just call internalDrawDeviceWithFilter with a null filter
|
||||||
// NOTE: We don't just call internalDrawDeviceWithFilter with a null filter
|
// because we want to take advantage of overridden drawDevice functions for
|
||||||
// because we want to take advantage of overridden drawDevice functions for
|
// document-based devices.
|
||||||
// document-based devices.
|
SkSamplingOptions sampling;
|
||||||
SkSamplingOptions sampling;
|
dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint);
|
||||||
dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1895,7 +1909,9 @@ void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec
|
|||||||
void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
|
void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||||
// We don't test quickReject because the shadow outsets the path's bounds.
|
// We don't test quickReject because the shadow outsets the path's bounds.
|
||||||
// TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
|
// TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
|
||||||
this->predrawNotify();
|
if (!this->predrawNotify()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this->topDevice()->drawShadow(path, rec);
|
this->topDevice()->drawShadow(path, rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1924,7 +1940,7 @@ void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], i
|
|||||||
|
|
||||||
void SkCanvas::onDiscard() {
|
void SkCanvas::onDiscard() {
|
||||||
if (fSurfaceBase) {
|
if (fSurfaceBase) {
|
||||||
fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
|
sk_ignore_unused_variable(fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1939,8 +1955,10 @@ void SkCanvas::internalDrawPaint(const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, nullptr, CheckForOverwrite::kYes);
|
auto layer = this->aboutToDraw(this, paint, nullptr, CheckForOverwrite::kYes);
|
||||||
this->topDevice()->drawPaint(layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawPaint(layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
|
void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
|
||||||
@ -1965,8 +1983,10 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, strokePaint, &bounds);
|
auto layer = this->aboutToDraw(this, strokePaint, &bounds);
|
||||||
this->topDevice()->drawPoints(mode, count, pts, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawPoints(mode, count, pts, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
|
void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
|
||||||
@ -1975,8 +1995,10 @@ void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &r, CheckForOverwrite::kYes);
|
auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes);
|
||||||
this->topDevice()->drawRect(r, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawRect(r, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
|
void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
|
||||||
@ -1985,8 +2007,10 @@ void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &bounds);
|
auto layer = this->aboutToDraw(this, paint, &bounds);
|
||||||
this->topDevice()->drawRegion(region, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawRegion(region, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawBehind(const SkPaint& paint) {
|
void SkCanvas::onDrawBehind(const SkPaint& paint) {
|
||||||
@ -2025,8 +2049,10 @@ void SkCanvas::onDrawBehind(const SkPaint& paint) {
|
|||||||
// ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
|
// ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint);
|
auto layer = this->aboutToDraw(this, paint);
|
||||||
this->topDevice()->drawPaint(layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawPaint(layer->paint());
|
||||||
|
}
|
||||||
|
|
||||||
dev->restore(fMCRec->fMatrix);
|
dev->restore(fMCRec->fMatrix);
|
||||||
}
|
}
|
||||||
@ -2037,8 +2063,10 @@ void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &oval);
|
auto layer = this->aboutToDraw(this, paint, &oval);
|
||||||
this->topDevice()->drawOval(oval, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawOval(oval, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
|
void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
|
||||||
@ -2049,8 +2077,10 @@ void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &oval);
|
auto layer = this->aboutToDraw(this, paint, &oval);
|
||||||
this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
||||||
@ -2071,8 +2101,10 @@ void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &bounds);
|
auto layer = this->aboutToDraw(this, paint, &bounds);
|
||||||
this->topDevice()->drawRRect(rrect, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawRRect(rrect, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
|
void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
|
||||||
@ -2081,8 +2113,10 @@ void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const Sk
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &bounds);
|
auto layer = this->aboutToDraw(this, paint, &bounds);
|
||||||
this->topDevice()->drawDRRect(outer, inner, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawDRRect(outer, inner, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
||||||
@ -2099,8 +2133,10 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, paint, &pathBounds);
|
auto layer = this->aboutToDraw(this, paint, &pathBounds);
|
||||||
this->topDevice()->drawPath(path, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawPath(path, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h,
|
bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h,
|
||||||
@ -2183,15 +2219,18 @@ void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
|
|||||||
layerToDevice.preTranslate(x, y);
|
layerToDevice.preTranslate(x, y);
|
||||||
skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y));
|
skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y));
|
||||||
|
|
||||||
this->predrawNotify();
|
if (this->predrawNotify()) {
|
||||||
device->drawFilteredImage(mapping, special.get(), filter.get(), sampling, realPaint);
|
device->drawFilteredImage(mapping, special.get(), filter.get(), sampling,realPaint);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} // else fall through to regular drawing path
|
} // else fall through to regular drawing path
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, realPaint, &bounds);
|
auto layer = this->aboutToDraw(this, realPaint, &bounds);
|
||||||
this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
|
if (layer) {
|
||||||
layer.paint(), kStrict_SrcRectConstraint);
|
this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
|
||||||
|
layer->paint(), kStrict_SrcRectConstraint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
|
void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
|
||||||
@ -2203,10 +2242,12 @@ void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const S
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, realPaint, &dst, CheckForOverwrite::kYes,
|
auto layer = this->aboutToDraw(this, realPaint, &dst, CheckForOverwrite::kYes,
|
||||||
image->isOpaque() ? kOpaque_ShaderOverrideOpacity
|
image->isOpaque() ? kOpaque_ShaderOverrideOpacity
|
||||||
: kNotOpaque_ShaderOverrideOpacity);
|
: kNotOpaque_ShaderOverrideOpacity);
|
||||||
this->topDevice()->drawImageRect(image, &src, dst, sampling, layer.paint(), constraint);
|
if (layer) {
|
||||||
|
this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
|
void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
|
||||||
@ -2217,8 +2258,10 @@ void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, realPaint, &dst);
|
auto layer = this->aboutToDraw(this, realPaint, &dst);
|
||||||
this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y,
|
void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y,
|
||||||
@ -2256,8 +2299,10 @@ void SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPa
|
|||||||
if (this->internalQuickReject(bounds, paint)) {
|
if (this->internalQuickReject(bounds, paint)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AutoLayerForImageFilter layer(this, paint, &bounds);
|
auto layer = this->aboutToDraw(this, paint, &bounds);
|
||||||
this->topDevice()->drawGlyphRunList(glyphRunList, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawGlyphRunList(glyphRunList, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These call the (virtual) onDraw... method
|
// These call the (virtual) onDraw... method
|
||||||
@ -2369,8 +2414,10 @@ void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmod
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, simplePaint, &bounds);
|
auto layer = this->aboutToDraw(this, simplePaint, &bounds);
|
||||||
this->topDevice()->drawVertices(vertices, bmode, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawVertices(vertices, bmode, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
||||||
@ -2398,8 +2445,10 @@ void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, simplePaint, &bounds);
|
auto layer = this->aboutToDraw(this, simplePaint, &bounds);
|
||||||
this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
|
void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
|
||||||
@ -2429,8 +2478,9 @@ void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
|
|||||||
void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
|
void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
|
||||||
// drawable bounds are no longer reliable (e.g. android displaylist)
|
// drawable bounds are no longer reliable (e.g. android displaylist)
|
||||||
// so don't use them for quick-reject
|
// so don't use them for quick-reject
|
||||||
this->predrawNotify();
|
if (this->predrawNotify()) {
|
||||||
this->topDevice()->drawDrawable(dr, matrix, this);
|
this->topDevice()->drawDrawable(dr, matrix, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
|
void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
|
||||||
@ -2445,15 +2495,18 @@ void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, realPaint);
|
auto layer = this->aboutToDraw(this, realPaint);
|
||||||
this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer.paint());
|
if (layer) {
|
||||||
|
this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer->paint());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
|
void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
|
||||||
SkASSERT(key);
|
SkASSERT(key);
|
||||||
|
|
||||||
this->predrawNotify();
|
if (this->predrawNotify()) {
|
||||||
this->topDevice()->drawAnnotation(rect, key, value);
|
this->topDevice()->drawAnnotation(rect, key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
|
void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
|
||||||
@ -2466,8 +2519,9 @@ void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->predrawNotify();
|
if (this->predrawNotify()) {
|
||||||
this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
|
this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
|
void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
|
||||||
@ -2507,9 +2561,11 @@ void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLayerForImageFilter layer(this, realPaint, setBoundsValid ? &setBounds : nullptr);
|
auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr);
|
||||||
this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
|
if (layer) {
|
||||||
layer.paint(), constraint);
|
this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
|
||||||
|
layer->paint(), constraint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -102,7 +102,7 @@ private:
|
|||||||
size_t addDraw(DrawType drawType, size_t* size) {
|
size_t addDraw(DrawType drawType, size_t* size) {
|
||||||
size_t offset = fWriter.bytesWritten();
|
size_t offset = fWriter.bytesWritten();
|
||||||
|
|
||||||
this->predrawNotify();
|
SkASSERT_RELEASE(this->predrawNotify());
|
||||||
|
|
||||||
SkASSERT(0 != *size);
|
SkASSERT(0 != *size);
|
||||||
SkASSERT(((uint8_t) drawType) == drawType);
|
SkASSERT(((uint8_t) drawType) == drawType);
|
||||||
|
@ -117,7 +117,7 @@ bool SkSurface_Base::outstandingImageSnapshot() const {
|
|||||||
return fCachedImage && !fCachedImage->unique();
|
return fCachedImage && !fCachedImage->unique();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
|
bool SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
|
||||||
this->dirtyGenerationID();
|
this->dirtyGenerationID();
|
||||||
|
|
||||||
SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
|
SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
|
||||||
@ -128,7 +128,13 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
|
|||||||
// on the image (besides us).
|
// on the image (besides us).
|
||||||
bool unique = fCachedImage->unique();
|
bool unique = fCachedImage->unique();
|
||||||
if (!unique) {
|
if (!unique) {
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
this->onCopyOnWrite(mode);
|
this->onCopyOnWrite(mode);
|
||||||
|
#else
|
||||||
|
if (!this->onCopyOnWrite(mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// regardless of copy-on-write, we must drop our cached image now, so
|
// regardless of copy-on-write, we must drop our cached image now, so
|
||||||
@ -144,6 +150,7 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
|
|||||||
} else if (kDiscard_ContentChangeMode == mode) {
|
} else if (kDiscard_ContentChangeMode == mode) {
|
||||||
this->onDiscard();
|
this->onDiscard();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SkSurface_Base::newGenerationID() {
|
uint32_t SkSurface_Base::newGenerationID() {
|
||||||
@ -191,7 +198,7 @@ uint32_t SkSurface::generationID() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
|
void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
|
||||||
asSB(this)->aboutToDraw(mode);
|
sk_ignore_unused_variable(asSB(this)->aboutToDraw(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
SkCanvas* SkSurface::getCanvas() {
|
SkCanvas* SkSurface::getCanvas() {
|
||||||
@ -297,7 +304,9 @@ void SkSurface::writePixels(const SkPixmap& pmap, int x, int y) {
|
|||||||
if (srcR.contains(dstR)) {
|
if (srcR.contains(dstR)) {
|
||||||
mode = kDiscard_ContentChangeMode;
|
mode = kDiscard_ContentChangeMode;
|
||||||
}
|
}
|
||||||
asSB(this)->aboutToDraw(mode);
|
if (!asSB(this)->aboutToDraw(mode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
asSB(this)->onWritePixels(pmap, x, y);
|
asSB(this)->onWritePixels(pmap, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,7 +395,11 @@ protected:
|
|||||||
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
|
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
|
||||||
void onWritePixels(const SkPixmap&, int x, int y) override {}
|
void onWritePixels(const SkPixmap&, int x, int y) override {}
|
||||||
void onDraw(SkCanvas*, SkScalar, SkScalar, const SkSamplingOptions&, const SkPaint*) override {}
|
void onDraw(SkCanvas*, SkScalar, SkScalar, const SkSamplingOptions&, const SkPaint*) override {}
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void onCopyOnWrite(ContentChangeMode) override {}
|
void onCopyOnWrite(ContentChangeMode) override {}
|
||||||
|
#else
|
||||||
|
bool onCopyOnWrite(ContentChangeMode) override { return true; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) {
|
sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) {
|
||||||
|
@ -107,8 +107,14 @@ public:
|
|||||||
* If the surface is about to change, we call this so that our subclass
|
* If the surface is about to change, we call this so that our subclass
|
||||||
* can optionally fork their backend (copy-on-write) in case it was
|
* can optionally fork their backend (copy-on-write) in case it was
|
||||||
* being shared with the cachedImage.
|
* being shared with the cachedImage.
|
||||||
|
*
|
||||||
|
* Returns false if the backing cannot be un-shared.
|
||||||
*/
|
*/
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
virtual void onCopyOnWrite(ContentChangeMode) = 0;
|
virtual void onCopyOnWrite(ContentChangeMode) = 0;
|
||||||
|
#else
|
||||||
|
virtual bool SK_WARN_UNUSED_RESULT onCopyOnWrite(ContentChangeMode) = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal the surface to remind its backing store that it's mutable again.
|
* Signal the surface to remind its backing store that it's mutable again.
|
||||||
@ -144,7 +150,8 @@ private:
|
|||||||
std::unique_ptr<SkCanvas> fCachedCanvas;
|
std::unique_ptr<SkCanvas> fCachedCanvas;
|
||||||
sk_sp<SkImage> fCachedImage;
|
sk_sp<SkImage> fCachedImage;
|
||||||
|
|
||||||
void aboutToDraw(ContentChangeMode mode);
|
// Returns false if drawing should not take place (allocation failure).
|
||||||
|
bool SK_WARN_UNUSED_RESULT aboutToDraw(ContentChangeMode mode);
|
||||||
|
|
||||||
// Returns true if there is an outstanding image-snapshot, indicating that a call to aboutToDraw
|
// Returns true if there is an outstanding image-snapshot, indicating that a call to aboutToDraw
|
||||||
// would trigger a copy-on-write.
|
// would trigger a copy-on-write.
|
||||||
|
@ -187,6 +187,7 @@ void SkSurface_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSp
|
|||||||
// Create a new render target and, if necessary, copy the contents of the old
|
// Create a new render target and, if necessary, copy the contents of the old
|
||||||
// render target into it. Note that this flushes the SkGpuDevice but
|
// render target into it. Note that this flushes the SkGpuDevice but
|
||||||
// doesn't force an OpenGL flush.
|
// doesn't force an OpenGL flush.
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
|
void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
|
||||||
GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
|
GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
|
||||||
|
|
||||||
@ -201,6 +202,25 @@ void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
|
|||||||
this->SkSurface_Gpu::onDiscard();
|
this->SkSurface_Gpu::onDiscard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
bool SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
|
||||||
|
GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
|
||||||
|
|
||||||
|
// are we sharing our backing proxy with the image? Note this call should never create a new
|
||||||
|
// image because onCopyOnWrite is only called when there is a cached image.
|
||||||
|
sk_sp<SkImage> image = this->refCachedImage();
|
||||||
|
SkASSERT(image);
|
||||||
|
|
||||||
|
if (static_cast<SkImage_Gpu*>(image.get())->surfaceMustCopyOnWrite(readSurfaceView.proxy())) {
|
||||||
|
if (!fDevice->replaceBackingProxy(mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (kDiscard_ContentChangeMode == mode) {
|
||||||
|
this->SkSurface_Gpu::onDiscard();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void SkSurface_Gpu::onDiscard() { fDevice->discard(); }
|
void SkSurface_Gpu::onDiscard() { fDevice->discard(); }
|
||||||
|
|
||||||
|
@ -44,8 +44,11 @@ public:
|
|||||||
RescaleMode,
|
RescaleMode,
|
||||||
ReadPixelsCallback callback,
|
ReadPixelsCallback callback,
|
||||||
ReadPixelsContext context) override;
|
ReadPixelsContext context) override;
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void onCopyOnWrite(ContentChangeMode) override;
|
void onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#else
|
||||||
|
bool onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#endif
|
||||||
void onDiscard() override;
|
void onDiscard() override;
|
||||||
GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo& info,
|
GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo& info,
|
||||||
const GrBackendSurfaceMutableState*) override;
|
const GrBackendSurfaceMutableState*) override;
|
||||||
|
@ -24,7 +24,11 @@ public:
|
|||||||
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
|
sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
|
||||||
void onWritePixels(const SkPixmap&, int x, int y) override;
|
void onWritePixels(const SkPixmap&, int x, int y) override;
|
||||||
void onDraw(SkCanvas*, SkScalar, SkScalar, const SkSamplingOptions&, const SkPaint*) override;
|
void onDraw(SkCanvas*, SkScalar, SkScalar, const SkSamplingOptions&, const SkPaint*) override;
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void onCopyOnWrite(ContentChangeMode) override;
|
void onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#else
|
||||||
|
bool onCopyOnWrite(ContentChangeMode) override;
|
||||||
|
#endif
|
||||||
void onRestoreBackingMutability() override;
|
void onRestoreBackingMutability() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -124,6 +128,7 @@ void SkSurface_Raster::onRestoreBackingMutability() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
|
||||||
void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
|
void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
|
||||||
// are we sharing pixelrefs with the image?
|
// are we sharing pixelrefs with the image?
|
||||||
sk_sp<SkImage> cached(this->refCachedImage());
|
sk_sp<SkImage> cached(this->refCachedImage());
|
||||||
@ -147,6 +152,36 @@ void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
|
|||||||
this->getCachedCanvas()->baseDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
|
this->getCachedCanvas()->baseDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
bool SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
|
||||||
|
// are we sharing pixelrefs with the image?
|
||||||
|
sk_sp<SkImage> cached(this->refCachedImage());
|
||||||
|
SkASSERT(cached);
|
||||||
|
if (SkBitmapImageGetPixelRef(cached.get()) == fBitmap.pixelRef()) {
|
||||||
|
SkASSERT(fWeOwnThePixels);
|
||||||
|
if (kDiscard_ContentChangeMode == mode) {
|
||||||
|
if (!fBitmap.tryAllocPixels()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SkBitmap prev(fBitmap);
|
||||||
|
if (!fBitmap.tryAllocPixels()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SkASSERT(prev.info() == fBitmap.info());
|
||||||
|
SkASSERT(prev.rowBytes() == fBitmap.rowBytes());
|
||||||
|
memcpy(fBitmap.getPixels(), prev.getPixels(), fBitmap.computeByteSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now fBitmap is a deep copy of itself (and therefore different from
|
||||||
|
// what is being used by the image. Next we update the canvas to use
|
||||||
|
// this as its backend, so we can't modify the image's pixels anymore.
|
||||||
|
SkASSERT(this->getCachedCanvas());
|
||||||
|
this->getCachedCanvas()->baseDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user