Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Unified Diff: src/core/SkPicture.cpp

Issue 1112523006: Sketch splitting SkPicture into an interface and SkBigPicture. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: note Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkMiniRecorder.cpp ('k') | src/core/SkPictureCommon.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkPicture.cpp
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 0145cbe5d7adab19f0b8602a1a5e0bb69c297c0f..6c1f6cb759ee5f9338877e2bf3ea5bb37dc03ae8 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -5,330 +5,107 @@
* found in the LICENSE file.
*/
-
-#include "SkPictureFlat.h"
+#include "SkAtomics.h"
+#include "SkMessageBus.h"
+#include "SkPicture.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);
-template <typename T> int SafeCount(const T* obj) {
- return obj ? obj->count() : 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);
-
+/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */
- // 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() : fUniqueID(0) {}
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;
- msg.fUniqueID = id;
+ SkPicture::DeletionMessage msg = { (int32_t)id };
SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
}
}
-const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
- SkPicture::AccelData::Key key) const {
- if (fAccelData.get() && fAccelData->getKey() == key) {
- return fAccelData.get();
- }
- 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();
+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.
+ }
}
-
- return static_cast<Domain>(id);
+ return id;
}
-///////////////////////////////////////////////////////////////////////////////
+static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
-void SkPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
- SkASSERT(canvas);
+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));
- // 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());
+ // 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;
- SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
- useBBH ? fBBH.get() : NULL, callback);
+ if (8 == sizeof(void*)) {
+ info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
+ }
+ return info;
}
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkStream.h"
-
-static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
-
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 (NULL == stream) {
+ if (!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();
- info.fFlags = stream->readU32();
-
- if (!IsValidPictInfo(info)) {
- return false;
- }
-
- if (pInfo != NULL) {
- *pInfo = info;
+ if (IsValidPictInfo(info)) {
+ if (pInfo) { *pInfo = info; }
+ return true;
}
- return true;
+ return false;
}
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;
}
@@ -337,32 +114,29 @@ bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo
buffer->readRect(&info.fCullRect);
info.fFlags = buffer->readUInt();
- if (!IsValidPictInfo(info)) {
- return false;
+ if (IsValidPictInfo(info)) {
+ if (pInfo) { *pInfo = info; }
+ return true;
}
-
- if (pInfo != NULL) {
- *pInfo = info;
- }
- return true;
+ return false;
}
SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
if (!data) {
- return NULL;
+ return nullptr;
}
SkPicturePlayback playback(data);
SkPictureRecorder r;
playback.draw(r.beginRecording(SkScalarCeilToInt(info.fCullRect.width()),
SkScalarCeilToInt(info.fCullRect.height())),
- NULL/*no callback*/);
+ nullptr/*no callback*/);
return r.endRecording();
}
SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
SkPictInfo info;
if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
- return NULL;
+ return nullptr;
}
SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromStream(stream, info, proc));
return Forwardport(info, data);
@@ -371,45 +145,24 @@ SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro
SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
SkPictInfo info;
if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
- return NULL;
+ return nullptr;
}
SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
return Forwardport(info, data);
}
-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) {
+SkPictureData* SkPicture::backport() const {
+ SkPictInfo info = this->createHeader();
SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
rec.beginRecording();
- SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
+ this->playback(&rec);
rec.endRecording();
return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
}
void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
- SkPictInfo info;
- this->createHeader(&info);
- SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
- this->drawableCount()));
+ SkPictInfo info = this->createHeader();
+ SkAutoTDelete<SkPictureData> data(this->backport());
stream->write(&info, sizeof(info));
if (data) {
@@ -421,10 +174,8 @@ void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer)
}
void SkPicture::flatten(SkWriteBuffer& buffer) const {
- SkPictInfo info;
- this->createHeader(&info);
- SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
- this->drawableCount()));
+ SkPictInfo info = this->createHeader();
+ SkAutoTDelete<SkPictureData> data(this->backport());
buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
buffer.writeUInt(info.fVersion);
@@ -438,49 +189,10 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
}
}
-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.
- }
+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 id;
+ return true;
}
« no previous file with comments | « src/core/SkMiniRecorder.cpp ('k') | src/core/SkPictureCommon.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698