Revert of Sketch splitting SkPicture into an interface and SkBigPicture. (patchset #25 id:480001 of https://codereview.chromium.org/1112523006/)

Reason for revert:
win_chromium_compile_dbg_ng

FAILED: ninja -t msvc -e environment.x86 -- E:\b\build\goma/gomacc "E:\b\depot_tools\win_toolchain\vs2013_files\VC\bin\amd64_x86\cl.exe" /nologo /showIncludes /FC @obj\third_party\skia\src\core\skia.SkBitmapHeap.obj.rsp /c ..\..\third_party\skia\src\core\SkBitmapHeap.cpp /Foobj\third_party\skia\src\core\skia.SkBitmapHeap.obj /Fdobj\skia\skia.cc.pdb
e:\b\build\slave\win\build\src\third_party\skia\include\core\skpicture.h(176) : error C2487: 'CURRENT_PICTURE_VERSION' : member of dll interface class may not be declared with dll interface

Original issue's description:
> Sketch splitting SkPicture into an interface and SkBigPicture.
>
> Adds small pictures for drawRect(), drawTextBlob(), and drawPath().
> These cover about 89% of draw calls from Blink SKPs,
> and about 25% of draw calls from our GMs.
>
> SkPicture handles:
>   - serialization and deserialization
>   - unique IDs
>
> Everything else is left to the subclasses:
>   - playback(), cullRect()
>   - hasBitmap(), hasText(), suitableForGPU(), etc.
>   - LayerInfo / AccelData if applicable.
>
> The time to record a 1-op picture improves a good chunk
> (2 mallocs to 1), and the time to record a 0-op picture
> greatly improves (2 mallocs to none):
>
>     picture_overhead_draw:   450ns -> 350ns
>     picture_overhead_nodraw: 300ns -> 90ns
>
> BUG=skia:
>
> Committed: https://skia.googlesource.com/skia/+/c92c129ff85b05a714bd1bf921c02d5e14651f8b
>
> Latest blink_linux_rel:
>
> http://build.chromium.org/p/tryserver.blink/builders/linux_blink_rel/builds/61248
>
> Committed: https://skia.googlesource.com/skia/+/15877b6eae33a9282458bdb904a6d00440eca0ec

TBR=reed@google.com,robertphillips@google.com,fmalita@chromium.org,mtklein@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review URL: https://codereview.chromium.org/1130283004
This commit is contained in:
mtklein 2015-05-18 14:53:43 -07:00 committed by Commit bot
parent 4f2dba625d
commit 72743b1654
26 changed files with 697 additions and 774 deletions

View File

@ -23,7 +23,6 @@
'<(skia_src_path)/core/SkAntiRun.h',
'<(skia_src_path)/core/SkBBHFactory.cpp',
'<(skia_src_path)/core/SkBBoxHierarchy.h',
'<(skia_src_path)/core/SkBigPicture.cpp',
'<(skia_src_path)/core/SkBitmap.cpp',
'<(skia_src_path)/core/SkBitmapCache.cpp',
'<(skia_src_path)/core/SkBitmapDevice.cpp',
@ -118,6 +117,7 @@
'<(skia_src_path)/core/SkImageInfo.cpp',
'<(skia_src_path)/core/SkImageGenerator.cpp',
'<(skia_src_path)/core/SkLayerInfo.h',
'<(skia_src_path)/core/SkLayerInfo.cpp',
'<(skia_src_path)/core/SkLocalMatrixShader.cpp',
'<(skia_src_path)/core/SkLineClipper.cpp',
'<(skia_src_path)/core/SkMallocPixelRef.cpp',
@ -133,7 +133,6 @@
'<(skia_src_path)/core/SkMessageBus.h',
'<(skia_src_path)/core/SkMetaData.cpp',
'<(skia_src_path)/core/SkMipMap.cpp',
'<(skia_src_path)/core/SkMiniRecorder.cpp',
'<(skia_src_path)/core/SkMultiPictureDraw.cpp',
'<(skia_src_path)/core/SkPackBits.cpp',
'<(skia_src_path)/core/SkPaint.cpp',

View File

@ -79,6 +79,7 @@
'<(skia_src_path)/utils/SkParse.cpp',
'<(skia_src_path)/utils/SkParseColor.cpp',
'<(skia_src_path)/utils/SkParsePath.cpp',
'<(skia_src_path)/utils/SkPictureUtils.cpp',
'<(skia_src_path)/utils/SkPatchGrid.cpp',
'<(skia_src_path)/utils/SkPatchGrid.h',
'<(skia_src_path)/utils/SkPatchUtils.cpp',

View File

@ -5,32 +5,62 @@
* found in the LICENSE file.
*/
#ifndef SkPicture_DEFINED
#define SkPicture_DEFINED
#include "SkImageDecoder.h"
#include "SkLazyPtr.h"
#include "SkRefCnt.h"
#include "SkTypes.h"
#include "SkTDArray.h"
#if SK_SUPPORT_GPU
class GrContext;
class SkBigPicture;
#endif
class SkBitmap;
class SkBBoxHierarchy;
class SkCanvas;
class SkData;
class SkPictureData;
class SkPixelSerializer;
class SkStream;
class SkWStream;
struct SkPictInfo;
class SkRecord;
namespace SkRecords {
class CollectLayers;
};
/** \class SkPicture
An SkPicture records drawing commands made to a canvas to be played back at a later time.
This base class handles serialization and a few other miscellany.
The SkPicture class records the drawing commands made to a canvas, to
be played back at a later time.
*/
class SK_API SkPicture : public SkRefCnt {
class SK_API SkPicture : public SkNVRefCnt<SkPicture> {
public:
virtual ~SkPicture();
// AccelData provides a base class for device-specific acceleration data.
class AccelData : public SkRefCnt {
public:
typedef uint8_t Domain;
typedef uint32_t Key;
AccelData(Key key) : fKey(key) { }
const Key& getKey() const { return fKey; }
// This entry point allows user's to get a unique domain prefix
// for their keys
static Domain GenerateDomain();
private:
Key fKey;
};
/** PRIVATE / EXPERIMENTAL -- do not call */
const AccelData* EXPERIMENTAL_getAccelData(AccelData::Key) const;
/**
* Function signature defining a function that sets up an SkBitmap from encoded data. On
@ -66,6 +96,8 @@ public:
*/
static SkPicture* CreateFromBuffer(SkReadBuffer&);
~SkPicture();
/**
* Subclasses of this can be passed to playback(). During the playback
* of the picture, this callback will periodically be invoked. If its
@ -80,6 +112,7 @@ public:
public:
AbortCallback() {}
virtual ~AbortCallback() {}
virtual bool abort() = 0;
};
@ -90,14 +123,16 @@ public:
@param canvas the canvas receiving the drawing commands.
@param callback a callback that allows interruption of playback
*/
virtual void playback(SkCanvas*, AbortCallback* = NULL) const = 0;
void playback(SkCanvas* canvas, AbortCallback* = NULL) const;
/** Return a cull rect for this picture.
Ops recorded into this picture that attempt to draw outside the cull might not be drawn.
/** Return the cull rect used when creating this picture: { 0, 0, cullWidth, cullHeight }.
It does not necessarily reflect the bounds of what has been recorded into the picture.
@return the cull rect used to create this picture
*/
SkRect cullRect() const { return fCullRect; }
/** Return a non-zero, unique value representing the picture.
*/
virtual SkRect cullRect() const = 0;
/** Returns a non-zero value unique among all pictures. */
uint32_t uniqueID() const;
/**
@ -106,7 +141,7 @@ public:
*
* TODO: Use serializer to serialize SkImages as well.
*/
void serialize(SkWStream*, SkPixelSerializer* = NULL) const;
void serialize(SkWStream*, SkPixelSerializer* serializer = NULL) const;
/**
* Serialize to a buffer.
@ -117,21 +152,7 @@ public:
* Returns true if any bitmaps may be produced when this SkPicture
* is replayed.
*/
virtual bool willPlayBackBitmaps() const = 0;
/** Return the approximate number of operations in this picture. This
* number may be greater or less than the number of SkCanvas calls
* recorded: some calls may be recorded as more than one operation, or some
* calls may be optimized away.
*/
virtual int approximateOpCount() const = 0;
/** Return true if this picture contains text.
*/
virtual bool hasText() const = 0;
/** Returns the approximate byte size of this picture, not including large ref'd objects. */
virtual size_t approximateBytesUsed() const = 0;
bool willPlayBackBitmaps() const;
/** Return true if the SkStream/Buffer represents a serialized picture, and
fills out SkPictInfo. After this function returns, the data source is not
@ -144,25 +165,76 @@ public:
static bool InternalOnly_StreamIsSKP(SkStream*, SkPictInfo*);
static bool InternalOnly_BufferIsSKP(SkReadBuffer*, SkPictInfo*);
/** Return true if the picture is suitable for rendering on the GPU. */
bool suitableForGpuRasterization(GrContext*, const char** whyNot = NULL) const;
/** Return true if the picture is suitable for rendering on the GPU.
*/
#if SK_SUPPORT_GPU
bool suitableForGpuRasterization(GrContext*, const char ** = NULL) const;
#endif
/** Return the approximate number of operations in this picture. This
* number may be greater or less than the number of SkCanvas calls
* recorded: some calls may be recorded as more than one operation, or some
* calls may be optimized away.
*/
int approximateOpCount() const;
/** Return true if this picture contains text.
*/
bool hasText() const;
// An array of refcounted const SkPicture pointers.
class SnapshotArray : ::SkNoncopyable {
public:
SnapshotArray(const SkPicture* pics[], int count) : fPics(pics), fCount(count) {}
~SnapshotArray() { for (int i = 0; i < fCount; i++) { fPics[i]->unref(); } }
const SkPicture* const* begin() const { return fPics; }
int count() const { return fCount; }
private:
SkAutoTMalloc<const SkPicture*> fPics;
int fCount;
};
// Sent via SkMessageBus from destructor.
struct DeletionMessage { int32_t fUniqueID; }; // TODO: -> uint32_t?
// Returns NULL if this is not an SkBigPicture.
virtual const SkBigPicture* asSkBigPicture() const { return NULL; }
struct DeletionMessage { int32_t fUniqueID; };
private:
// Subclass whitelist.
SkPicture();
friend class SkBigPicture;
friend class SkEmptyPicture;
template <typename> friend class SkMiniPicture;
virtual int numSlowPaths() const = 0;
friend struct SkPathCounter;
// V2 : adds SkPixelRef's generation ID.
// V3 : PictInfo tag at beginning, and EOF tag at the end
// V4 : move SkPictInfo to be the header
// V5 : don't read/write FunctionPtr on cross-process (we can detect that)
// V6 : added serialization of SkPath's bounds (and packed its flags tighter)
// V7 : changed drawBitmapRect(IRect) to drawBitmapRectToRect(Rect)
// V8 : Add an option for encoding bitmaps
// V9 : Allow the reader and writer of an SKP disagree on whether to support
// SK_SUPPORT_HINTING_SCALE_FACTOR
// V10: add drawRRect, drawOval, clipRRect
// V11: modify how readBitmap and writeBitmap store their info.
// V12: add conics to SkPath, use new SkPathRef flattening
// V13: add flag to drawBitmapRectToRect
// parameterize blurs by sigma rather than radius
// V14: Add flags word to PathRef serialization
// V15: Remove A1 bitmap config (and renumber remaining configs)
// V16: Move SkPath's isOval flag to SkPathRef
// V17: SkPixelRef now writes SkImageInfo
// V18: SkBitmap now records x,y for its pixelref origin, instead of offset.
// V19: encode matrices and regions into the ops stream
// V20: added bool to SkPictureImageFilter's serialization (to allow SkPicture serialization)
// V21: add pushCull, popCull
// V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes
// V23: SkPaint::FilterLevel became a real enum
// V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
// V25: SkDashPathEffect now only writes phase and interval array when flattening
// V26: Removed boolean from SkColorShader for inheriting color from SkPaint.
// V27: Remove SkUnitMapper from gradients (and skia).
// V28: No longer call bitmap::flatten inside SkWriteBuffer::writeBitmap.
// V29: Removed SaveFlags parameter from save().
// V30: Remove redundant SkMatrix from SkLocalMatrixShader.
// V31: Add a serialized UniqueID to SkImageFilter.
// V32: Removed SkPaintOptionsAndroid from SkPaint
// V33: Serialize only public API of effects.
// V34: Add SkTextBlob serialization.
// V35: Store SkRect (rather then width & height) in header
// V36: Remove (obsolete) alphatype from SkColorTable
// V37: Added shadow only option to SkDropShadowImageFilter (last version to record CLEAR)
@ -171,20 +243,67 @@ private:
// V40: Remove UniqueID serialization from SkImageFilter.
// V41: Added serialization of SkBitmapSource's filterQuality parameter
// Note: If the picture version needs to be increased then please follow the
// steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 35, // Produced by Chrome M39.
CURRENT_PICTURE_VERSION = 41;
static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
static const uint32_t CURRENT_PICTURE_VERSION = 41;
static_assert(MIN_PICTURE_VERSION <= 41,
"Remove kFontFileName and related code from SkFontDescriptor.cpp.");
void createHeader(SkPictInfo* info) const;
static bool IsValidPictInfo(const SkPictInfo& info);
// Takes ownership of the (optional) SnapshotArray.
// For performance, we take ownership of the caller's refs on the SkRecord, BBH, and AccelData.
SkPicture(const SkRect& cullRect,
SkRecord*,
SnapshotArray*,
SkBBoxHierarchy*,
AccelData*,
size_t approxBytesUsedBySubPictures);
static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);
static SkPictureData* Backport(const SkRecord&, const SkPictInfo&,
SkPicture const* const drawablePics[], int drawableCount);
SkPictInfo createHeader() const;
SkPictureData* backport() const;
// uint32_t fRefCnt; from SkNVRefCnt<SkPicture>
mutable uint32_t fUniqueID;
const SkRect fCullRect;
SkAutoTUnref<const SkRecord> fRecord;
SkAutoTDelete<const SnapshotArray> fDrawablePicts;
SkAutoTUnref<const SkBBoxHierarchy> fBBH;
SkAutoTUnref<const AccelData> fAccelData;
const size_t fApproxBytesUsedBySubPictures;
mutable uint32_t fUniqueID;
// helpers for fDrawablePicts
int drawableCount() const;
// will return NULL if drawableCount() returns 0
SkPicture const* const* drawablePicts() const;
struct PathCounter;
struct Analysis {
Analysis() {} // Only used by SkPictureData codepath.
explicit Analysis(const SkRecord&);
bool suitableForGpuRasterization(const char** reason, int sampleCount) const;
uint8_t fNumSlowPathsAndDashEffects;
bool fWillPlaybackBitmaps : 1;
bool fHasText : 1;
};
SkLazyPtr<Analysis> fAnalysis;
const Analysis& analysis() const;
friend class SkPictureRecorder; // SkRecord-based constructor.
friend class GrLayerHoister; // access to fRecord
friend class ReplaceDraw;
friend class SkPictureUtils;
friend class SkRecordedDrawable;
};
SK_COMPILE_ASSERT(sizeof(SkPicture) <= 88, SkPictureSize);
#endif

View File

@ -8,7 +8,6 @@
#ifndef SkPictureRecorder_DEFINED
#define SkPictureRecorder_DEFINED
#include "../../src/core/SkMiniRecorder.h"
#include "SkBBHFactory.h"
#include "SkPicture.h"
#include "SkRefCnt.h"
@ -103,7 +102,6 @@ private:
SkAutoTUnref<SkBBoxHierarchy> fBBH;
SkAutoTUnref<SkRecorder> fRecorder;
SkAutoTUnref<SkRecord> fRecord;
SkMiniRecorder fMiniRecorder;
typedef SkNoncopyable INHERITED;
};

View File

@ -10,8 +10,6 @@
#include "SkPicture.h"
// TODO: remove this file?
class SK_API SkPictureUtils {
public:
/**
@ -20,9 +18,7 @@ public:
* includes nested SkPictures, but does not include large objects that
* SkRecord holds a reference to (e.g. paths, or pixels backing bitmaps).
*/
static size_t ApproximateBytesUsed(const SkPicture* pict) {
return pict->approximateBytesUsed();
}
static size_t ApproximateBytesUsed(const SkPicture* pict);
};
#endif

View File

@ -1,98 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBBoxHierarchy.h"
#include "SkBigPicture.h"
#include "SkPictureCommon.h"
#include "SkRecord.h"
#include "SkRecordDraw.h"
SkBigPicture::SkBigPicture(const SkRect& cull,
SkRecord* record,
SnapshotArray* drawablePicts,
SkBBoxHierarchy* bbh,
AccelData* accelData,
size_t approxBytesUsedBySubPictures)
: fCullRect(cull)
, fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
, fRecord(record) // Take ownership of caller's ref.
, fDrawablePicts(drawablePicts) // Take ownership.
, fBBH(bbh) // Take ownership of caller's ref.
, fAccelData(accelData) // Take ownership of caller's ref.
{}
void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
SkASSERT(canvas);
// If the query contains the whole picture, don't bother with the BBH.
SkRect clipBounds = { 0, 0, 0, 0 };
(void)canvas->getClipBounds(&clipBounds);
const bool useBBH = !clipBounds.contains(this->cullRect());
SkRecordDraw(*fRecord,
canvas,
this->drawablePicts(),
nullptr,
this->drawableCount(),
useBBH ? fBBH.get() : nullptr,
callback);
}
void SkBigPicture::partialPlayback(SkCanvas* canvas,
unsigned start,
unsigned stop,
const SkMatrix& initialCTM) const {
SkASSERT(canvas);
SkRecordPartialDraw(*fRecord,
canvas,
this->drawablePicts(),
this->drawableCount(),
start,
stop,
initialCTM);
}
const SkBigPicture::Analysis& SkBigPicture::analysis() const {
auto create = [&]() { return SkNEW_ARGS(Analysis, (*fRecord)); };
return *fAnalysis.get(create);
}
SkRect SkBigPicture::cullRect() const { return fCullRect; }
bool SkBigPicture::hasText() const { return this->analysis().fHasText; }
bool SkBigPicture::willPlayBackBitmaps() const { return this->analysis().fWillPlaybackBitmaps; }
int SkBigPicture::numSlowPaths() const { return this->analysis().fNumSlowPathsAndDashEffects; }
int SkBigPicture::approximateOpCount() const { return fRecord->count(); }
size_t SkBigPicture::approximateBytesUsed() const {
size_t bytes = sizeof(*this) + fRecord->bytesUsed() + fApproxBytesUsedBySubPictures;
if (fBBH) { bytes += fBBH->bytesUsed(); }
return bytes;
}
int SkBigPicture::drawableCount() const {
return fDrawablePicts ? fDrawablePicts->count() : 0;
}
SkPicture const* const* SkBigPicture::drawablePicts() const {
return fDrawablePicts ? fDrawablePicts->begin() : nullptr;
}
SkBigPicture::Analysis::Analysis(const SkRecord& record) {
SkTextHunter text;
SkBitmapHunter bitmap;
SkPathCounter path;
bool hasText = false, hasBitmap = false;
for (unsigned i = 0; i < record.count(); i++) {
hasText = hasText || record.visit<bool>(i, text);
hasBitmap = hasBitmap || record.visit<bool>(i, bitmap);
record.visit<void>(i, path);
}
fHasText = hasText;
fWillPlaybackBitmaps = hasBitmap;
fNumSlowPathsAndDashEffects = SkTMin<int>(path.fNumSlowPathsAndDashEffects, 255);
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBigPicture_DEFINED
#define SkBigPicture_DEFINED
#include "SkPicture.h"
#include "SkLazyPtr.h"
class SkBBoxHierarchy;
class SkRecord;
// An implementation of SkPicture supporting an arbitrary number of drawing commands.
class SkBigPicture final : public SkPicture {
public:
// AccelData provides a base class for device-specific acceleration data.
class AccelData : public SkRefCnt { };
// An array of refcounted const SkPicture pointers.
class SnapshotArray : ::SkNoncopyable {
public:
SnapshotArray(const SkPicture* pics[], int count) : fPics(pics), fCount(count) {}
~SnapshotArray() { for (int i = 0; i < fCount; i++) { fPics[i]->unref(); } }
const SkPicture* const* begin() const { return fPics; }
int count() const { return fCount; }
private:
SkAutoTMalloc<const SkPicture*> fPics;
int fCount;
};
SkBigPicture(const SkRect& cull,
SkRecord*, // We take ownership of the caller's ref.
SnapshotArray*, // We take exclusive ownership.
SkBBoxHierarchy*, // We take ownership of the caller's ref.
AccelData*, // We take ownership of the caller's ref.
size_t approxBytesUsedBySubPictures);
// SkPicture overrides
void playback(SkCanvas*, AbortCallback*) const override;
SkRect cullRect() const override;
bool hasText() const override;
bool willPlayBackBitmaps() const override;
int approximateOpCount() const override;
size_t approximateBytesUsed() const override;
const SkBigPicture* asSkBigPicture() const override { return this; }
// Used by GrLayerHoister
void partialPlayback(SkCanvas*,
unsigned start,
unsigned stop,
const SkMatrix& initialCTM) const;
// Used by GrRecordReplaceDraw
const SkBBoxHierarchy* bbh() const { return fBBH; }
const SkRecord* record() const { return fRecord; }
const AccelData* accelData() const { return fAccelData; }
private:
struct Analysis {
explicit Analysis(const SkRecord&);
bool suitableForGpuRasterization(const char** reason) const;
uint8_t fNumSlowPathsAndDashEffects;
bool fWillPlaybackBitmaps : 1;
bool fHasText : 1;
};
int numSlowPaths() const override;
const Analysis& analysis() const;
int drawableCount() const;
SkPicture const* const* drawablePicts() const;
const SkRect fCullRect;
const size_t fApproxBytesUsedBySubPictures;
SkLazyPtr<const Analysis> fAnalysis;
SkAutoTUnref<const SkRecord> fRecord;
SkAutoTDelete<const SnapshotArray> fDrawablePicts;
SkAutoTUnref<const SkBBoxHierarchy> fBBH;
SkAutoTUnref<const AccelData> fAccelData;
};
#endif//SkBigPicture_DEFINED

15
src/core/SkLayerInfo.cpp Normal file
View File

@ -0,0 +1,15 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkLayerInfo.h"
SkPicture::AccelData::Key SkLayerInfo::ComputeKey() {
static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
return gGPUID;
}

View File

@ -8,12 +8,12 @@
#ifndef SkLayerInfo_DEFINED
#define SkLayerInfo_DEFINED
#include "SkBigPicture.h"
#include "SkPicture.h"
#include "SkTArray.h"
// This class stores information about the saveLayer/restore pairs found
// within an SkPicture. It is used by Ganesh to perform layer hoisting.
class SkLayerInfo : public SkBigPicture::AccelData {
class SkLayerInfo : public SkPicture::AccelData {
public:
// Information about a given saveLayer/restore block in an SkPicture
class BlockInfo {
@ -33,12 +33,12 @@ public:
SkRect fSrcBounds;
// The pre-matrix begins as the identity and accumulates the transforms
// of the containing SkPictures (if any). This matrix state has to be
// part of the initial matrix during replay so that it will be
// part of the initial matrix during replay so that it will be
// preserved across setMatrix calls.
SkMatrix fPreMat;
// The matrix state (in the leaf picture) in which this layer's draws
// The matrix state (in the leaf picture) in which this layer's draws
// must occur. It will/can be overridden by setMatrix calls in the
// layer itself. It does not include the translation needed to map the
// layer itself. It does not include the translation needed to map the
// layer's top-left point to the origin (which must be part of the
// initial matrix).
SkMatrix fLocalMat;
@ -60,7 +60,7 @@ public:
int fKeySize; // # of ints
};
SkLayerInfo() {}
SkLayerInfo(Key key) : INHERITED(key) { }
BlockInfo& addBlock() { return fBlocks.push_back(); }
@ -72,10 +72,14 @@ public:
return fBlocks[index];
}
// We may, in the future, need to pass in the GPUDevice in order to
// incorporate the clip and matrix state into the key
static SkPicture::AccelData::Key ComputeKey();
private:
SkTArray<BlockInfo, true> fBlocks;
typedef SkBigPicture::AccelData INHERITED;
typedef SkPicture::AccelData INHERITED;
};
#endif // SkLayerInfo_DEFINED

View File

@ -1,103 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkLazyPtr.h"
#include "SkMiniRecorder.h"
#include "SkPicture.h"
#include "SkPictureCommon.h"
#include "SkRecordDraw.h"
#include "SkTextBlob.h"
using namespace SkRecords;
class SkEmptyPicture final : public SkPicture {
public:
void playback(SkCanvas*, AbortCallback*) const override { }
size_t approximateBytesUsed() const override { return sizeof(*this); }
int approximateOpCount() const override { return 0; }
SkRect cullRect() const override { return SkRect::MakeEmpty(); }
bool hasText() const override { return false; }
int numSlowPaths() const override { return 0; }
bool willPlayBackBitmaps() const override { return false; }
};
SK_DECLARE_STATIC_LAZY_PTR(SkEmptyPicture, gEmptyPicture);
template <typename T>
class SkMiniPicture final : public SkPicture {
public:
SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts.
}
void playback(SkCanvas* c, AbortCallback*) const override {
SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
}
size_t approximateBytesUsed() const override { return sizeof(*this); }
int approximateOpCount() const override { return 1; }
SkRect cullRect() const override { return fCull; }
bool hasText() const override { return SkTextHunter()(fOp); }
bool willPlayBackBitmaps() const override { return SkBitmapHunter()(fOp); }
int numSlowPaths() const override {
SkPathCounter counter;
counter(fOp);
return counter.fNumSlowPathsAndDashEffects;
}
private:
SkRect fCull;
T fOp;
};
SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
SkMiniRecorder::~SkMiniRecorder() {
if (fState != State::kEmpty) {
// We have internal state pending.
// Detaching then deleting a picture is an easy way to clean up.
SkDELETE(this->detachAsPicture(SkRect::MakeEmpty()));
}
SkASSERT(fState == State::kEmpty);
}
#define TRY_TO_STORE(Type, ...) \
if (fState != State::kEmpty) { return false; } \
fState = State::k##Type; \
new (fBuffer.get()) Type(__VA_ARGS__); \
return true
bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
TRY_TO_STORE(DrawRect, paint, rect);
}
bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
TRY_TO_STORE(DrawPath, paint, path);
}
bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
TRY_TO_STORE(DrawTextBlob, p, b, x, y);
}
#undef TRY_TO_STORE
#define CASE(Type) \
case State::k##Type: \
fState = State::kEmpty; \
return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer.get())))
SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
switch (fState) {
case State::kEmpty: return SkRef(gEmptyPicture.get());
CASE(DrawPath);
CASE(DrawRect);
CASE(DrawTextBlob);
}
SkASSERT(false);
return NULL;
}
#undef CASE

View File

@ -1,44 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMiniRecorder_DEFINED
#define SkMiniRecorder_DEFINED
#include "SkRecords.h"
#include "SkScalar.h"
#include "SkTypes.h"
class SkCanvas;
// Records small pictures, but only a limited subset of the canvas API, and may fail.
class SkMiniRecorder : SkNoncopyable {
public:
SkMiniRecorder();
~SkMiniRecorder();
// Try to record an op. Returns false on failure.
bool drawPath(const SkPath&, const SkPaint&);
bool drawRect(const SkRect&, const SkPaint&);
bool drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint&);
// Detach anything we've recorded as a picture, resetting this SkMiniRecorder.
SkPicture* detachAsPicture(const SkRect& cull);
private:
enum class State { kEmpty, kDrawPath, kDrawRect, kDrawTextBlob };
State fState;
template <size_t A, size_t B>
struct Max { static const size_t val = A > B ? A : B; };
static const size_t kInlineStorage = Max<sizeof(SkRecords::DrawPath),
Max<sizeof(SkRecords::DrawRect),
sizeof(SkRecords::DrawTextBlob)>::val>::val;
SkAlignedSStorage<kInlineStorage> fBuffer;
};
#endif//SkMiniRecorder_DEFINED

View File

@ -5,107 +5,330 @@
* found in the LICENSE file.
*/
#include "SkAtomics.h"
#include "SkMessageBus.h"
#include "SkPicture.h"
#include "SkPictureFlat.h"
#include "SkPictureData.h"
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
#include "SkPictureRecorder.h"
#include "SkAtomics.h"
#include "SkBitmapDevice.h"
#include "SkCanvas.h"
#include "SkChunkAlloc.h"
#include "SkMessageBus.h"
#include "SkPaintPriv.h"
#include "SkPathEffect.h"
#include "SkPicture.h"
#include "SkRegion.h"
#include "SkShader.h"
#include "SkStream.h"
#include "SkTDArray.h"
#include "SkTLogic.h"
#include "SkTSearch.h"
#include "SkTime.h"
#include "SkReader32.h"
#include "SkWriter32.h"
#include "SkRTree.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#endif
#include "SkRecord.h"
#include "SkRecordDraw.h"
#include "SkRecordOpts.h"
#include "SkRecorder.h"
DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */
template <typename T> int SafeCount(const T* obj) {
return obj ? obj->count() : 0;
}
SkPicture::SkPicture() : fUniqueID(0) {}
///////////////////////////////////////////////////////////////////////////////
namespace {
// Some commands have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
/** SkRecords visitor to determine whether an instance may require an
"external" bitmap to rasterize. May return false positives.
Does not return true for bitmap text.
Expected use is to determine whether images need to be decoded before
rasterizing a particular SkRecord.
*/
struct BitmapTester {
// Helpers. These create HasMember_bitmap and HasMember_paint.
SK_CREATE_MEMBER_DETECTOR(bitmap);
SK_CREATE_MEMBER_DETECTOR(paint);
// Main entry for visitor:
// If the command is a DrawPicture, recurse.
// If the command has a bitmap directly, return true.
// If the command has a paint and the paint has a bitmap, return true.
// Otherwise, return false.
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
template <typename T>
bool operator()(const T& r) { return CheckBitmap(r); }
// If the command has a bitmap, of course we're going to play back bitmaps.
template <typename T>
static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
// If not, look for one in its paint (if it has a paint).
template <typename T>
static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
// If we have a paint, dig down into the effects looking for a bitmap.
template <typename T>
static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
const SkPaint* paint = AsPtr(r.paint);
if (paint) {
const SkShader* shader = paint->getShader();
if (shader &&
shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
return true;
}
}
return false;
}
// If we don't have a paint, that non-paint has no bitmap.
template <typename T>
static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
};
bool WillPlaybackBitmaps(const SkRecord& record) {
BitmapTester tester;
for (unsigned i = 0; i < record.count(); i++) {
if (record.visit<bool>(i, tester)) {
return true;
}
}
return false;
}
// SkRecord visitor to find recorded text.
struct TextHunter {
// All ops with text have that text as a char array member named "text".
SK_CREATE_MEMBER_DETECTOR(text);
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
template <typename T> SK_WHEN(HasMember_text<T>, bool) operator()(const T&) { return true; }
template <typename T> SK_WHEN(!HasMember_text<T>, bool) operator()(const T&) { return false; }
};
} // namespace
/** SkRecords visitor to determine heuristically whether or not a SkPicture
will be performant when rasterized on the GPU.
*/
struct SkPicture::PathCounter {
SK_CREATE_MEMBER_DETECTOR(paint);
PathCounter() : fNumSlowPathsAndDashEffects(0) {}
// Recurse into nested pictures.
void operator()(const SkRecords::DrawPicture& op) {
const SkPicture::Analysis& analysis = op.picture->analysis();
fNumSlowPathsAndDashEffects += analysis.fNumSlowPathsAndDashEffects;
}
void checkPaint(const SkPaint* paint) {
if (paint && paint->getPathEffect()) {
// Initially assume it's slow.
fNumSlowPathsAndDashEffects++;
}
}
void operator()(const SkRecords::DrawPoints& op) {
this->checkPaint(&op.paint);
const SkPathEffect* effect = op.paint.getPathEffect();
if (effect) {
SkPathEffect::DashInfo info;
SkPathEffect::DashType dashType = effect->asADash(&info);
if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
fNumSlowPathsAndDashEffects--;
}
}
}
void operator()(const SkRecords::DrawPath& op) {
this->checkPaint(&op.paint);
if (op.paint.isAntiAlias() && !op.path.isConvex()) {
SkPaint::Style paintStyle = op.paint.getStyle();
const SkRect& pathBounds = op.path.getBounds();
if (SkPaint::kStroke_Style == paintStyle &&
0 == op.paint.getStrokeWidth()) {
// AA hairline concave path is not slow.
} else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
pathBounds.height() < 64.f && !op.path.isVolatile()) {
// AADF eligible concave path is not slow.
} else {
fNumSlowPathsAndDashEffects++;
}
}
}
template <typename T>
SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
this->checkPaint(AsPtr(op.paint));
}
template <typename T>
SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
int fNumSlowPathsAndDashEffects;
};
SkPicture::Analysis::Analysis(const SkRecord& record) {
fWillPlaybackBitmaps = WillPlaybackBitmaps(record);
PathCounter counter;
for (unsigned i = 0; i < record.count(); i++) {
record.visit<void>(i, counter);
}
fNumSlowPathsAndDashEffects = SkTMin<int>(counter.fNumSlowPathsAndDashEffects, 255);
fHasText = false;
TextHunter text;
for (unsigned i = 0; i < record.count(); i++) {
if (record.visit<bool>(i, text)) {
fHasText = true;
break;
}
}
}
bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason,
int sampleCount) const {
// TODO: the heuristic used here needs to be refined
static const int kNumSlowPathsTol = 6;
bool ret = fNumSlowPathsAndDashEffects < kNumSlowPathsTol;
if (!ret && reason) {
*reason = "Too many slow paths (either concave or dashed).";
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int SkPicture::drawableCount() const {
return fDrawablePicts.get() ? fDrawablePicts->count() : 0;
}
SkPicture const* const* SkPicture::drawablePicts() const {
return fDrawablePicts.get() ? fDrawablePicts->begin() : NULL;
}
SkPicture::~SkPicture() {
// TODO: move this to ~SkBigPicture() only?
// If the ID is still zero, no one has read it, so no need to send this message.
uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
if (id != 0) {
SkPicture::DeletionMessage msg = { (int32_t)id };
SkPicture::DeletionMessage msg;
msg.fUniqueID = id;
SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
}
}
uint32_t SkPicture::uniqueID() const {
static uint32_t gNextID = 1;
uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
while (id == 0) {
uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
sk_memory_order_relaxed,
sk_memory_order_relaxed)) {
id = next;
} else {
// sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
}
const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
SkPicture::AccelData::Key key) const {
if (fAccelData.get() && fAccelData->getKey() == key) {
return fAccelData.get();
}
return id;
return NULL;
}
SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
static int32_t gNextID = 0;
int32_t id = sk_atomic_inc(&gNextID);
if (id >= 1 << (8 * sizeof(Domain))) {
SK_CRASH();
}
return static_cast<Domain>(id);
}
///////////////////////////////////////////////////////////////////////////////
void SkPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
SkASSERT(canvas);
// If the query contains the whole picture, don't bother with the BBH.
SkRect clipBounds = { 0, 0, 0, 0 };
(void)canvas->getClipBounds(&clipBounds);
const bool useBBH = !clipBounds.contains(this->cullRect());
SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
useBBH ? fBBH.get() : NULL, callback);
}
///////////////////////////////////////////////////////////////////////////////
#include "SkStream.h"
static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
SkPictInfo SkPicture::createHeader() const {
SkPictInfo info;
// Copy magic bytes at the beginning of the header
static_assert(sizeof(kMagic) == 8, "");
static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
memcpy(info.fMagic, kMagic, sizeof(kMagic));
// Set picture info after magic bytes in the header
info.fVersion = CURRENT_PICTURE_VERSION;
info.fCullRect = this->cullRect();
info.fFlags = SkPictInfo::kCrossProcess_Flag;
// TODO: remove this flag, since we're always float (now)
info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
if (8 == sizeof(void*)) {
info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
}
return info;
}
bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
return false;
}
if (info.fVersion < MIN_PICTURE_VERSION || info.fVersion > CURRENT_PICTURE_VERSION) {
if (info.fVersion < MIN_PICTURE_VERSION ||
info.fVersion > CURRENT_PICTURE_VERSION) {
return false;
}
return true;
}
bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
if (!stream) {
if (NULL == stream) {
return false;
}
// Check magic bytes.
SkPictInfo info;
SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
if (!stream->read(&info.fMagic, sizeof(kMagic))) {
return false;
}
info.fVersion = stream->readU32();
info.fCullRect.fLeft = stream->readScalar();
info.fCullRect.fTop = stream->readScalar();
info.fCullRect.fRight = stream->readScalar();
info.fVersion = stream->readU32();
info.fCullRect.fLeft = stream->readScalar();
info.fCullRect.fTop = stream->readScalar();
info.fCullRect.fRight = stream->readScalar();
info.fCullRect.fBottom = stream->readScalar();
info.fFlags = stream->readU32();
if (IsValidPictInfo(info)) {
if (pInfo) { *pInfo = info; }
return true;
info.fFlags = stream->readU32();
if (!IsValidPictInfo(info)) {
return false;
}
return false;
if (pInfo != NULL) {
*pInfo = info;
}
return true;
}
bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
// Check magic bytes.
SkPictInfo info;
SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
return false;
}
@ -114,29 +337,32 @@ bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo
buffer->readRect(&info.fCullRect);
info.fFlags = buffer->readUInt();
if (IsValidPictInfo(info)) {
if (pInfo) { *pInfo = info; }
return true;
if (!IsValidPictInfo(info)) {
return false;
}
return false;
if (pInfo != NULL) {
*pInfo = info;
}
return true;
}
SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
if (!data) {
return nullptr;
return NULL;
}
SkPicturePlayback playback(data);
SkPictureRecorder r;
playback.draw(r.beginRecording(SkScalarCeilToInt(info.fCullRect.width()),
SkScalarCeilToInt(info.fCullRect.height())),
nullptr/*no callback*/);
NULL/*no callback*/);
return r.endRecording();
}
SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
SkPictInfo info;
if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
return nullptr;
return NULL;
}
SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromStream(stream, info, proc));
return Forwardport(info, data);
@ -145,24 +371,45 @@ SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro
SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
SkPictInfo info;
if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
return nullptr;
return NULL;
}
SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
return Forwardport(info, data);
}
SkPictureData* SkPicture::backport() const {
SkPictInfo info = this->createHeader();
void SkPicture::createHeader(SkPictInfo* info) const {
// Copy magic bytes at the beginning of the header
SkASSERT(sizeof(kMagic) == 8);
SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
memcpy(info->fMagic, kMagic, sizeof(kMagic));
// Set picture info after magic bytes in the header
info->fVersion = CURRENT_PICTURE_VERSION;
info->fCullRect = this->cullRect();
info->fFlags = SkPictInfo::kCrossProcess_Flag;
// TODO: remove this flag, since we're always float (now)
info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
if (8 == sizeof(void*)) {
info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
}
}
// This for compatibility with serialization code only. This is not cheap.
SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
SkPicture const* const drawablePicts[], int drawableCount) {
SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
rec.beginRecording();
this->playback(&rec);
SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
rec.endRecording();
return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
}
void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
SkPictInfo info = this->createHeader();
SkAutoTDelete<SkPictureData> data(this->backport());
SkPictInfo info;
this->createHeader(&info);
SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
this->drawableCount()));
stream->write(&info, sizeof(info));
if (data) {
@ -174,8 +421,10 @@ void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer)
}
void SkPicture::flatten(SkWriteBuffer& buffer) const {
SkPictInfo info = this->createHeader();
SkAutoTDelete<SkPictureData> data(this->backport());
SkPictInfo info;
this->createHeader(&info);
SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
this->drawableCount()));
buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
buffer.writeUInt(info.fVersion);
@ -189,10 +438,49 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
}
}
bool SkPicture::suitableForGpuRasterization(GrContext*, const char** whyNot) const {
if (this->numSlowPaths() > 5) {
if (whyNot) { *whyNot = "Too many slow paths (either concave or dashed)."; }
return false;
}
return true;
const SkPicture::Analysis& SkPicture::analysis() const {
auto create = [&](){ return SkNEW_ARGS(Analysis, (*fRecord)); };
return *fAnalysis.get(create);
}
#if SK_SUPPORT_GPU
bool SkPicture::suitableForGpuRasterization(GrContext*, const char **reason) const {
return this->analysis().suitableForGpuRasterization(reason, 0);
}
#endif
bool SkPicture::hasText() const { return this->analysis().fHasText; }
bool SkPicture::willPlayBackBitmaps() const { return this->analysis().fWillPlaybackBitmaps; }
int SkPicture::approximateOpCount() const { return fRecord->count(); }
SkPicture::SkPicture(const SkRect& cullRect,
SkRecord* record,
SnapshotArray* drawablePicts,
SkBBoxHierarchy* bbh,
AccelData* accelData,
size_t approxBytesUsedBySubPictures)
: fUniqueID(0)
, fCullRect(cullRect)
, fRecord(record) // Take ownership of caller's ref.
, fDrawablePicts(drawablePicts) // Take ownership.
, fBBH(bbh) // Take ownership of caller's ref.
, fAccelData(accelData) // Take ownership of caller's ref.
, fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
{}
static uint32_t gNextID = 1;
uint32_t SkPicture::uniqueID() const {
uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
while (id == 0) {
uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
sk_memory_order_relaxed,
sk_memory_order_relaxed)) {
id = next;
} else {
// sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
}
}
return id;
}

View File

@ -1,136 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// Some shared code used by both SkBigPicture and SkMiniPicture.
// SkTextHunter -- SkRecord visitor that returns true when the op draws text.
// SkBitmapHunter -- SkRecord visitor that returns true when the op draws a bitmap.
// SkPathCounter -- SkRecord visitor that counts paths that draw slowly on the GPU.
#include "SkPathEffect.h"
#include "SkRecords.h"
#include "SkTLogic.h"
struct SkTextHunter {
// Most ops never have text. Some always do. Subpictures know themeselves.
template <typename T> bool operator()(const T&) { return false; }
bool operator()(const SkRecords::DrawPosText&) { return true; }
bool operator()(const SkRecords::DrawPosTextH&) { return true; }
bool operator()(const SkRecords::DrawText&) { return true; }
bool operator()(const SkRecords::DrawTextBlob&) { return true; }
bool operator()(const SkRecords::DrawTextOnPath&) { return true; }
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
};
struct SkBitmapHunter {
// Helpers. These create HasMember_bitmap and HasMember_paint.
SK_CREATE_MEMBER_DETECTOR(bitmap);
SK_CREATE_MEMBER_DETECTOR(paint);
// Some ops have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
// Main entry for visitor:
// If the op is a DrawPicture, recurse.
// If the op has a bitmap directly, return true.
// If the op has a paint and the paint has a bitmap, return true.
// Otherwise, return false.
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
template <typename T>
bool operator()(const T& r) { return CheckBitmap(r); }
// If the op has a bitmap, of course we're going to play back bitmaps.
template <typename T>
static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
// If not, look for one in its paint (if it has a paint).
template <typename T>
static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
// If we have a paint, dig down into the effects looking for a bitmap.
template <typename T>
static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
const SkPaint* paint = AsPtr(r.paint);
if (paint) {
const SkShader* shader = paint->getShader();
if (shader &&
shader->asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
return true;
}
}
return false;
}
// If we don't have a paint, that non-paint has no bitmap.
template <typename T>
static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
};
// TODO: might be nicer to have operator() return an int (the number of slow paths) ?
struct SkPathCounter {
SK_CREATE_MEMBER_DETECTOR(paint);
// Some ops have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
SkPathCounter() : fNumSlowPathsAndDashEffects(0) {}
// Recurse into nested pictures.
void operator()(const SkRecords::DrawPicture& op) {
fNumSlowPathsAndDashEffects += op.picture->numSlowPaths();
}
void checkPaint(const SkPaint* paint) {
if (paint && paint->getPathEffect()) {
// Initially assume it's slow.
fNumSlowPathsAndDashEffects++;
}
}
void operator()(const SkRecords::DrawPoints& op) {
this->checkPaint(&op.paint);
const SkPathEffect* effect = op.paint.getPathEffect();
if (effect) {
SkPathEffect::DashInfo info;
SkPathEffect::DashType dashType = effect->asADash(&info);
if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
fNumSlowPathsAndDashEffects--;
}
}
}
void operator()(const SkRecords::DrawPath& op) {
this->checkPaint(&op.paint);
if (op.paint.isAntiAlias() && !op.path.isConvex()) {
SkPaint::Style paintStyle = op.paint.getStyle();
const SkRect& pathBounds = op.path.getBounds();
if (SkPaint::kStroke_Style == paintStyle &&
0 == op.paint.getStrokeWidth()) {
// AA hairline concave path is not slow.
} else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
pathBounds.height() < 64.f && !op.path.isVolatile()) {
// AADF eligible concave path is not slow.
} else {
fNumSlowPathsAndDashEffects++;
}
}
}
template <typename T>
SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
this->checkPaint(AsPtr(op.paint));
}
template <typename T>
SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
int fNumSlowPathsAndDashEffects;
};

View File

@ -5,7 +5,6 @@
* found in the LICENSE file.
*/
#include "SkBigPicture.h"
#include "SkData.h"
#include "SkDrawable.h"
#include "SkLayerInfo.h"
@ -19,7 +18,7 @@
SkPictureRecorder::SkPictureRecorder() {
fActivelyRecording = false;
fRecorder.reset(SkNEW_ARGS(SkRecorder, (nullptr, SkRect::MakeWH(0,0), &fMiniRecorder)));
fRecorder.reset(SkNEW_ARGS(SkRecorder, (nullptr, SkRect::MakeWH(0,0))));
}
SkPictureRecorder::~SkPictureRecorder() {}
@ -35,10 +34,8 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
SkASSERT(fBBH.get());
}
if (!fRecord) {
fRecord.reset(SkNEW(SkRecord));
}
fRecorder->reset(fRecord.get(), cullRect, &fMiniRecorder);
fRecord.reset(SkNEW(SkRecord));
fRecorder->reset(fRecord.get(), cullRect);
fActivelyRecording = true;
return this->getRecordingCanvas();
}
@ -50,23 +47,19 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
SkPicture* SkPictureRecorder::endRecordingAsPicture() {
fActivelyRecording = false;
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
if (fRecord->count() == 0) {
return fMiniRecorder.detachAsPicture(fCullRect);
}
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);
SkAutoTUnref<SkLayerInfo> saveLayerData;
if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) {
saveLayerData.reset(SkNEW(SkLayerInfo));
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
}
SkDrawableList* drawableList = fRecorder->getDrawableList();
SkBigPicture::SnapshotArray* pictList =
drawableList ? drawableList->newDrawableSnapshot() : NULL;
SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL;
if (fBBH.get()) {
if (saveLayerData) {
@ -84,12 +77,12 @@ SkPicture* SkPictureRecorder::endRecordingAsPicture() {
for (int i = 0; pictList && i < pictList->count(); i++) {
subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
}
return SkNEW_ARGS(SkBigPicture, (fCullRect,
fRecord.detach(),
pictList,
fBBH.detach(),
saveLayerData.detach(),
subPictureBytes));
return SkNEW_ARGS(SkPicture, (fCullRect,
fRecord.detach(),
pictList,
fBBH.detach(),
saveLayerData.detach(),
subPictureBytes));
}
void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
@ -140,7 +133,7 @@ protected:
}
SkPicture* onNewPictureSnapshot() override {
SkBigPicture::SnapshotArray* pictList = NULL;
SkPicture::SnapshotArray* pictList = NULL;
if (fDrawableList) {
// TODO: should we plumb-down the BBHFactory and recordFlags from our host
// PictureRecorder?
@ -150,7 +143,9 @@ protected:
SkAutoTUnref<SkLayerInfo> saveLayerData;
if (fBBH && fDoSaveLayerInfo) {
saveLayerData.reset(SkNEW(SkLayerInfo));
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
SkBBoxHierarchy* bbh = NULL; // we've already computed fBBH (received in constructor)
// TODO: update saveLayer info computation to reuse the already computed
@ -162,22 +157,20 @@ protected:
for (int i = 0; pictList && i < pictList->count(); i++) {
subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
}
// SkBigPicture will take ownership of a ref on both fRecord and fBBH.
// SkPicture will take ownership of a ref on both fRecord and fBBH.
// We're not willing to give up our ownership, so we must ref them for SkPicture.
return SkNEW_ARGS(SkBigPicture, (fBounds,
SkRef(fRecord.get()),
pictList,
SkSafeRef(fBBH.get()),
saveLayerData.detach(),
subPictureBytes));
return SkNEW_ARGS(SkPicture, (fBounds,
SkRef(fRecord.get()),
pictList,
SkSafeRef(fBBH.get()),
saveLayerData.detach(),
subPictureBytes));
}
};
SkDrawable* SkPictureRecorder::endRecordingAsDrawable() {
fActivelyRecording = false;
fRecorder->flushMiniRecorder();
fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);

View File

@ -587,7 +587,7 @@ private:
class CollectLayers : SkNoncopyable {
public:
CollectLayers(const SkRect& cullRect, const SkRecord& record,
const SkBigPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
: fSaveLayersInStack(0)
, fAccelData(accelData)
, fPictList(pictList)
@ -640,10 +640,10 @@ private:
void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
// For sub-pictures, we wrap their layer information within the parent
// picture's rendering hierarchy
const SkLayerInfo* childData = NULL;
if (const SkBigPicture* bp = picture->asSkBigPicture()) {
childData = static_cast<const SkLayerInfo*>(bp->accelData());
}
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkLayerInfo* childData =
static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
if (!childData) {
// If the child layer hasn't been generated with saveLayer data we
// assume the worst (i.e., that it does contain layers which nest
@ -774,7 +774,7 @@ private:
// The op code indices of all the currently active saveLayers
SkTDArray<unsigned> fSaveLayerOpStack;
SkLayerInfo* fAccelData;
const SkBigPicture::SnapshotArray* fPictList;
const SkPicture::SnapshotArray* fPictList;
SkRecords::FillBounds fFillBounds;
};
@ -793,7 +793,7 @@ void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
}
void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
const SkBigPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
SkLayerInfo* data) {
SkRecords::CollectLayers visitor(cullRect, record, pictList, data);

View File

@ -9,7 +9,6 @@
#define SkRecordDraw_DEFINED
#include "SkBBoxHierarchy.h"
#include "SkBigPicture.h"
#include "SkCanvas.h"
#include "SkMatrix.h"
#include "SkRecord.h"
@ -21,7 +20,7 @@ class SkLayerInfo;
void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy*);
void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
const SkBigPicture::SnapshotArray*,
const SkPicture::SnapshotArray*,
SkBBoxHierarchy* bbh, SkLayerInfo* data);
// Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::Draw.

View File

@ -5,7 +5,6 @@
* found in the LICENSE file.
*/
#include "SkBigPicture.h"
#include "SkPatchUtils.h"
#include "SkPicture.h"
#include "SkPictureUtils.h"
@ -15,7 +14,7 @@ SkDrawableList::~SkDrawableList() {
fArray.unrefAll();
}
SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
SkPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
const int count = fArray.count();
if (0 == count) {
return NULL;
@ -24,7 +23,7 @@ SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
for (int i = 0; i < count; ++i) {
pics[i] = fArray[i]->newPictureSnapshot();
}
return SkNEW_ARGS(SkBigPicture::SnapshotArray, (pics.detach(), count));
return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
}
void SkDrawableList::append(SkDrawable* drawable) {
@ -33,23 +32,20 @@ void SkDrawableList::append(SkDrawable* drawable) {
///////////////////////////////////////////////////////////////////////////////////////////////
SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr)
SkRecorder::SkRecorder(SkRecord* record, int width, int height)
: SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
, fApproxBytesUsedBySubPictures(0)
, fRecord(record)
, fMiniRecorder(mr) {}
, fRecord(record) {}
SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr)
SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
: SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
, fApproxBytesUsedBySubPictures(0)
, fRecord(record)
, fMiniRecorder(mr) {}
, fRecord(record) {}
void SkRecorder::reset(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr) {
void SkRecorder::reset(SkRecord* record, const SkRect& bounds) {
this->forgetRecord();
fRecord = record;
this->resetForNextPicture(bounds.roundOut());
fMiniRecorder = mr;
}
void SkRecorder::forgetRecord() {
@ -59,13 +55,9 @@ void SkRecorder::forgetRecord() {
}
// To make appending to fRecord a little less verbose.
#define APPEND(T, ...) \
if (fMiniRecorder) { this->flushMiniRecorder(); } \
#define APPEND(T, ...) \
SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
#define TRY_MINIRECORDER(method, ...) \
if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; }
// For methods which must call back into SkCanvas.
#define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
@ -133,15 +125,6 @@ char* SkRecorder::copy(const char* src) {
return this->copy(src, strlen(src)+1);
}
void SkRecorder::flushMiniRecorder() {
if (fMiniRecorder) {
SkMiniRecorder* mr = fMiniRecorder;
fMiniRecorder = nullptr; // Needs to happen before p->playback(this) or we loop forever.
// TODO: this can probably be done more efficiently by SkMiniRecorder if it matters.
SkAutoTUnref<SkPicture> p(mr->detachAsPicture(SkRect::MakeEmpty()));
p->playback(this);
}
}
void SkRecorder::onDrawPaint(const SkPaint& paint) {
APPEND(DrawPaint, delay_copy(paint));
@ -155,7 +138,6 @@ void SkRecorder::onDrawPoints(PointMode mode,
}
void SkRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
TRY_MINIRECORDER(drawRect, rect, paint);
APPEND(DrawRect, delay_copy(paint), rect);
}
@ -180,7 +162,6 @@ void SkRecorder::onDrawDrawable(SkDrawable* drawable) {
}
void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
TRY_MINIRECORDER(drawPath, path, paint);
APPEND(DrawPath, delay_copy(paint), delay_copy(path));
}
@ -267,7 +248,6 @@ void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkP
void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint);
APPEND(DrawTextBlob, delay_copy(paint), blob, x, y);
}

View File

@ -8,9 +8,7 @@
#ifndef SkRecorder_DEFINED
#define SkRecorder_DEFINED
#include "SkBigPicture.h"
#include "SkCanvas.h"
#include "SkMiniRecorder.h"
#include "SkRecord.h"
#include "SkRecords.h"
#include "SkTDArray.h"
@ -27,7 +25,7 @@ public:
void append(SkDrawable* drawable);
// Return a new or ref'd array of pictures that were snapped from our drawables.
SkBigPicture::SnapshotArray* newDrawableSnapshot();
SkPicture::SnapshotArray* newDrawableSnapshot();
private:
SkTDArray<SkDrawable*> fArray;
@ -38,10 +36,10 @@ private:
class SkRecorder : public SkCanvas {
public:
// Does not take ownership of the SkRecord.
SkRecorder(SkRecord*, int width, int height, SkMiniRecorder* = nullptr); // legacy version
SkRecorder(SkRecord*, const SkRect& bounds, SkMiniRecorder* = nullptr);
SkRecorder(SkRecord*, int width, int height); // legacy version
SkRecorder(SkRecord*, const SkRect& bounds);
void reset(SkRecord*, const SkRect& bounds, SkMiniRecorder* = nullptr);
void reset(SkRecord*, const SkRect& bounds);
size_t approxBytesUsedBySubPictures() const { return fApproxBytesUsedBySubPictures; }
@ -122,8 +120,6 @@ public:
SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override { return NULL; }
void flushMiniRecorder();
private:
template <typename T>
T* copy(const T*);
@ -140,8 +136,6 @@ private:
size_t fApproxBytesUsedBySubPictures;
SkRecord* fRecord;
SkAutoTDelete<SkDrawableList> fDrawableList;
SkMiniRecorder* fMiniRecorder;
};
#endif//SkRecorder_DEFINED

View File

@ -81,7 +81,6 @@ struct T { \
#define RECORD1(T, A, a) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z> \
T(Z a) : a(a) {} \
A a; \
@ -90,7 +89,6 @@ struct T { \
#define RECORD2(T, A, a, B, b) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y> \
T(Z a, Y b) : a(a), b(b) {} \
A a; B b; \
@ -99,7 +97,6 @@ struct T { \
#define RECORD3(T, A, a, B, b, C, c) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X> \
T(Z a, Y b, X c) : a(a), b(b), c(c) {} \
A a; B b; C c; \
@ -108,7 +105,6 @@ struct T { \
#define RECORD4(T, A, a, B, b, C, c, D, d) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W> \
T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {} \
A a; B b; C c; D d; \
@ -117,7 +113,6 @@ struct T { \
#define RECORD5(T, A, a, B, b, C, c, D, d, E, e) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W, typename V> \
T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {} \
A a; B b; C c; D d; E e; \
@ -130,7 +125,6 @@ struct T { \
template <typename T>
class RefBox : SkNoncopyable {
public:
RefBox() {}
RefBox(T* obj) : fObj(SkSafeRef(obj)) {}
~RefBox() { SkSafeUnref(fObj); }
@ -144,7 +138,6 @@ private:
template <typename T>
class Optional : SkNoncopyable {
public:
Optional() : fPtr(nullptr) {}
Optional(T* ptr) : fPtr(ptr) {}
~Optional() { if (fPtr) fPtr->~T(); }
@ -174,7 +167,6 @@ private:
template <typename T>
class PODArray {
public:
PODArray() {}
PODArray(T* ptr) : fPtr(ptr) {}
// Default copy and assign.
@ -189,7 +181,6 @@ private:
// Using this, we guarantee the immutability of all bitmaps we record.
class ImmutableBitmap : SkNoncopyable {
public:
ImmutableBitmap() {}
explicit ImmutableBitmap(const SkBitmap& bitmap) {
if (bitmap.isImmutable()) {
fBitmap = bitmap;
@ -212,7 +203,6 @@ private:
// SkPath::cheapComputeDirection() is similar.
// Recording is a convenient time to cache these, or we can delay it to between record and playback.
struct PreCachedPath : public SkPath {
PreCachedPath() {}
explicit PreCachedPath(const SkPath& path) : SkPath(path) {
this->updateBoundsCache();
SkPath::Direction junk;
@ -223,7 +213,6 @@ struct PreCachedPath : public SkPath {
// Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it.
// This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader).
struct TypedMatrix : public SkMatrix {
TypedMatrix() {}
explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) {
(void)this->getType();
}
@ -238,7 +227,6 @@ RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas:
RECORD1(SetMatrix, TypedMatrix, matrix);
struct RegionOpAndAA {
RegionOpAndAA() {}
RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {}
SkRegion::Op op : 31; // This really only needs to be 3, but there's no win today to do so.
unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned.

View File

@ -9,7 +9,6 @@
#include "GrLayerHoister.h"
#include "GrRecordReplaceDraw.h"
#include "SkBigPicture.h"
#include "SkCanvas.h"
#include "SkDeviceImageFilterProxy.h"
#include "SkDeviceProperties.h"
@ -22,7 +21,7 @@
// Create the layer information for the hoisted layer and secure the
// required texture/render target resources.
static void prepare_for_hoisting(GrLayerCache* layerCache,
static void prepare_for_hoisting(GrLayerCache* layerCache,
const SkPicture* topLevelPicture,
const SkMatrix& initialMat,
const SkLayerInfo::BlockInfo& info,
@ -75,7 +74,7 @@ static void prepare_for_hoisting(GrLayerCache* layerCache,
} else {
hl = recycled->append();
}
layerCache->addUse(layer);
hl->fLayer = layer;
hl->fPicture = pict;
@ -130,12 +129,12 @@ void GrLayerHoister::FindLayersToAtlas(GrContext* context,
}
GrLayerCache* layerCache = context->getLayerCache();
layerCache->processDeletedPictures();
const SkBigPicture::AccelData* topLevelData = NULL;
if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
topLevelData = bp->accelData();
}
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
if (!topLevelData) {
return;
}
@ -190,10 +189,9 @@ void GrLayerHoister::FindLayersToHoist(GrContext* context,
layerCache->processDeletedPictures();
const SkBigPicture::AccelData* topLevelData = NULL;
if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
topLevelData = bp->accelData();
}
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
if (!topLevelData) {
return;
}
@ -241,11 +239,7 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
for (int i = 0; i < atlased.count(); ++i) {
const GrCachedLayer* layer = atlased[i].fLayer;
const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture();
if (!pict) {
// TODO: can we assume / assert this?
continue;
}
const SkPicture* pict = atlased[i].fPicture;
const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();)
@ -271,7 +265,10 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
atlasCanvas->setMatrix(initialCTM);
atlasCanvas->concat(atlased[i].fLocalMat);
pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop(), initialCTM);
SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas,
pict->drawablePicts(), pict->drawableCount(),
layer->start() + 1, layer->stop(), initialCTM);
atlasCanvas->restore();
}
@ -331,11 +328,7 @@ void GrLayerHoister::FilterLayer(GrContext* context,
void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) {
for (int i = 0; i < layers.count(); ++i) {
GrCachedLayer* layer = layers[i].fLayer;
const SkBigPicture* pict = layers[i].fPicture->asSkBigPicture();
if (!pict) {
// TODO: can we assume / assert this?
continue;
}
const SkPicture* pict = layers[i].fPicture;
const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
// Each non-atlased layer has its own GrTexture
@ -360,7 +353,10 @@ void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLay
layerCanvas->setMatrix(initialCTM);
layerCanvas->concat(layers[i].fLocalMat);
pict->partialPlayback(layerCanvas, layer->start()+1, layer->stop(), initialCTM);
SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas,
pict->drawablePicts(), pict->drawableCount(),
layer->start()+1, layer->stop(), initialCTM);
layerCanvas->flush();
if (layer->filter()) {

View File

@ -8,7 +8,6 @@
#include "GrContext.h"
#include "GrLayerCache.h"
#include "GrRecordReplaceDraw.h"
#include "SkBigPicture.h"
#include "SkCanvasPriv.h"
#include "SkGrPixelRef.h"
#include "SkImage.h"
@ -46,7 +45,7 @@ static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canva
canvas->drawBitmapRectToRect(bm, &src, dst, layer->paint());
canvas->restore();
} else {
canvas->drawSprite(bm,
canvas->drawSprite(bm,
layer->srcIR().fLeft + layer->offset().fX,
layer->srcIR().fTop + layer->offset().fY,
layer->paint());
@ -60,7 +59,7 @@ public:
ReplaceDraw(SkCanvas* canvas, GrLayerCache* layerCache,
SkPicture const* const drawablePicts[], int drawableCount,
const SkPicture* topLevelPicture,
const SkBigPicture* picture,
const SkPicture* picture,
const SkMatrix& initialMatrix,
SkPicture::AbortCallback* callback,
const unsigned* opIndices, int numIndices)
@ -77,8 +76,8 @@ public:
}
int draw() {
const SkBBoxHierarchy* bbh = fPicture->bbh();
const SkRecord* record = fPicture->record();
const SkBBoxHierarchy* bbh = fPicture->fBBH.get();
const SkRecord* record = fPicture->fRecord.get();
if (NULL == record) {
return 0;
}
@ -136,17 +135,13 @@ public:
SkAutoCanvasMatrixPaint acmp(fCanvas, &dp.matrix, dp.paint, dp.picture->cullRect());
if (const SkBigPicture* bp = dp.picture->asSkBigPicture()) {
// Draw sub-pictures with the same replacement list but a different picture
ReplaceDraw draw(fCanvas, fLayerCache,
this->drawablePicts(), this->drawableCount(),
fTopLevelPicture, bp, fInitialMatrix, fCallback,
fOpIndexStack.begin(), fOpIndexStack.count());
fNumReplaced += draw.draw();
} else {
// TODO: can we assume / assert this doesn't happen?
dp.picture->playback(fCanvas, fCallback);
}
// Draw sub-pictures with the same replacement list but a different picture
ReplaceDraw draw(fCanvas, fLayerCache,
this->drawablePicts(), this->drawableCount(),
fTopLevelPicture, dp.picture, fInitialMatrix, fCallback,
fOpIndexStack.begin(), fOpIndexStack.count());
fNumReplaced += draw.draw();
fOpIndexStack.pop();
}
@ -173,7 +168,7 @@ public:
draw_replacement_bitmap(layer, fCanvas);
if (fPicture->bbh()) {
if (fPicture->fBBH.get()) {
while (fOps[fIndex] < layer->stop()) {
++fIndex;
}
@ -195,7 +190,7 @@ private:
SkCanvas* fCanvas;
GrLayerCache* fLayerCache;
const SkPicture* fTopLevelPicture;
const SkBigPicture* fPicture;
const SkPicture* fPicture;
const SkMatrix fInitialMatrix;
SkPicture::AbortCallback* fCallback;
@ -216,15 +211,9 @@ int GrRecordReplaceDraw(const SkPicture* picture,
SkPicture::AbortCallback* callback) {
SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
if (const SkBigPicture* bp = picture->asSkBigPicture()) {
// TODO: drawablePicts?
ReplaceDraw draw(canvas, layerCache, NULL, 0,
bp, bp,
initialMatrix, callback, NULL, 0);
return draw.draw();
} else {
// TODO: can we assume / assert this doesn't happen?
picture->playback(canvas, callback);
return 0;
}
// TODO: drawablePicts?
ReplaceDraw draw(canvas, layerCache, NULL, 0,
picture, picture,
initialMatrix, callback, NULL, 0);
return draw.draw();
}

View File

@ -1999,10 +1999,9 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
return false;
}
const SkBigPicture::AccelData* data = NULL;
if (const SkBigPicture* bp = mainPicture->asSkBigPicture()) {
data = bp->accelData();
}
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkPicture::AccelData* data = mainPicture->EXPERIMENTAL_getAccelData(key);
if (!data) {
return false;
}

View File

@ -217,6 +217,8 @@ private:
bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
static SkPicture::AccelData::Key ComputeAccelDataKey();
static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
int sampleCount);

View File

@ -0,0 +1,25 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBBoxHierarchy.h"
#include "SkCanvas.h"
#include "SkData.h"
#include "SkPictureUtils.h"
#include "SkRecord.h"
#include "SkShader.h"
size_t SkPictureUtils::ApproximateBytesUsed(const SkPicture* pict) {
size_t byteCount = sizeof(*pict);
byteCount += pict->fRecord->bytesUsed();
if (pict->fBBH.get()) {
byteCount += pict->fBBH->bytesUsed();
}
byteCount += pict->fApproxBytesUsedBySubPictures;
return byteCount;
}

View File

@ -111,10 +111,7 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
}
SkPictureRecorder recorder;
SkCanvas* c = recorder.beginRecording(1, 1);
// Draw something, anything, to prevent an empty-picture optimization,
// which is a singleton and never purged.
c->drawRect(SkRect::MakeWH(1,1), SkPaint());
recorder.beginRecording(1, 1);
SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
GrLayerCache cache(context);

View File

@ -23,7 +23,6 @@
#include "SkPictureUtils.h"
#include "SkPixelRef.h"
#include "SkPixelSerializer.h"
#include "SkMiniRecorder.h"
#include "SkRRect.h"
#include "SkRandom.h"
#include "SkRecord.h"
@ -364,10 +363,9 @@ static void test_savelayer_extraction(skiatest::Reporter* reporter) {
// Now test out the SaveLayer extraction
if (!SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds()) {
const SkBigPicture* bp = pict->asSkBigPicture();
REPORTER_ASSERT(reporter, bp);
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkBigPicture::AccelData* data = bp->accelData();
const SkPicture::AccelData* data = pict->EXPERIMENTAL_getAccelData(key);
REPORTER_ASSERT(reporter, data);
const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
@ -1109,6 +1107,30 @@ static void test_gen_id(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
}
static void test_bytes_used(skiatest::Reporter* reporter) {
SkPictureRecorder recorder;
recorder.beginRecording(0, 0);
SkAutoTUnref<SkPicture> empty(recorder.endRecording());
// Sanity check to make sure we aren't under-measuring.
REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) >=
sizeof(SkPicture) + sizeof(SkRecord));
// Protect against any unintentional bloat.
size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get());
REPORTER_ASSERT(reporter, approxUsed <= 432);
// Sanity check of nested SkPictures.
SkPictureRecorder r2;
r2.beginRecording(0, 0);
r2.getRecordingCanvas()->drawPicture(empty.get());
SkAutoTUnref<SkPicture> nested(r2.endRecording());
REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(nested.get()) >=
SkPictureUtils::ApproximateBytesUsed(empty.get()));
}
DEF_TEST(Picture, reporter) {
#ifdef SK_DEBUG
test_deleting_empty_picture();
@ -1129,6 +1151,7 @@ DEF_TEST(Picture, reporter) {
test_hierarchical(reporter);
test_gen_id(reporter);
test_savelayer_extraction(reporter);
test_bytes_used(reporter);
}
static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
@ -1244,10 +1267,7 @@ DEF_TEST(Picture_SkipBBH, r) {
SpoonFedBBHFactory factory(&bbh);
SkPictureRecorder recorder;
SkCanvas* c = recorder.beginRecording(bound, &factory);
// Record a few ops so we don't hit a small- or empty- picture optimization.
c->drawRect(bound, SkPaint());
c->drawRect(bound, SkPaint());
recorder.beginRecording(bound, &factory);
SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
SkCanvas big(640, 480), small(300, 200);
@ -1303,13 +1323,3 @@ DEF_TEST(Picture_getRecordingCanvas, r) {
REPORTER_ASSERT(r, !rec.getRecordingCanvas());
}
}
DEF_TEST(MiniRecorderLeftHanging, r) {
// Any shader or other ref-counted effect will do just fine here.
SkPaint paint;
paint.setShader(SkShader::CreateColorShader(SK_ColorRED))->unref();
SkMiniRecorder rec;
REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
// Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
}