Move canvas helper structs to header

This is necessary cleanup before changing the type of the matrix and
clip stack. That work has landed and reverted several times, so landing
this piece separately, first.

Change-Id: I147e4cc4260fa5e07a0712503f879da120f8466a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/435278
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2021-07-30 15:24:22 -04:00 committed by SkCQ
parent 7f01c22314
commit 68556bc798
4 changed files with 105 additions and 123 deletions

View File

@ -57,6 +57,7 @@ class SkPixmap;
class SkRegion;
class SkRRect;
struct SkRSXform;
class SkSpecialImage;
class SkSurface;
class SkSurface_Base;
class SkTextBlob;
@ -2288,7 +2289,48 @@ private:
// operations should route to this device.
SkBaseDevice* topDevice() const;
class MCRec;
// Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing,
// clip, and matrix commands. There is a layer per call to saveLayer() using the
// kFullLayer_SaveLayerStrategy.
struct Layer {
sk_sp<SkBaseDevice> fDevice;
sk_sp<SkImageFilter> fImageFilter; // applied to layer *before* being drawn by paint
SkPaint fPaint;
Layer(sk_sp<SkBaseDevice> device, sk_sp<SkImageFilter> imageFilter, const SkPaint& paint);
};
// Encapsulate state needed to restore from saveBehind()
struct BackImage {
sk_sp<SkSpecialImage> fImage;
SkIPoint fLoc;
};
class MCRec {
public:
// If not null, this MCRec corresponds with the saveLayer() record that made the layer.
// The base "layer" is not stored here, since it is stored inline in SkCanvas and has no
// restoration behavior.
std::unique_ptr<Layer> fLayer;
// This points to the device of the top-most layer (which may be lower in the stack), or
// to the canvas's fBaseDevice. The MCRec does not own the device.
SkBaseDevice* fDevice;
std::unique_ptr<BackImage> fBackImage;
SkM44 fMatrix;
int fDeferredSaveCount = 0;
MCRec(SkBaseDevice* device);
MCRec(const MCRec* prev);
~MCRec();
void newLayer(sk_sp<SkBaseDevice> layerDevice,
sk_sp<SkImageFilter> filter,
const SkPaint& restorePaint);
void reset(SkBaseDevice* device);
};
SkDeque fMCStack;
// points to top of stack

View File

@ -184,31 +184,6 @@ void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
namespace {
// Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing,
// clip, and matrix commands. There is a layer per call to saveLayer() using the
// kFullLayer_SaveLayerStrategy.
struct Layer {
sk_sp<SkBaseDevice> fDevice;
sk_sp<SkImageFilter> fImageFilter; // applied to layer *before* being drawn by paint
SkPaint fPaint;
Layer(sk_sp<SkBaseDevice> device, sk_sp<SkImageFilter> imageFilter, const SkPaint& paint)
: fDevice(std::move(device))
, fImageFilter(std::move(imageFilter))
, fPaint(paint) {
SkASSERT(fDevice);
// Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint'
// can be used as-is to draw the result of the filter to the dst device.
SkASSERT(!fPaint.getImageFilter());
}
};
// Encapsulate state needed to restore from saveBehind()
struct BackImage {
sk_sp<SkSpecialImage> fImage;
SkIPoint fLoc;
};
enum class CheckForOverwrite : bool {
kNo = false,
kYes = true
@ -216,65 +191,43 @@ enum class CheckForOverwrite : bool {
} // namespace
/* This is the record we keep for each save/restore level in the stack.
Since a level optionally copies the matrix and/or stack, we have pointers
for these fields. If the value is copied for this level, the copy is
stored in the ...Storage field, and the pointer points to that. If the
value is not copied for this level, we ignore ...Storage, and just point
at the corresponding value in the previous level in the stack.
*/
class SkCanvas::MCRec {
public:
// If not null, this MCRec corresponds with the saveLayer() record that made the layer.
// The base "layer" is not stored here, since it is stored inline in SkCanvas and has no
// restoration behavior.
std::unique_ptr<Layer> fLayer;
SkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device,
sk_sp<SkImageFilter> imageFilter,
const SkPaint& paint)
: fDevice(std::move(device)), fImageFilter(std::move(imageFilter)), fPaint(paint) {
SkASSERT(fDevice);
// Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint'
// can be used as-is to draw the result of the filter to the dst device.
SkASSERT(!fPaint.getImageFilter());
}
// This points to the device of the top-most layer (which may be lower in the stack), or
// to the canvas's fBaseDevice. The MCRec does not own the device.
SkBaseDevice* fDevice;
SkCanvas::MCRec::MCRec(SkBaseDevice* device) : fDevice(device) {
SkASSERT(fDevice);
inc_rec();
}
std::unique_ptr<BackImage> fBackImage;
SkM44 fMatrix;
int fDeferredSaveCount;
SkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) {
SkASSERT(fDevice);
inc_rec();
}
MCRec(SkBaseDevice* device)
: fLayer(nullptr)
, fDevice(device)
, fBackImage(nullptr)
, fDeferredSaveCount(0) {
SkASSERT(fDevice);
fMatrix.setIdentity();
inc_rec();
}
SkCanvas::MCRec::~MCRec() { dec_rec(); }
MCRec(const MCRec& prev)
: fLayer(nullptr)
, fDevice(prev.fDevice)
, fMatrix(prev.fMatrix)
, fDeferredSaveCount(0) {
SkASSERT(fDevice);
inc_rec();
}
~MCRec() {
dec_rec();
}
void SkCanvas::MCRec::newLayer(sk_sp<SkBaseDevice> layerDevice,
sk_sp<SkImageFilter> filter,
const SkPaint& restorePaint) {
SkASSERT(!fBackImage);
fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint);
fDevice = fLayer->fDevice.get();
}
void newLayer(sk_sp<SkBaseDevice> layerDevice, sk_sp<SkImageFilter> filter,
const SkPaint& restorePaint) {
SkASSERT(!fBackImage);
fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint);
fDevice = fLayer->fDevice.get();
}
void reset(SkBaseDevice* device) {
SkASSERT(!fLayer);
SkASSERT(device);
SkASSERT(fDeferredSaveCount == 0);
fDevice = device;
fMatrix.setIdentity();
}
};
void SkCanvas::MCRec::reset(SkBaseDevice* device) {
SkASSERT(!fLayer);
SkASSERT(device);
SkASSERT(fDeferredSaveCount == 0);
fDevice = device;
fMatrix.setIdentity();
}
class SkCanvas::AutoUpdateQRBounds {
public:
@ -445,27 +398,21 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) {
fQuickRejectBounds = this->computeDeviceClipBounds();
}
SkCanvas::SkCanvas()
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps()
{
SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
this->init(nullptr);
}
SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(SkSurfacePropsCopyOrDefault(props))
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(SkSurfacePropsCopyOrDefault(props)) {
inc_canvas();
this->init(sk_make_sp<SkNoPixelsDevice>(
SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
}
SkCanvas::SkCanvas(const SkIRect& bounds)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps()
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
@ -473,30 +420,26 @@ SkCanvas::SkCanvas(const SkIRect& bounds)
}
SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(device->surfaceProps())
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(device->surfaceProps()) {
inc_canvas();
this->init(device);
}
SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(props)
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(props) {
inc_canvas();
sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
this->init(device);
}
SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
SkCanvas::SkCanvas(const SkBitmap& bitmap,
std::unique_ptr<SkRasterHandleAllocator> alloc,
SkRasterHandleAllocator::Handle hndl)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps()
, fAllocator(std::move(alloc))
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fAllocator(std::move(alloc)) {
inc_canvas();
sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
@ -507,8 +450,7 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr)
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(), fAllocator(nullptr)
{
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
SkBitmap tmp(bitmap);
@ -519,9 +461,7 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
#endif
SkCanvas::~SkCanvas() {
// free up the contents of our deque
this->restoreToCount(1); // restore everything but the last
this->internalRestore(); // restore the last, since we're going away
dec_canvas();
@ -668,7 +608,7 @@ void SkCanvas::restoreToCount(int count) {
}
void SkCanvas::internalSave() {
fMCRec = new (fMCStack.push_back()) MCRec(*fMCRec);
fMCRec = new (fMCStack.push_back()) MCRec(fMCRec);
this->topDevice()->save();
}
@ -1178,7 +1118,7 @@ void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
}
void SkCanvas::internalRestore() {
SkASSERT(fMCStack.count() != 0);
SkASSERT(!fMCStack.empty());
// now detach these from fMCRec so we can pop(). Gets freed after its drawn
std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer);

View File

@ -75,7 +75,7 @@ struct MSKPPlayer::DrawLayerCmd : Cmd {
void MSKPPlayer::DrawLayerCmd::draw(SkCanvas* canvas,
const LayerMap& layerMap,
LayerStateMap* layerStateMap) const {
const Layer& layer = layerMap.at(fLayerId);
const LayerCmds& layer = layerMap.at(fLayerId);
LayerState* layerState = &(*layerStateMap)[fLayerId];
if (!layerState->fSurface) {
layerState->fCurrCmd = 0;
@ -119,7 +119,7 @@ void MSKPPlayer::DrawLayerCmd::draw(SkCanvas* canvas,
class MSKPPlayer::CmdRecordCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
public:
CmdRecordCanvas(Layer* dst, LayerMap* offscreenLayers, const SkIRect* clipRect = nullptr)
CmdRecordCanvas(LayerCmds* dst, LayerMap* offscreenLayers, const SkIRect* clipRect = nullptr)
: fDst(dst), fOffscreenLayers(offscreenLayers) {
if (clipRect) {
fClipRect = *clipRect;
@ -332,7 +332,7 @@ protected:
if (fNextDrawPictureToLayerID != -1) {
SkASSERT(!matrix);
SkASSERT(!paint);
Layer* layer = &fOffscreenLayers->at(fNextDrawPictureToLayerID);
LayerCmds* layer = &fOffscreenLayers->at(fNextDrawPictureToLayerID);
CmdRecordCanvas sc(layer, fOffscreenLayers, &fNextDrawPictureToLayerClipRect);
picture->playback(&sc);
fNextDrawPictureToLayerID = -1;
@ -371,7 +371,7 @@ private:
}
SkPictureRecorder fRecorder; // accumulates draws until we draw an offscreen into this layer.
Layer* fDst = nullptr;
LayerCmds* fDst = nullptr;
SkIRect fClipRect = SkIRect::MakeEmpty();
int fNextDrawPictureToLayerID = -1;
SkIRect fNextDrawPictureToLayerClipRect = SkIRect::MakeEmpty();
@ -438,14 +438,14 @@ bool MSKPPlayer::playFrame(SkCanvas* canvas, int i) {
}
// Replay all the commands for this frame to the caller's canvas.
const Layer& layer = fRootLayers[i];
const LayerCmds& layer = fRootLayers[i];
for (const auto& cmd : layer.fCmds) {
cmd->draw(canvas, fOffscreenLayers, &fOffscreenLayerStates);
}
return true;
}
sk_sp<SkSurface> MSKPPlayer::MakeSurfaceForLayer(const Layer& layer, SkCanvas* rootCanvas) {
sk_sp<SkSurface> MSKPPlayer::MakeSurfaceForLayer(const LayerCmds& layer, SkCanvas* rootCanvas) {
// Assume layer has same surface props and info as this (mskp doesn't currently record this
// data).
SkSurfaceProps props;
@ -497,7 +497,7 @@ sk_sp<SkImage> MSKPPlayer::layerSnapshot(int layerID) const {
return iter->second.fSurface->makeImageSnapshot();
}
void MSKPPlayer::collectReferencedLayers(const Layer& layer, std::vector<int>* out) const {
void MSKPPlayer::collectReferencedLayers(const LayerCmds& layer, std::vector<int>* out) const {
for (const auto& cmd : layer.fCmds) {
if (int id = cmd->layerID(); id >= 0) {
// Linear, but we'd need to have a lot of layers to actually care.

View File

@ -95,9 +95,9 @@ private:
struct DrawLayerCmd;
// The commands for a root/offscreen layer and dimensions of the layer.
struct Layer {
Layer() = default;
Layer(Layer&&) = default;
struct LayerCmds {
LayerCmds() = default;
LayerCmds(LayerCmds&&) = default;
SkISize fDimensions;
std::vector<std::unique_ptr<Cmd>> fCmds;
};
@ -108,19 +108,19 @@ private:
sk_sp<SkSurface> fSurface;
};
static sk_sp<SkSurface> MakeSurfaceForLayer(const Layer&, SkCanvas* rootCanvas);
static sk_sp<SkSurface> MakeSurfaceForLayer(const LayerCmds&, SkCanvas* rootCanvas);
void collectReferencedLayers(const Layer& layer, std::vector<int>*) const;
void collectReferencedLayers(const LayerCmds& layer, std::vector<int>*) const;
// MSKP layer ID -> Layer
using LayerMap = std::unordered_map<int, Layer>;
// MSKP layer ID -> LayerCmds
using LayerMap = std::unordered_map<int, LayerCmds>;
// MSKP layer ID -> LayerState
using LayerStateMap = std::unordered_map<int, LayerState>;
/**
* A SkCanvas that consumes the SkPicture and records Cmds into a Layer. It will spawn
* additional Layers and record nested SkPictures into those using additional CmdRecordCanvas
* CmdRecordCanvas instances. It needs access to fOffscreenLayers to create and update Layer
* CmdRecordCanvas instances. It needs access to fOffscreenLayers to create and update LayerCmds
* structs for offscreen layers.
*/
class CmdRecordCanvas;
@ -129,7 +129,7 @@ private:
LayerMap fOffscreenLayers; // All the offscreen layers for all frames.
LayerStateMap fOffscreenLayerStates; // Current surfaces and command idx for offscreen
// layers
std::vector<Layer> fRootLayers; // One root layer for each frame.
std::vector<LayerCmds> fRootLayers; // One root layer for each frame.
};
#endif