SkPDF: refactor streams, experimental threading
All PDF Streams are immediatly serialized, and are never long-lived
in memory.
if EXPERIMENTAL fExecutor is set on the Document, streams are
compressed in parallel.
Results for PDFBigDocBench:
without patch 1807885.01 μs
with patch without executor 1802808.35 μs
with patch with executor 246313.72 μs
SkPDFStreamOut() function replaces SkPDFStream classes.
Page resources are all serialized early.
Several Document-level objects are serialzied early.
SkUUID introduced as top-level object.
Many {insert|append}ObjRef() converted to memory efficient
{insert|append}Ref().
Bug: skia:8630
Change-Id: Ic336917d0c8b9ac1c2423b43bfe9b49a3533fbff
Reviewed-on: https://skia-review.googlesource.com/c/176588
Auto-Submit: Hal Canary <halcanary@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/src/pdf/SkPDFDocumentPriv.h b/src/pdf/SkPDFDocumentPriv.h
index c23e026..27810dd 100644
--- a/src/pdf/SkPDFDocumentPriv.h
+++ b/src/pdf/SkPDFDocumentPriv.h
@@ -8,13 +8,17 @@
#define SkPDFDocumentPriv_DEFINED
#include "SkCanvas.h"
-#include "SkPDFDocument.h"
#include "SkPDFCanon.h"
+#include "SkPDFDocument.h"
#include "SkPDFFont.h"
#include "SkPDFMetadata.h"
+#include "SkUUID.h"
+
+#include <atomic>
class SkPDFDevice;
class SkPDFTag;
+class SkExecutor;
const char* SkPDFGetNodeIdKey();
@@ -31,23 +35,26 @@
// Logically part of SkPDFDocument (like SkPDFCanon), but separate to
// keep similar functionality together.
struct SkPDFObjectSerializer {
- int fNextObjectNumber = 1;
+ std::atomic<int> fNextObjectNumber = {1};
+ SkPDFIndirectReference reserve() { return SkPDFIndirectReference{fNextObjectNumber++}; }
SkPDFOffsetMap fOffsets;
- sk_sp<SkPDFObject> fInfoDict;
size_t fBaseOffset = SIZE_MAX;
SkPDFObjectSerializer();
~SkPDFObjectSerializer();
- SkPDFObjectSerializer(SkPDFObjectSerializer&&);
- SkPDFObjectSerializer& operator=(SkPDFObjectSerializer&&);
+ SkPDFObjectSerializer(SkPDFObjectSerializer&&) = delete;
+ SkPDFObjectSerializer& operator=(SkPDFObjectSerializer&&) = delete;
SkPDFObjectSerializer(const SkPDFObjectSerializer&) = delete;
SkPDFObjectSerializer& operator=(const SkPDFObjectSerializer&) = delete;
SkWStream* beginObject(SkPDFIndirectReference, SkWStream*);
void endObject(SkWStream*);
- void serializeHeader(SkWStream*, const SkPDF::Metadata&);
+ void serializeHeader(SkWStream*);
void serializeObject(const sk_sp<SkPDFObject>&, SkWStream*);
- void serializeFooter(SkWStream*, const sk_sp<SkPDFObject>, sk_sp<SkPDFObject>);
+ void serializeFooter(SkWStream*,
+ SkPDFIndirectReference infoDict,
+ SkPDFIndirectReference docCatalog,
+ SkUUID uuid);
SkPDFFileOffset offset(SkWStream*);
};
@@ -73,7 +80,8 @@
after calling serialize, since those changes will be too late.
*/
SkPDFIndirectReference serialize(const sk_sp<SkPDFObject>&);
- SkPDFIndirectReference emit(const SkPDFObject&);
+ SkPDFIndirectReference emit(const SkPDFObject&, SkPDFIndirectReference);
+ SkPDFIndirectReference emit(const SkPDFObject& o) { return this->emit(o, this->reserveRef()); }
SkPDFCanon* canon() { return &fCanon; }
const SkPDF::Metadata& metadata() const { return fMetadata; }
@@ -81,10 +89,12 @@
// Returns -1 if no mark ID.
int getMarkIdForNodeId(int nodeId);
- SkPDFIndirectReference reserve();
+ SkPDFIndirectReference reserveRef();
SkWStream* beginObject(SkPDFIndirectReference);
void endObject();
+ SkExecutor* executor() const { return fExecutor; }
+
private:
sk_sp<SkPDFTag> recursiveBuildTagTree(const SkPDF::StructureElementNode& node,
sk_sp<SkPDFTag> parent);
@@ -95,11 +105,13 @@
std::vector<sk_sp<SkPDFDict>> fPages;
sk_sp<SkPDFDict> fDests;
sk_sp<SkPDFDevice> fPageDevice;
- sk_sp<SkPDFObject> fID;
- sk_sp<SkPDFObject> fXMP;
+ SkUUID fUUID;
+ SkPDFIndirectReference fInfoDict;
+ SkPDFIndirectReference fXMP;
SkPDF::Metadata fMetadata;
SkScalar fRasterScale = 1;
SkScalar fInverseRasterScale = 1;
+ SkExecutor* fExecutor = nullptr;
// For tagged PDFs.
@@ -110,7 +122,9 @@
// A mapping from node ID to tag for fast lookup.
SkTHashMap<int, sk_sp<SkPDFTag>> fNodeIdToTag;
- int fOutstandingRefs = 0;
+ std::atomic<int> fOutstandingRefs = {0};
+ SkMutex fMutex;
+ SkSemaphore fSemaphore;
void reset();
};