add testing code for serialized Slugs
By setting the compile time flag:
SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE
will cause all SkTextBlobs to be rendered by analyzing the Slug
to create strike cache differences and serialize the Blob to a Slug.
Then the serialized strike cache differences are used to populate
the strike cache using a different TypefaceIDs using SkTypeface_Remote
as a proxy for the real SkTypeface. This will create a hard break
between the original glyph data, and the proxied glyph data.
It will then deserialize the Slug doing TypefaceID translation to
the SkTypeface_Remote, and draw the unflattened Slug.
Bug: chromium:1278340
Change-Id: I0f1980dee966b1092a99741793aed9d138451f4d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/510228
Reviewed-by: Robert Phillips <robertphillips@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 9eaaa07..60444ea 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -261,7 +261,8 @@
* rendering of all glyphs. This must be set to true to use GrSlug.
*/
#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG) || \
- defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
+ defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE) || \
+ defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
bool fSupportBilerpFromGlyphAtlas = true;
#else
bool fSupportBilerpFromGlyphAtlas = false;
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 26106cc..a5b3b28 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -1804,7 +1804,6 @@
skgpu::v1::SurfaceDrawContext* sdc,
GrAtlasSubRunOwner) const {
SkASSERT(this->glyphCount() != 0);
- SkASSERT(!viewMatrix.localToDevice().hasPerspective());
const SkMatrix& drawMatrix = viewMatrix.localToDevice();
diff --git a/src/gpu/v1/Device.cpp b/src/gpu/v1/Device.cpp
index 7e51255..97a19ce 100644
--- a/src/gpu/v1/Device.cpp
+++ b/src/gpu/v1/Device.cpp
@@ -50,6 +50,10 @@
#include "src/image/SkSurface_Gpu.h"
#include "src/utils/SkUTF.h"
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
+ #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
+#endif
+
#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner())
///////////////////////////////////////////////////////////////////////////////
@@ -987,6 +991,108 @@
}
#endif
+// This testing method draws a blob by analyzing it to create strike cache
+// differences and then serializing the Blob to a Slug. This creates a hard
+// break between the original glyph data, and the proxied glyph data - and
+// closely mimics how Chrome draws text.
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
+namespace {
+class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
+ public SkStrikeClient::DiscardableHandleManager {
+public:
+ DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
+ ~DiscardableManager() override = default;
+
+ // Server implementation.
+ SkDiscardableHandleId createHandle() override SK_EXCLUDES(fLock) {
+ SkAutoMutexExclusive l(fLock);
+
+ // Handles starts as locked.
+ fLockedHandles.add(++fNextHandleId);
+ return fNextHandleId;
+ }
+ bool lockHandle(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
+ SkAutoMutexExclusive l(fLock);
+
+ fLockedHandles.add(id);
+ return true;
+ }
+
+ // Client implementation.
+ bool deleteHandle(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
+ return false;
+ }
+
+ void notifyCacheMiss(
+ SkStrikeClient::CacheMissType type, int fontSize) override SK_EXCLUDES(fLock) {
+ SkAutoMutexExclusive l(fLock);
+
+ fCacheMissCount[type]++;
+ }
+ bool isHandleDeleted(SkDiscardableHandleId id) override SK_EXCLUDES(fLock) {
+ return false;
+ }
+
+private:
+ // The tests below run in parallel on multiple threads and use the same
+ // process global SkStrikeCache. So the implementation needs to be
+ // thread-safe.
+ mutable SkMutex fLock;
+
+ SkDiscardableHandleId fNextHandleId SK_GUARDED_BY(fLock) = 0u;
+ SkTHashSet<SkDiscardableHandleId> fLockedHandles SK_GUARDED_BY(fLock);
+ int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u] SK_GUARDED_BY(fLock);
+};
+} // namespace
+
+void Device::testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(
+ SkCanvas* canvas, const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
+ if (glyphRunList.blob() == nullptr) {
+ fSurfaceDrawContext->drawGlyphRunList(
+ canvas, this->clip(), this->asMatrixProvider(), glyphRunList, paint);
+ return;
+ }
+
+ sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
+ SkStrikeServer server{discardableManager.get()};
+
+ SkStrikeClient client{discardableManager, false};
+ SkSurfaceProps surfaceProps;
+ if (!canvas->getProps(&surfaceProps)) {
+ SK_ABORT("Ahhhhh! can't get the surface props.");
+ }
+ sk_sp<SkColorSpace> colorSpace = canvas->imageInfo().refColorSpace();
+ bool useDFT = this->recordingContext()->asDirectContext()->supportsDistanceFieldText();
+ auto analysisCanvas = server.makeAnalysisCanvas(
+ canvas->getBaseLayerSize().width(), canvas->getBaseLayerSize().width(),
+ surfaceProps,
+ std::move(colorSpace),
+ useDFT
+ );
+
+ analysisCanvas->setMatrix(canvas->getTotalMatrix());
+ auto srcSlug = GrSlug::ConvertBlob(analysisCanvas.get(),
+ *glyphRunList.blob(),
+ glyphRunList.origin(),
+ paint);
+
+ if (srcSlug == nullptr) {
+ return;
+ }
+
+ std::vector<uint8_t> serverStrikeData;
+ server.writeStrikeData(&serverStrikeData);
+
+ if (!client.readStrikeData(serverStrikeData.data(), serverStrikeData.size())) {
+ SK_ABORT("Problem reading the strike cache updates");
+ }
+
+ auto dstSlugData = srcSlug->serialize();
+ auto dstSlug = client.deserializeSlug(dstSlugData->data(), dstSlugData->size());
+ this->drawSlug(canvas, dstSlug.get());
+}
+#endif
+
void Device::onDrawGlyphRunList(SkCanvas* canvas,
const SkGlyphRunList& glyphRunList,
const SkPaint& paint) {
@@ -994,14 +1100,16 @@
GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get());
SkASSERT(!glyphRunList.hasRSXForm());
- #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
this->testingOnly_drawGlyphRunListWithSlug(canvas, glyphRunList, paint);
- #elif defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
+#elif defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
this->testingOnly_drawGlyphRunListWithSerializedSlug(canvas, glyphRunList, paint);
- #else
+#elif defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
+ this->testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(canvas, glyphRunList, paint);
+#else
fSurfaceDrawContext->drawGlyphRunList(
canvas, this->clip(), this->asMatrixProvider(), glyphRunList, paint);
- #endif
+#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/v1/Device_v1.h b/src/gpu/v1/Device_v1.h
index c963ede..876f415 100644
--- a/src/gpu/v1/Device_v1.h
+++ b/src/gpu/v1/Device_v1.h
@@ -210,17 +210,28 @@
bool forceConservativeRasterClip() const override { return true; }
const GrClip* clip() const { return &fClip; }
- #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG)
void testingOnly_drawGlyphRunListWithSlug(SkCanvas* canvas,
const SkGlyphRunList& glyphRunList,
const SkPaint& paint);
- #endif
- #if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
+ void testingOnly_drawGlyphRunListWithSlug(SkCanvas* canvas,
+ const SkGlyphRunList& glyphRunList,
+ const SkPaint& paint);
+#endif
+
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_SERIALIZE)
void testingOnly_drawGlyphRunListWithSerializedSlug(SkCanvas* canvas,
const SkGlyphRunList& glyphRunList,
const SkPaint& paint);
- #endif
+#endif
+
+#if defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
+ void testingOnly_drawGlyphRunListWithSerializedSlugAndStrike(SkCanvas* canvas,
+ const SkGlyphRunList& glyphRunList,
+ const SkPaint& paint);
+#endif
+
// If not null, dstClip must be contained inside dst and will also respect the edge AA flags.
// If 'preViewMatrix' is not null, final CTM will be this->ctm() * preViewMatrix.
void drawImageQuad(const SkImage*, const SkRect* src, const SkRect* dst,
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index d8a19ca..88f2d99 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -30,6 +30,10 @@
#include "tools/ToolUtils.h"
#include "tools/fonts/TestEmptyTypeface.h"
+// Since SkRemoteGlyphCache is not re-entrant, we can't use it while drawing slugs to simulate
+// text blobs in the GPU stack.
+#if !defined(SK_EXPERIMENTAL_SIMULATE_DRAWGLYPHRUNLIST_WITH_SLUG_STRIKE_SERIALIZE)
+
class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
public SkStrikeClient::DiscardableHandleManager {
public:
@@ -1080,3 +1084,4 @@
// Must unlock everything on termination, otherwise valgrind complains about memory leaks.
discardableManager->unlockAndDeleteAll();
}
+#endif