fonts: Reland push font remoting.
This relands the following changes: 1) https://skia-review.googlesource.com/c/skia/+/120283 2) https://skia-review.googlesource.com/c/skia/+/125029 3) https://skia-review.googlesource.com/c/skia/+/125140 The original changes had to be reverted due to a memory leak in SkBaseDevice from SkTextBlobCacheDiffCanvas. This has been addressed by https://skia-review.googlesource.com/c/skia/+/125160 TBR=herb@google.com Bug: skia:7515, 831354 Change-Id: I73f4fcb1c397f31bf01553ff48c71ed2d6dd0770 Reviewed-on: https://skia-review.googlesource.com/125326 Commit-Queue: Khusal Sagar <khushalsagar@chromium.org> Reviewed-by: Khusal Sagar <khushalsagar@chromium.org>
This commit is contained in:
parent
81afc04b53
commit
38a0843688
@ -226,6 +226,7 @@ tests_sources = [
|
|||||||
"$_tests/SkNxTest.cpp",
|
"$_tests/SkNxTest.cpp",
|
||||||
"$_tests/SkPEGTest.cpp",
|
"$_tests/SkPEGTest.cpp",
|
||||||
"$_tests/SkRasterPipelineTest.cpp",
|
"$_tests/SkRasterPipelineTest.cpp",
|
||||||
|
"$_tests/SkRemoteGlyphCacheTest.cpp",
|
||||||
"$_tests/SkResourceCacheTest.cpp",
|
"$_tests/SkResourceCacheTest.cpp",
|
||||||
"$_tests/SkSharedMutexTest.cpp",
|
"$_tests/SkSharedMutexTest.cpp",
|
||||||
"$_tests/SkSLErrorTest.cpp",
|
"$_tests/SkSLErrorTest.cpp",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,192 +5,196 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SkRemoteGlyphCache_DEFINED
|
#ifndef SkRemoteGlyphCachePriv_DEFINED
|
||||||
#define SkRemoteGlyphCache_DEFINED
|
#define SkRemoteGlyphCachePriv_DEFINED
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../private/SkTHash.h"
|
||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkDescriptor.h"
|
|
||||||
#include "SkDrawLooper.h"
|
#include "SkDrawLooper.h"
|
||||||
#include "SkGlyphCache.h"
|
|
||||||
#include "SkMakeUnique.h"
|
#include "SkMakeUnique.h"
|
||||||
#include "SkNoDrawCanvas.h"
|
#include "SkNoDrawCanvas.h"
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
|
#include "SkRemoteGlyphCache.h"
|
||||||
#include "SkSerialProcs.h"
|
#include "SkSerialProcs.h"
|
||||||
#include "SkStrikeCache.h"
|
|
||||||
#include "SkTextBlobRunIterator.h"
|
|
||||||
#include "SkTHash.h"
|
|
||||||
#include "SkTypeface.h"
|
#include "SkTypeface.h"
|
||||||
#include "SkTypeface_remote.h"
|
|
||||||
|
|
||||||
// The client uses a SkStrikeCacheClientRPC to send and receive data.
|
class Serializer;
|
||||||
using SkStrikeCacheClientRPC = std::function<sk_sp<SkData>(const SkData&)>;
|
class SkDescriptor;
|
||||||
|
class SkGlyphCache;
|
||||||
|
struct SkPackedGlyphID;
|
||||||
|
class SkScalerContextRecDescriptor;
|
||||||
|
class SkTextBlobRunIterator;
|
||||||
|
class SkTypefaceProxy;
|
||||||
|
struct WireTypeface;
|
||||||
|
|
||||||
class SkScalerContextRecDescriptor {
|
class SkStrikeServer;
|
||||||
public:
|
|
||||||
SkScalerContextRecDescriptor() {}
|
|
||||||
explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) {
|
|
||||||
auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor);
|
|
||||||
desc->init();
|
|
||||||
desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
|
|
||||||
desc->computeChecksum();
|
|
||||||
SkASSERT(sizeof(fDescriptor) == desc->getLength());
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit SkScalerContextRecDescriptor(const SkDescriptor& desc)
|
struct SkDescriptorMapOperators {
|
||||||
: SkScalerContextRecDescriptor(ExtractRec(desc)) { }
|
size_t operator()(const SkDescriptor* key) const;
|
||||||
|
bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const;
|
||||||
SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) {
|
|
||||||
std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkDescriptor& desc() const {
|
|
||||||
return *reinterpret_cast<const SkDescriptor*>(&fDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Hash {
|
|
||||||
uint32_t operator()(SkScalerContextRecDescriptor const& s) const {
|
|
||||||
return s.desc().getChecksum();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
friend bool operator==(const SkScalerContextRecDescriptor& lhs,
|
|
||||||
const SkScalerContextRecDescriptor& rhs ) {
|
|
||||||
return lhs.desc() == rhs.desc();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static SkScalerContextRec ExtractRec(const SkDescriptor& desc) {
|
|
||||||
uint32_t size;
|
|
||||||
auto recPtr = desc.findEntry(kRec_SkDescriptorTag, &size);
|
|
||||||
|
|
||||||
SkScalerContextRec result;
|
|
||||||
std::memcpy(&result, recPtr, size);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// The system only passes descriptors without effects. That is why it uses a fixed size
|
|
||||||
// descriptor. storageFor is needed because some of the constructors below are private.
|
|
||||||
template <typename T>
|
|
||||||
using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
|
|
||||||
struct {
|
|
||||||
storageFor<SkDescriptor> dummy1;
|
|
||||||
storageFor<SkDescriptor::Entry> dummy2;
|
|
||||||
storageFor<SkScalerContextRec> dummy3;
|
|
||||||
} fDescriptor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkStrikeDifferences {
|
template <typename T>
|
||||||
public:
|
using SkDescriptorMap = std::unordered_map<const SkDescriptor*, T, SkDescriptorMapOperators,
|
||||||
SkStrikeDifferences(SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc);
|
SkDescriptorMapOperators>;
|
||||||
void add(uint16_t glyphID, SkIPoint pos);
|
|
||||||
SkFontID fTypefaceID;
|
|
||||||
std::unique_ptr<SkDescriptor> fDesc;
|
|
||||||
std::unique_ptr<SkTHashSet<SkPackedGlyphID>> fGlyphIDs =
|
|
||||||
skstd::make_unique<SkTHashSet<SkPackedGlyphID>>();
|
|
||||||
};
|
|
||||||
|
|
||||||
class SkStrikeCacheDifferenceSpec {
|
using SkDescriptorSet =
|
||||||
public:
|
std::unordered_set<const SkDescriptor*, SkDescriptorMapOperators, SkDescriptorMapOperators>;
|
||||||
SkStrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID);
|
|
||||||
int strikeCount() const { return fDescriptorToDifferencesMap.size(); }
|
|
||||||
size_t sizeBytes() const;
|
|
||||||
template <typename PerStrike, typename PerGlyph>
|
|
||||||
void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const;
|
|
||||||
|
|
||||||
private:
|
// A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops
|
||||||
SkDescriptorMap<SkStrikeDifferences> fDescriptorToDifferencesMap{16};
|
// which will be serialized and renderered using the SkStrikeClient.
|
||||||
};
|
class SK_API SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas {
|
||||||
|
|
||||||
class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas {
|
|
||||||
public:
|
public:
|
||||||
SkTextBlobCacheDiffCanvas(int width, int height,
|
SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix,
|
||||||
const SkMatrix& deviceMatrix,
|
const SkSurfaceProps& props, SkStrikeServer* strikeserver);
|
||||||
const SkSurfaceProps& props,
|
~SkTextBlobCacheDiffCanvas() override;
|
||||||
SkScalerContextFlags flags,
|
|
||||||
SkStrikeCacheDifferenceSpec* strikeDiffs);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
|
SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
|
||||||
|
|
||||||
void onDrawTextBlob(
|
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
|
||||||
const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override;
|
const SkPaint& paint) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processLooper(
|
void processLooper(const SkPoint& position,
|
||||||
const SkPoint& position,
|
const SkTextBlobRunIterator& it,
|
||||||
const SkTextBlobRunIterator& it,
|
const SkPaint& origPaint,
|
||||||
const SkPaint& origPaint,
|
SkDrawLooper* looper);
|
||||||
SkDrawLooper* looper);
|
void processGlyphRun(const SkPoint& position,
|
||||||
|
const SkTextBlobRunIterator& it,
|
||||||
void processGlyphRun(
|
const SkPaint& runPaint);
|
||||||
const SkPoint& position,
|
|
||||||
const SkTextBlobRunIterator& it,
|
|
||||||
const SkPaint& runPaint);
|
|
||||||
|
|
||||||
const SkMatrix fDeviceMatrix;
|
const SkMatrix fDeviceMatrix;
|
||||||
const SkSurfaceProps fSurfaceProps;
|
const SkSurfaceProps fSurfaceProps;
|
||||||
const SkScalerContextFlags fScalerContextFlags;
|
SkStrikeServer* const fStrikeServer;
|
||||||
|
|
||||||
SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkStrikeServer {
|
using SkDiscardableHandleId = uint32_t;
|
||||||
|
|
||||||
|
// This class is not thread-safe.
|
||||||
|
class SK_API SkStrikeServer {
|
||||||
public:
|
public:
|
||||||
SkStrikeServer();
|
// An interface used by the server to create handles for pinning SkGlyphCache
|
||||||
|
// entries on the remote client.
|
||||||
|
class SK_API DiscardableHandleManager {
|
||||||
|
public:
|
||||||
|
virtual ~DiscardableHandleManager() {}
|
||||||
|
|
||||||
|
// Creates a new *locked* handle and returns a unique ID that can be used to identify
|
||||||
|
// it on the remote client.
|
||||||
|
virtual SkDiscardableHandleId createHandle() = 0;
|
||||||
|
|
||||||
|
// Returns true if the handle could be successfully locked. The server can
|
||||||
|
// assume it will remain locked until the next set of serialized entries is
|
||||||
|
// pulled from the SkStrikeServer.
|
||||||
|
// If returns false, the cache entry mapped to the handle has been deleted
|
||||||
|
// on the client. Any subsequent attempts to lock the same handle are not
|
||||||
|
// allowed.
|
||||||
|
virtual bool lockHandle(SkDiscardableHandleId) = 0;
|
||||||
|
|
||||||
|
// TODO(khushalsagar): Add an API which checks whether a handle is still
|
||||||
|
// valid without locking, so we can avoid tracking stale handles once they
|
||||||
|
// have been purged on the remote side.
|
||||||
|
};
|
||||||
|
|
||||||
|
SkStrikeServer(DiscardableHandleManager* discardableHandleManager);
|
||||||
~SkStrikeServer();
|
~SkStrikeServer();
|
||||||
|
|
||||||
// embedding clients call these methods
|
// Serializes the typeface to be remoted using this server.
|
||||||
void serve(const SkData&, std::vector<uint8_t>*);
|
sk_sp<SkData> serializeTypeface(SkTypeface*);
|
||||||
|
|
||||||
void prepareSerializeProcs(SkSerialProcs* procs);
|
// Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any
|
||||||
|
// handles locked using the DiscardableHandleManager will be assumed to be
|
||||||
|
// unlocked after this call.
|
||||||
|
void writeStrikeData(std::vector<uint8_t>* memory);
|
||||||
|
|
||||||
// mostly called internally by Skia
|
// Methods used internally in skia ------------------------------------------
|
||||||
SkScalerContext* generateScalerContext(
|
class SkGlyphCacheState {
|
||||||
const SkScalerContextRecDescriptor& desc, SkFontID typefaceId);
|
public:
|
||||||
|
SkGlyphCacheState(std::unique_ptr<SkDescriptor> desc,
|
||||||
|
SkDiscardableHandleId discardableHandleId);
|
||||||
|
~SkGlyphCacheState();
|
||||||
|
|
||||||
|
void addGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID);
|
||||||
|
void writePendingGlyphs(Serializer* serializer);
|
||||||
|
bool has_pending_glyphs() const { return !fPendingGlyphs.empty(); }
|
||||||
|
SkDiscardableHandleId discardable_handle_id() const { return fDiscardableHandleId; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The set of glyphs cached on the remote client.
|
||||||
|
SkTHashSet<SkPackedGlyphID> fCachedGlyphs;
|
||||||
|
|
||||||
|
// The set of glyphs which has not yet been serialized and sent to the
|
||||||
|
// remote client.
|
||||||
|
std::vector<SkPackedGlyphID> fPendingGlyphs;
|
||||||
|
|
||||||
|
std::unique_ptr<SkDescriptor> fDesc;
|
||||||
|
const SkDiscardableHandleId fDiscardableHandleId = -1;
|
||||||
|
std::unique_ptr<SkScalerContext> fContext;
|
||||||
|
};
|
||||||
|
SkGlyphCacheState* getOrCreateCache(SkTypeface*, std::unique_ptr<SkDescriptor>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using DescriptorToContextMap = SkTHashMap<SkScalerContextRecDescriptor,
|
SkDescriptorMap<std::unique_ptr<SkGlyphCacheState>> fRemoteGlyphStateMap;
|
||||||
std::unique_ptr<SkScalerContext>,
|
DiscardableHandleManager* const fDiscardableHandleManager;
|
||||||
SkScalerContextRecDescriptor::Hash>;
|
SkTHashSet<SkFontID> fCachedTypefaces;
|
||||||
|
|
||||||
sk_sp<SkData> encodeTypeface(SkTypeface* tf);
|
// State cached until the next serialization.
|
||||||
|
SkDescriptorSet fLockedDescs;
|
||||||
int fOpCount = 0;
|
std::vector<WireTypeface> fTypefacesToSend;
|
||||||
SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap;
|
|
||||||
DescriptorToContextMap fScalerContextMap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkStrikeClient {
|
class SK_API SkStrikeClient {
|
||||||
public:
|
public:
|
||||||
SkStrikeClient(SkStrikeCacheClientRPC);
|
// An interface to delete handles that may be pinned by the remote server.
|
||||||
|
class DiscardableHandleManager : public SkRefCnt {
|
||||||
|
public:
|
||||||
|
virtual ~DiscardableHandleManager() {}
|
||||||
|
|
||||||
// embedding clients call these methods
|
// Returns true if the handle was unlocked and can be safely deleted. Once
|
||||||
void primeStrikeCache(const SkStrikeCacheDifferenceSpec&);
|
// successful, subsequent attempts to delete the same handle are invalid.
|
||||||
void prepareDeserializeProcs(SkDeserialProcs* procs);
|
virtual bool deleteHandle(SkDiscardableHandleId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// mostly called internally by Skia
|
SkStrikeClient(sk_sp<DiscardableHandleManager>);
|
||||||
void generateFontMetrics(
|
~SkStrikeClient();
|
||||||
const SkTypefaceProxy&, const SkScalerContextRec&, SkPaint::FontMetrics*);
|
|
||||||
void generateMetricsAndImage(
|
// Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the
|
||||||
const SkTypefaceProxy&, const SkScalerContextRec&, SkArenaAlloc*, SkGlyph*);
|
// data is invalid.
|
||||||
bool generatePath(
|
sk_sp<SkTypeface> deserializeTypeface(const void* data, size_t length);
|
||||||
const SkTypefaceProxy&, const SkScalerContextRec&, SkGlyphID glyph, SkPath* path);
|
|
||||||
SkTypeface* lookupTypeface(SkFontID id);
|
// Deserializes the strike data from a SkStrikeServer. All messages generated
|
||||||
|
// from a server when serializing the ops must be deserialized before the op
|
||||||
|
// is rasterized.
|
||||||
|
// Returns false if the data is invalid.
|
||||||
|
bool readStrikeData(const volatile void* memory, size_t memorySize);
|
||||||
|
|
||||||
|
// TODO: Remove these since we don't support pulling this data on-demand.
|
||||||
|
void generateFontMetrics(const SkTypefaceProxy& typefaceProxy,
|
||||||
|
const SkScalerContextRec& rec,
|
||||||
|
SkPaint::FontMetrics* metrics);
|
||||||
|
void generateMetricsAndImage(const SkTypefaceProxy& typefaceProxy,
|
||||||
|
const SkScalerContextRec& rec,
|
||||||
|
SkArenaAlloc* alloc,
|
||||||
|
SkGlyph* glyph);
|
||||||
|
void generatePath(const SkTypefaceProxy& typefaceProxy,
|
||||||
|
const SkScalerContextRec& rec,
|
||||||
|
SkGlyphID glyphID,
|
||||||
|
SkPath* path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sk_sp<SkTypeface> decodeTypeface(const void* buf, size_t len);
|
class DiscardableStrikePinner;
|
||||||
|
|
||||||
// TODO: Figure out how to manage the entries for the following maps.
|
sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
|
||||||
SkTHashMap<SkFontID, sk_sp<SkTypefaceProxy>> fMapIdToTypeface;
|
|
||||||
|
|
||||||
SkStrikeCacheClientRPC fClientRPC;
|
SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface;
|
||||||
|
sk_sp<DiscardableHandleManager> fDiscardableHandleManager;
|
||||||
std::vector<uint8_t> fBuffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SkRemoteGlyphCache_DEFINED
|
#endif // SkRemoteGlyphCachePriv_DEFINED
|
||||||
|
@ -135,8 +135,8 @@ public:
|
|||||||
fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
|
fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
|
||||||
msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n",
|
msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n",
|
||||||
fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
|
fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
|
||||||
msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n",
|
msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", fLumBits,
|
||||||
fLumBits, fDeviceGamma, fPaintGamma, fContrast);
|
fDeviceGamma, fPaintGamma, fContrast);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define SkStrikeCache_DEFINED
|
#define SkStrikeCache_DEFINED
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "SkDescriptor.h"
|
#include "SkDescriptor.h"
|
||||||
#include "SkSpinlock.h"
|
#include "SkSpinlock.h"
|
||||||
@ -31,24 +32,6 @@ class SkTraceMemoryDump;
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct SkDescriptorMapOperators {
|
|
||||||
size_t operator()(const SkDescriptor* key) const {
|
|
||||||
return key->getChecksum();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
|
|
||||||
return *lhs == *rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using SkDescriptorMap =
|
|
||||||
std::unordered_map<
|
|
||||||
const SkDescriptor*,
|
|
||||||
T,
|
|
||||||
SkDescriptorMapOperators,
|
|
||||||
SkDescriptorMapOperators>;
|
|
||||||
|
|
||||||
class SkStrikePinner {
|
class SkStrikePinner {
|
||||||
public:
|
public:
|
||||||
virtual ~SkStrikePinner() = default;
|
virtual ~SkStrikePinner() = default;
|
||||||
|
@ -6,17 +6,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SkTypeface_remote.h"
|
#include "SkTypeface_remote.h"
|
||||||
|
|
||||||
#include "SkPaint.h"
|
|
||||||
#include "SkRemoteGlyphCache.h"
|
#include "SkRemoteGlyphCache.h"
|
||||||
|
|
||||||
SkScalerContextProxy::SkScalerContextProxy(
|
#include "SkPaint.h"
|
||||||
sk_sp<SkTypeface> tf,
|
|
||||||
const SkScalerContextEffects& effects,
|
SkScalerContextProxy::SkScalerContextProxy(sk_sp<SkTypeface> tf,
|
||||||
const SkDescriptor* desc,
|
const SkScalerContextEffects& effects,
|
||||||
SkStrikeClient* rsc)
|
const SkDescriptor* desc,
|
||||||
: SkScalerContext{std::move(tf), effects, desc}
|
SkStrikeClient* rsc)
|
||||||
, fClient{rsc} {}
|
: SkScalerContext{std::move(tf), effects, desc}, fClient{rsc} {}
|
||||||
|
|
||||||
unsigned SkScalerContextProxy::generateGlyphCount() {
|
unsigned SkScalerContextProxy::generateGlyphCount() {
|
||||||
SK_ABORT("Should never be called.");
|
SK_ABORT("Should never be called.");
|
||||||
@ -40,7 +38,8 @@ void SkScalerContextProxy::generateImage(const SkGlyph& glyph) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
|
bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
|
||||||
return fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path);
|
fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) {
|
void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) {
|
||||||
|
@ -21,11 +21,10 @@ class SkTypefaceProxy;
|
|||||||
|
|
||||||
class SkScalerContextProxy : public SkScalerContext {
|
class SkScalerContextProxy : public SkScalerContext {
|
||||||
public:
|
public:
|
||||||
SkScalerContextProxy(
|
SkScalerContextProxy(sk_sp<SkTypeface> tf,
|
||||||
sk_sp<SkTypeface> tf,
|
const SkScalerContextEffects& effects,
|
||||||
const SkScalerContextEffects& effects,
|
const SkDescriptor* desc,
|
||||||
const SkDescriptor* desc,
|
SkStrikeClient* rsc);
|
||||||
SkStrikeClient* rsc);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned generateGlyphCount() override;
|
unsigned generateGlyphCount() override;
|
||||||
@ -52,16 +51,12 @@ private:
|
|||||||
|
|
||||||
class SkTypefaceProxy : public SkTypeface {
|
class SkTypefaceProxy : public SkTypeface {
|
||||||
public:
|
public:
|
||||||
SkTypefaceProxy(
|
SkTypefaceProxy(SkFontID fontId,
|
||||||
SkFontID fontId,
|
int glyphCount,
|
||||||
int glyphCount,
|
const SkFontStyle& style,
|
||||||
const SkFontStyle& style,
|
bool isFixed,
|
||||||
bool isFixed,
|
SkStrikeClient* rsc)
|
||||||
SkStrikeClient* rsc)
|
: INHERITED{style, false}, fFontId{fontId}, fGlyphCount{glyphCount}, fRsc{rsc} {}
|
||||||
: INHERITED{style, false}
|
|
||||||
, fFontId{fontId}
|
|
||||||
, fGlyphCount{glyphCount}
|
|
||||||
, fRsc{rsc} { }
|
|
||||||
SkFontID remoteTypefaceID() const {return fFontId;}
|
SkFontID remoteTypefaceID() const {return fFontId;}
|
||||||
int glyphCount() const {return fGlyphCount;}
|
int glyphCount() const {return fGlyphCount;}
|
||||||
static SkTypefaceProxy* DownCast(SkTypeface* typeface) {
|
static SkTypefaceProxy* DownCast(SkTypeface* typeface) {
|
||||||
@ -138,6 +133,8 @@ protected:
|
|||||||
private:
|
private:
|
||||||
const SkFontID fFontId;
|
const SkFontID fFontId;
|
||||||
const int fGlyphCount;
|
const int fGlyphCount;
|
||||||
|
|
||||||
|
// TODO: Does this need a ref to the strike client? If yes, make it a weak ref.
|
||||||
SkStrikeClient* const fRsc;
|
SkStrikeClient* const fRsc;
|
||||||
|
|
||||||
typedef SkTypeface INHERITED;
|
typedef SkTypeface INHERITED;
|
||||||
|
223
tests/SkRemoteGlyphCacheTest.cpp
Normal file
223
tests/SkRemoteGlyphCacheTest.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkGraphics.h"
|
||||||
|
#include "SkMutex.h"
|
||||||
|
#include "SkRemoteGlyphCache.h"
|
||||||
|
#include "SkStrikeCache.h"
|
||||||
|
#include "SkSurface.h"
|
||||||
|
#include "SkTextBlob.h"
|
||||||
|
#include "SkTypeface_remote.h"
|
||||||
|
#include "Test.h"
|
||||||
|
|
||||||
|
class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
|
||||||
|
public SkStrikeClient::DiscardableHandleManager {
|
||||||
|
public:
|
||||||
|
DiscardableManager() = default;
|
||||||
|
~DiscardableManager() override = default;
|
||||||
|
|
||||||
|
// Server implementation.
|
||||||
|
SkDiscardableHandleId createHandle() override {
|
||||||
|
// Handles starts as locked.
|
||||||
|
fLockedHandles.add(++fNextHandleId);
|
||||||
|
return fNextHandleId;
|
||||||
|
}
|
||||||
|
bool lockHandle(SkDiscardableHandleId id) override {
|
||||||
|
if (id <= fLastDeletedHandleId) return false;
|
||||||
|
fLockedHandles.add(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client implementation.
|
||||||
|
bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
|
||||||
|
|
||||||
|
void unlockAll() { fLockedHandles.reset(); }
|
||||||
|
void unlockAndDeleteAll() {
|
||||||
|
unlockAll();
|
||||||
|
fLastDeletedHandleId = fNextHandleId;
|
||||||
|
}
|
||||||
|
const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
|
||||||
|
SkDiscardableHandleId handleCount() { return fNextHandleId; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkDiscardableHandleId fNextHandleId = 0u;
|
||||||
|
SkDiscardableHandleId fLastDeletedHandleId = 0u;
|
||||||
|
SkTHashSet<SkDiscardableHandleId> fLockedHandles;
|
||||||
|
};
|
||||||
|
|
||||||
|
sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
|
||||||
|
SkPaint font;
|
||||||
|
font.setTypeface(tf);
|
||||||
|
font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||||
|
font.setTextAlign(SkPaint::kLeft_Align);
|
||||||
|
font.setStyle(SkPaint::kFill_Style);
|
||||||
|
font.setHinting(SkPaint::kNormal_Hinting);
|
||||||
|
font.setTextSize(1u);
|
||||||
|
|
||||||
|
SkTextBlobBuilder builder;
|
||||||
|
SkRect bounds = SkRect::MakeWH(10, 10);
|
||||||
|
const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
|
||||||
|
SkASSERT(runBuffer.utf8text == nullptr);
|
||||||
|
SkASSERT(runBuffer.clusters == nullptr);
|
||||||
|
|
||||||
|
for (int i = 0; i < glyphCount; i++) {
|
||||||
|
runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
|
||||||
|
runBuffer.pos[i] = SkIntToScalar(i);
|
||||||
|
}
|
||||||
|
return builder.make();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height) {
|
||||||
|
auto surface = SkSurface::MakeRasterN32Premul(width, height);
|
||||||
|
SkPaint paint;
|
||||||
|
surface->getCanvas()->drawTextBlob(blob.get(), 0u, 0u, paint);
|
||||||
|
SkBitmap bitmap;
|
||||||
|
bitmap.allocN32Pixels(width, height);
|
||||||
|
surface->readPixels(bitmap, 0, 0);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
|
||||||
|
sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
|
||||||
|
SkStrikeServer server(discardableManager.get());
|
||||||
|
SkStrikeClient client(discardableManager);
|
||||||
|
|
||||||
|
auto server_tf = SkTypeface::MakeDefault();
|
||||||
|
auto tf_data = server.serializeTypeface(server_tf.get());
|
||||||
|
|
||||||
|
auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
|
||||||
|
REPORTER_ASSERT(reporter, client_tf);
|
||||||
|
REPORTER_ASSERT(reporter, SkTypefaceProxy::DownCast(client_tf.get())->remoteTypefaceID() ==
|
||||||
|
server_tf->uniqueID());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkRemoteGlyphCache_StrikeSerialization, reporter) {
|
||||||
|
sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
|
||||||
|
SkStrikeServer server(discardableManager.get());
|
||||||
|
SkStrikeClient client(discardableManager);
|
||||||
|
|
||||||
|
// Server.
|
||||||
|
auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
|
||||||
|
auto serverTfData = server.serializeTypeface(serverTf.get());
|
||||||
|
|
||||||
|
int glyphCount = 10;
|
||||||
|
auto serverBlob = buildTextBlob(serverTf, glyphCount);
|
||||||
|
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||||
|
SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
|
||||||
|
SkPaint paint;
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
|
||||||
|
std::vector<uint8_t> serverStrikeData;
|
||||||
|
server.writeStrikeData(&serverStrikeData);
|
||||||
|
|
||||||
|
// Client.
|
||||||
|
auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
|
||||||
|
REPORTER_ASSERT(reporter,
|
||||||
|
client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
|
||||||
|
auto clientBlob = buildTextBlob(clientTf, glyphCount);
|
||||||
|
|
||||||
|
SkBitmap expected = RasterBlob(serverBlob, 10, 10);
|
||||||
|
SkBitmap actual = RasterBlob(clientBlob, 10, 10);
|
||||||
|
for (int i = 0; i < expected.width(); ++i) {
|
||||||
|
for (int j = 0; j < expected.height(); ++j) {
|
||||||
|
REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
|
||||||
|
sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
|
||||||
|
SkStrikeServer server(discardableManager.get());
|
||||||
|
SkStrikeClient client(discardableManager);
|
||||||
|
|
||||||
|
auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
|
||||||
|
server.serializeTypeface(serverTf.get());
|
||||||
|
int glyphCount = 10;
|
||||||
|
auto serverBlob = buildTextBlob(serverTf, glyphCount);
|
||||||
|
|
||||||
|
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||||
|
SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
|
||||||
|
SkPaint paint;
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
|
||||||
|
// The strike from the blob should be locked after it has been drawn on the canvas.
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
|
||||||
|
|
||||||
|
// Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
|
||||||
|
// again.
|
||||||
|
std::vector<uint8_t> fontData;
|
||||||
|
server.writeStrikeData(&fontData);
|
||||||
|
discardableManager->unlockAll();
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
|
||||||
|
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
|
||||||
|
sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
|
||||||
|
SkStrikeServer server(discardableManager.get());
|
||||||
|
SkStrikeClient client(discardableManager);
|
||||||
|
|
||||||
|
auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
|
||||||
|
server.serializeTypeface(serverTf.get());
|
||||||
|
int glyphCount = 10;
|
||||||
|
auto serverBlob = buildTextBlob(serverTf, glyphCount);
|
||||||
|
|
||||||
|
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||||
|
SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
|
||||||
|
SkPaint paint;
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
|
||||||
|
|
||||||
|
// Write the strike data and delete all the handles. Re-analyzing the blob should create new
|
||||||
|
// handles.
|
||||||
|
std::vector<uint8_t> fontData;
|
||||||
|
server.writeStrikeData(&fontData);
|
||||||
|
discardableManager->unlockAndDeleteAll();
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
printf("HandleCount: %d\n ", discardableManager->handleCount());
|
||||||
|
REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
|
||||||
|
sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
|
||||||
|
SkStrikeServer server(discardableManager.get());
|
||||||
|
SkStrikeClient client(discardableManager);
|
||||||
|
|
||||||
|
// Server.
|
||||||
|
auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
|
||||||
|
auto serverTfData = server.serializeTypeface(serverTf.get());
|
||||||
|
|
||||||
|
int glyphCount = 10;
|
||||||
|
auto serverBlob = buildTextBlob(serverTf, glyphCount);
|
||||||
|
|
||||||
|
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||||
|
SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
|
||||||
|
SkPaint paint;
|
||||||
|
cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
|
||||||
|
|
||||||
|
std::vector<uint8_t> serverStrikeData;
|
||||||
|
server.writeStrikeData(&serverStrikeData);
|
||||||
|
|
||||||
|
// Client.
|
||||||
|
REPORTER_ASSERT(reporter,
|
||||||
|
client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
|
||||||
|
auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
|
||||||
|
|
||||||
|
// The cache remains alive until it is pinned in the discardable manager.
|
||||||
|
SkGraphics::PurgeFontCache();
|
||||||
|
REPORTER_ASSERT(reporter, !clientTf->unique());
|
||||||
|
|
||||||
|
// Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
|
||||||
|
// clientTf.
|
||||||
|
discardableManager->unlockAndDeleteAll();
|
||||||
|
SkGraphics::PurgeFontCache();
|
||||||
|
REPORTER_ASSERT(reporter, clientTf->unique());
|
||||||
|
}
|
@ -16,8 +16,9 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "SkRemoteGlyphCache.h"
|
|
||||||
#include "SkGraphics.h"
|
#include "SkGraphics.h"
|
||||||
|
#include "SkRemoteGlyphCache.h"
|
||||||
|
#include "SkScalerContext.h"
|
||||||
#include "SkSurface.h"
|
#include "SkSurface.h"
|
||||||
|
|
||||||
static std::string gSkpName;
|
static std::string gSkpName;
|
||||||
@ -25,6 +26,46 @@ static bool gUseGpu = true;
|
|||||||
static bool gPurgeFontCaches = true;
|
static bool gPurgeFontCaches = true;
|
||||||
static bool gUseProcess = true;
|
static bool gUseProcess = true;
|
||||||
|
|
||||||
|
class ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager {
|
||||||
|
public:
|
||||||
|
ServerDiscardableManager() = default;
|
||||||
|
~ServerDiscardableManager() override = default;
|
||||||
|
|
||||||
|
SkDiscardableHandleId createHandle() override { return ++nextHandleId; }
|
||||||
|
bool lockHandle(SkDiscardableHandleId handleId) override {
|
||||||
|
return handleId > lastPurgedHandleId;
|
||||||
|
}
|
||||||
|
void purgeAll() { lastPurgedHandleId = nextHandleId; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkDiscardableHandleId nextHandleId = 0u;
|
||||||
|
SkDiscardableHandleId lastPurgedHandleId = 0u;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager {
|
||||||
|
public:
|
||||||
|
class ScopedPurgeCache {
|
||||||
|
public:
|
||||||
|
ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) {
|
||||||
|
if (fManager) fManager->allowPurging = true;
|
||||||
|
}
|
||||||
|
~ScopedPurgeCache() {
|
||||||
|
if (fManager) fManager->allowPurging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClientDiscardableManager* fManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientDiscardableManager() = default;
|
||||||
|
~ClientDiscardableManager() override = default;
|
||||||
|
|
||||||
|
bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool allowPurging = false;
|
||||||
|
};
|
||||||
|
|
||||||
static bool write_SkData(int fd, const SkData& data) {
|
static bool write_SkData(int fd, const SkData& data) {
|
||||||
size_t size = data.size();
|
size_t size = data.size();
|
||||||
ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
|
ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
|
||||||
@ -43,7 +84,6 @@ static bool write_SkData(int fd, const SkData& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static sk_sp<SkData> read_SkData(int fd) {
|
static sk_sp<SkData> read_SkData(int fd) {
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
ssize_t readSize = ::read(fd, &size, sizeof(size));
|
ssize_t readSize = ::read(fd, &size, sizeof(size));
|
||||||
if (readSize <= 0) {
|
if (readSize <= 0) {
|
||||||
@ -92,44 +132,56 @@ private:
|
|||||||
std::chrono::duration<double> fElapsedSeconds{0.0};
|
std::chrono::duration<double> fElapsedSeconds{0.0};
|
||||||
};
|
};
|
||||||
|
|
||||||
static void build_prime_cache_spec(const SkIRect &bounds,
|
static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer, int writeFd) {
|
||||||
const SkSurfaceProps &props,
|
|
||||||
const SkPicture &pic,
|
|
||||||
SkStrikeCacheDifferenceSpec *strikeDifference) {
|
|
||||||
SkMatrix deviceMatrix = SkMatrix::I();
|
SkMatrix deviceMatrix = SkMatrix::I();
|
||||||
|
const SkIRect bounds = pic.cullRect().round();
|
||||||
SkTextBlobCacheDiffCanvas filter(
|
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
|
||||||
bounds.width(), bounds.height(), deviceMatrix, props,
|
SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), deviceMatrix, props,
|
||||||
SkScalerContextFlags::kFakeGammaAndBoostContrast,
|
strikeServer);
|
||||||
strikeDifference);
|
|
||||||
|
|
||||||
pic.playback(&filter);
|
pic.playback(&filter);
|
||||||
|
|
||||||
|
std::vector<uint8_t> fontData;
|
||||||
|
strikeServer->writeStrikeData(&fontData);
|
||||||
|
auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size());
|
||||||
|
return write_SkData(writeFd, *data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void final_draw(std::string outFilename,
|
static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client,
|
||||||
SkDeserialProcs* procs,
|
ClientDiscardableManager* discardableManager, int readFd, int writeFd) {
|
||||||
SkData* picData,
|
SkDeserialProcs procs;
|
||||||
SkStrikeClient* client) {
|
auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
|
||||||
|
return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length);
|
||||||
|
};
|
||||||
|
procs.fTypefaceProc = decode;
|
||||||
|
procs.fTypefaceCtx = client;
|
||||||
|
|
||||||
auto pic = SkPicture::MakeFromData(picData, procs);
|
auto pic = SkPicture::MakeFromData(picData, &procs);
|
||||||
|
|
||||||
auto cullRect = pic->cullRect();
|
auto cullRect = pic->cullRect();
|
||||||
auto r = cullRect.round();
|
auto r = cullRect.round();
|
||||||
|
|
||||||
auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
|
auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
|
||||||
auto c = s->getCanvas();
|
auto c = s->getCanvas();
|
||||||
auto picUnderTest = SkPicture::MakeFromData(picData, procs);
|
auto picUnderTest = SkPicture::MakeFromData(picData, &procs);
|
||||||
|
|
||||||
Timer drawTime;
|
Timer drawTime;
|
||||||
|
auto randomData = SkData::MakeUninitialized(1u);
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
if (gPurgeFontCaches) {
|
if (gPurgeFontCaches) {
|
||||||
|
ClientDiscardableManager::ScopedPurgeCache purge(discardableManager);
|
||||||
SkGraphics::PurgeFontCache();
|
SkGraphics::PurgeFontCache();
|
||||||
|
SkASSERT(SkGraphics::GetFontCacheUsed() == 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTime.start();
|
drawTime.start();
|
||||||
if (client != nullptr) {
|
if (client != nullptr) {
|
||||||
SkStrikeCacheDifferenceSpec strikeDifference;
|
// Kick the renderer to send us the fonts.
|
||||||
build_prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference);
|
write_SkData(writeFd, *randomData);
|
||||||
client->primeStrikeCache(strikeDifference);
|
auto fontData = read_SkData(readFd);
|
||||||
|
if (fontData && !fontData->isEmpty()) {
|
||||||
|
if (!client->readStrikeData(fontData->data(), fontData->size()))
|
||||||
|
SK_ABORT("Bad serialization");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c->drawPicture(picUnderTest);
|
c->drawPicture(picUnderTest);
|
||||||
drawTime.stop();
|
drawTime.stop();
|
||||||
@ -150,22 +202,16 @@ static void final_draw(std::string outFilename,
|
|||||||
static void gpu(int readFd, int writeFd) {
|
static void gpu(int readFd, int writeFd) {
|
||||||
|
|
||||||
if (gUseGpu) {
|
if (gUseGpu) {
|
||||||
auto clientRPC = [readFd, writeFd](const SkData& inBuffer) {
|
|
||||||
write_SkData(writeFd, inBuffer);
|
|
||||||
return read_SkData(readFd);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto picData = read_SkData(readFd);
|
auto picData = read_SkData(readFd);
|
||||||
if (picData == nullptr) {
|
if (picData == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkStrikeClient client{clientRPC};
|
sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
|
||||||
|
SkStrikeClient strikeClient(discardableManager);
|
||||||
|
|
||||||
SkDeserialProcs procs;
|
final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
|
||||||
client.prepareDeserializeProcs(&procs);
|
writeFd);
|
||||||
|
|
||||||
final_draw("test.png", &procs, picData.get(), &client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::close(writeFd);
|
::close(writeFd);
|
||||||
@ -177,7 +223,8 @@ static void gpu(int readFd, int writeFd) {
|
|||||||
static int renderer(
|
static int renderer(
|
||||||
const std::string& skpName, int readFd, int writeFd)
|
const std::string& skpName, int readFd, int writeFd)
|
||||||
{
|
{
|
||||||
SkStrikeServer server{};
|
ServerDiscardableManager discardableManager;
|
||||||
|
SkStrikeServer server(&discardableManager);
|
||||||
auto closeAll = [readFd, writeFd]() {
|
auto closeAll = [readFd, writeFd]() {
|
||||||
::close(writeFd);
|
::close(writeFd);
|
||||||
::close(readFd);
|
::close(readFd);
|
||||||
@ -186,11 +233,16 @@ static int renderer(
|
|||||||
auto skpData = SkData::MakeFromFileName(skpName.c_str());
|
auto skpData = SkData::MakeFromFileName(skpName.c_str());
|
||||||
std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
|
std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
|
||||||
|
|
||||||
SkSerialProcs procs;
|
|
||||||
sk_sp<SkData> stream;
|
sk_sp<SkData> stream;
|
||||||
if (gUseGpu) {
|
if (gUseGpu) {
|
||||||
auto pic = SkPicture::MakeFromData(skpData.get());
|
auto pic = SkPicture::MakeFromData(skpData.get());
|
||||||
server.prepareSerializeProcs(&procs);
|
SkSerialProcs procs;
|
||||||
|
auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
|
||||||
|
return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
|
||||||
|
};
|
||||||
|
procs.fTypefaceProc = encode;
|
||||||
|
procs.fTypefaceCtx = &server;
|
||||||
|
|
||||||
stream = pic->serialize(&procs);
|
stream = pic->serialize(&procs);
|
||||||
|
|
||||||
if (!write_SkData(writeFd, *stream)) {
|
if (!write_SkData(writeFd, *stream)) {
|
||||||
@ -198,22 +250,18 @@ static int renderer(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> tmpBuffer;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto inBuffer = read_SkData(readFd);
|
auto inBuffer = read_SkData(readFd);
|
||||||
if (inBuffer == nullptr) {
|
if (inBuffer == nullptr) {
|
||||||
closeAll();
|
closeAll();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (gPurgeFontCaches) discardableManager.purgeAll();
|
||||||
tmpBuffer.clear();
|
push_font_data(*pic.get(), &server, writeFd);
|
||||||
server.serve(*inBuffer, &tmpBuffer);
|
|
||||||
auto outBuffer = SkData::MakeWithoutCopy(tmpBuffer.data(), tmpBuffer.size());
|
|
||||||
write_SkData(writeFd, *outBuffer);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stream = skpData;
|
stream = skpData;
|
||||||
final_draw("test-correct.png", nullptr, stream.get(), nullptr);
|
final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
|
||||||
closeAll();
|
closeAll();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user