SkCanvas: switch from SkDeque to std::deque

Bug: skia:10987
Change-Id: If252f644dc3b8827356f9c7044c8e01fd0fc5afe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/434676
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-29 14:18:20 -04:00 committed by SkCQ
parent 94df5d607c
commit cc9d20f308
4 changed files with 124 additions and 168 deletions

View File

@ -26,10 +26,10 @@
#include "include/core/SkString.h"
#include "include/core/SkSurfaceProps.h"
#include "include/core/SkTypes.h"
#include "include/private/SkDeque.h"
#include "include/private/SkMacros.h"
#include <cstring>
#include <deque>
#include <memory>
#include <vector>
@ -57,6 +57,7 @@ class SkPixmap;
class SkRegion;
class SkRRect;
struct SkRSXform;
class SkSpecialImage;
class SkSurface;
class SkSurface_Base;
class SkTextBlob;
@ -2288,20 +2289,55 @@ 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;
SkDeque fMCStack;
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);
};
std::deque<MCRec> fMCStack;
// points to top of stack
MCRec* fMCRec;
MCRec* fMCRec;
sk_sp<SkMarkerStack> fMarkerStack;
// the first N recs that can fit here mean we won't call malloc
static constexpr int kMCRecSize = 96; // most recent measurement
static constexpr int kMCRecCount = 32; // common depth for save/restores
intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)];
// Installed via init()
sk_sp<SkBaseDevice> fBaseDevice;
const SkSurfaceProps fProps;

View File

@ -186,31 +186,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
@ -218,65 +193,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:
@ -421,11 +374,6 @@ void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
}
void SkCanvas::init(sk_sp<SkBaseDevice> device) {
// SkCanvas.h declares internal storage for the hidden struct MCRec, and this
// assert ensure it's sufficient. <= is used because the struct has pointer fields, so the
// declared size is an upper bound across architectures. When the size is smaller, more stack
static_assert(sizeof(MCRec) <= kMCRecSize);
if (!device) {
device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps);
}
@ -434,7 +382,7 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) {
SkASSERT(device);
fSaveCount = 1;
fMCRec = new (fMCStack.push_back()) MCRec(device.get());
fMCRec = &fMCStack.emplace_back(device.get());
fMarkerStack = sk_make_sp<SkMarkerStack>();
// The root device and the canvas should always have the same pixel geometry
@ -448,58 +396,42 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) {
fQuickRejectBounds = this->computeDeviceClipBounds();
}
SkCanvas::SkCanvas()
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps()
{
SkCanvas::SkCanvas() {
inc_canvas();
this->init(nullptr);
}
SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(SkSurfacePropsCopyOrDefault(props))
{
: 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()
{
SkCanvas::SkCanvas(const SkIRect& bounds) {
inc_canvas();
SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
}
SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(device->surfaceProps())
{
SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device) : fProps(device->surfaceProps()) {
inc_canvas();
this->init(device);
}
SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(props)
{
SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) : 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))
{
: fAllocator(std::move(alloc)) {
inc_canvas();
sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
@ -509,9 +441,7 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocat
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)
{
SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior) {
inc_canvas();
SkBitmap tmp(bitmap);
@ -522,9 +452,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();
@ -614,13 +542,8 @@ void SkCanvas::checkForDeferredSave() {
int SkCanvas::getSaveCount() const {
#ifdef SK_DEBUG
int count = 0;
SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
for (;;) {
const MCRec* rec = (const MCRec*)iter.next();
if (!rec) {
break;
}
count += 1 + rec->fDeferredSaveCount;
for (const auto &rec : fMCStack) {
count += 1 + rec.fDeferredSaveCount;
}
SkASSERT(count == fSaveCount);
#endif
@ -648,7 +571,7 @@ void SkCanvas::restore() {
fMCRec->fDeferredSaveCount -= 1;
} else {
// check for underflow
if (fMCStack.count() > 1) {
if (fMCStack.size() > 1) {
this->willRestore();
SkASSERT(fSaveCount > 1);
fSaveCount -= 1;
@ -671,7 +594,7 @@ void SkCanvas::restoreToCount(int count) {
}
void SkCanvas::internalSave() {
fMCRec = new (fMCStack.push_back()) MCRec(*fMCRec);
fMCRec = &fMCStack.emplace_back(fMCRec);
this->topDevice()->save();
}
@ -1182,7 +1105,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);
@ -1191,15 +1114,16 @@ void SkCanvas::internalRestore() {
fMarkerStack->restore(fMCRec);
// now do the normal restore()
fMCRec->~MCRec(); // balanced in save()
fMCStack.pop_back();
fMCRec = (MCRec*) fMCStack.back();
if (!fMCRec) {
if (fMCStack.empty()) {
// This was the last record, restored during the destruction of the SkCanvas
fMCRec = nullptr;
return;
}
fMCRec = &fMCStack.back();
this->topDevice()->restore(fMCRec->fMatrix);
if (backImage) {
@ -1967,23 +1891,19 @@ void SkCanvas::onDrawBehind(const SkPaint& paint) {
return;
}
SkIRect bounds;
SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
for (;;) {
const MCRec* rec = (const MCRec*)iter.prev();
if (!rec) {
return; // no backimages, so nothing to draw
}
if (rec->fBackImage) {
// drawBehind should only have been called when the saveBehind record is active;
// if this fails, it means a real saveLayer was made w/o being restored first.
SkASSERT(dev == rec->fDevice);
bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
auto rec = std::find_if(fMCStack.rbegin(), fMCStack.rend(), [](const MCRec& r) {
return r.fBackImage != nullptr;
});
if (rec == fMCStack.rend()) {
return; // no backimages, so nothing to draw
}
// drawBehind should only have been called when the saveBehind record is active;
// if this fails, it means a real saveLayer was made w/o being restored first.
SkASSERT(dev == rec->fDevice);
SkIRect bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
rec->fBackImage->fImage->width(),
rec->fBackImage->fImage->height());
break;
}
}
// The backimage location (and thus bounds) were defined in the device's space, so mark it
// as a clip. We use a clip instead of just drawing a rect in case the paint has an image

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