// -- RemoteStrike ---------------------------------------------------------------------------- class RemoteStrike final : public sktext::StrikeForGPU { public: // N.B. RemoteStrike is not valid until ensureScalerContext is called.
RemoteStrike(const SkStrikeSpec& strikeSpec,
std::unique_ptr<SkScalerContext> context,
SkDiscardableHandleId discardableHandleId);
~RemoteStrike() override = default;
// The context built using fDescriptor
std::unique_ptr<SkScalerContext> fContext;
SkTypefaceID fStrikeSpecTypefaceId;
// fStrikeSpec is set every time getOrCreateCache is called. This allows the code to maintain // the fContext as lazy as possible. const SkStrikeSpec* fStrikeSpec;
// Have the metrics been sent for this strike. Only send them once. bool fHaveSentFontMetrics{false};
// The masks and paths that currently reside in the GPU process.
THashTable<SkGlyphDigest, SkPackedGlyphID, SkGlyphDigest> fSentGlyphs;
// The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed // TextBlobs. Cleared after diffs are serialized.
std::vector<SkGlyph> fMasksToSend;
std::vector<SkGlyph> fPathsToSend;
std::vector<SkGlyph> fDrawablesToSend;
// Alloc for storing bits and pieces of paths and drawables, Cleared after diffs are serialized.
SkArenaAllocWithReset fAlloc{256};
};
RemoteStrike::RemoteStrike( const SkStrikeSpec& strikeSpec,
std::unique_ptr<SkScalerContext> context,
uint32_t discardableHandleId)
: fDescriptor{strikeSpec.descriptor()}
, fDiscardableHandleId(discardableHandleId)
, fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()} // N.B. context must come last because it is used above.
, fContext{std::move(context)}
, fStrikeSpecTypefaceId(strikeSpec.typeface().uniqueID()) {
SkASSERT(fDescriptor.getDesc() != nullptr);
SkASSERT(fContext != nullptr);
}
// ScalerContext should not hold to the typeface, so we should not use its ID. // We should use StrikeSpec typeface and its ID instead.
buffer.writeUInt(fStrikeSpecTypefaceId);
buffer.writeUInt(fDiscardableHandleId);
fDescriptor.getDesc()->flatten(buffer);
buffer.writeBool(fHaveSentFontMetrics); if (!fHaveSentFontMetrics) { // Write FontMetrics if not sent before.
SkFontMetrics fontMetrics;
fContext->getFontMetrics(&fontMetrics);
SkFontMetricsPriv::Flatten(buffer, fontMetrics);
fHaveSentFontMetrics = true;
}
// Make sure to install all the mask data into the glyphs before sending. for (SkGlyph& glyph: fMasksToSend) {
this->prepareForImage(&glyph);
}
// Make sure to install all the path data into the glyphs before sending. for (SkGlyph& glyph: fPathsToSend) {
this->prepareForPath(&glyph);
}
// Make sure to install all the drawable data into the glyphs before sending. for (SkGlyph& glyph: fDrawablesToSend) {
this->prepareForDrawable(&glyph);
}
// Send all the pending glyph information.
SkStrike::FlattenGlyphsByType(buffer, fMasksToSend, fPathsToSend, fDrawablesToSend);
// Reset all the sending data.
fMasksToSend.clear();
fPathsToSend.clear();
fDrawablesToSend.clear();
fAlloc.reset();
}
void SkStrikeServerImpl::writeStrikeData(std::vector<uint8_t>* memory) { // We can use the default SkSerialProcs because we do not currently need to encode any SkImages.
SkBinaryWriteBuffer buffer{nullptr, 0, {}};
// Gather statistics about what needs to be sent.
size_t strikesToSend = 0;
fRemoteStrikesToSend.foreach([&](RemoteStrike* strike) { if (strike->hasPendingGlyphs()) {
strikesToSend++;
} else { // This strike has nothing to send, so drop its scaler context to reduce memory.
strike->resetScalerContext();
}
});
// If there are no strikes or typefaces to send, then cleanup and return. if (strikesToSend == 0 && fTypefacesToSend.empty()) {
fRemoteStrikesToSend.reset(); return;
}
// Send newly seen typefaces.
SkASSERT_RELEASE(SkTFitsIn<int>(fTypefacesToSend.size()));
buffer.writeInt(fTypefacesToSend.size()); for (constauto& typeface: fTypefacesToSend) {
SkTypefaceProxyPrototype proto{typeface};
proto.flatten(buffer);
}
fTypefacesToSend.clear();
void SkStrikeServerImpl::checkForDeletedEntries() { auto it = fDescToRemoteStrike.begin(); while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
it != fDescToRemoteStrike.end()) {
RemoteStrike* strike = it->second.get(); if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) { // If we are trying to send the strike, then do not erase it. if (!fRemoteStrikesToSend.contains(strike)) { // Erase returns the iterator following the removed element.
it = fDescToRemoteStrike.erase(it); continue;
}
}
++it;
}
}
sk_sp<RemoteStrike> SkStrikeServerImpl::getOrCreateCache(const SkStrikeSpec& strikeSpec) { // In cases where tracing is turned off, make sure not to get an unused function warning. // Lambdaize the function.
TRACE_EVENT1("skia", "RecForDesc", "rec",
TRACE_STR_COPY(
[&strikeSpec](){ auto ptr =
strikeSpec.descriptor().findEntry(kRec_SkDescriptorTag, nullptr);
SkScalerContextRec rec;
std::memcpy((void*)&rec, ptr, sizeof(rec)); return rec.dump();
}().c_str()
)
);
if (auto it = fDescToRemoteStrike.find(&strikeSpec.descriptor());
it != fDescToRemoteStrike.end())
{ // We have processed the RemoteStrike before. Reuse it.
sk_sp<RemoteStrike> strike = it->second;
strike->setStrikeSpec(strikeSpec); if (fRemoteStrikesToSend.contains(strike.get())) { // Already tracking return strike;
}
// Strike is in unknown state on GPU. Start tracking strike on GPU by locking it. bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId()); if (locked) {
fRemoteStrikesToSend.add(strike.get()); return strike;
}
// If it wasn't locked, then forget this strike, and build it anew below.
fDescToRemoteStrike.erase(it);
}
const SkTypeface& typeface = strikeSpec.typeface(); // Create a new RemoteStrike. Start by processing the typeface. const SkTypefaceID typefaceId = typeface.uniqueID(); if (!fCachedTypefaces.contains(typefaceId)) {
fCachedTypefaces.add(typefaceId);
fTypefacesToSend.emplace_back(typeface);
}
auto context = strikeSpec.createScalerContext(); auto newHandle = fDiscardableHandleManager->createHandle(); // Locked on creation auto remoteStrike = sk_make_sp<RemoteStrike>(strikeSpec, std::move(context), newHandle);
remoteStrike->setStrikeSpec(strikeSpec);
fRemoteStrikesToSend.add(remoteStrike.get()); auto d = &remoteStrike->getDescriptor();
fDescToRemoteStrike[d] = remoteStrike;
// Just ignore the resulting SubRunContainer. Since we're passing in a null SubRunAllocator // no SubRuns will be produced.
STSubRunAllocator<sizeof(SubRunContainer), alignof(SubRunContainer)> tempAlloc; auto container = SubRunContainer::MakeInAlloc(glyphRunList,
drawMatrix,
paint,
this->strikeDeviceInfo(),
fStrikeServerImpl,
&tempAlloc,
SubRunContainer::kStrikeCalculationsOnly, "Cache Diff"); // Calculations only. No SubRuns.
SkASSERT(container->isEmpty());
}
// Use the SkStrikeServer's strike cache to generate the Slug. return sktext::gpu::MakeSlug(this->localToDevice(),
glyphRunList,
paint,
this->strikeDeviceInfo(),
fStrikeServerImpl);
}
std::unique_ptr<SkCanvas> SkStrikeServer::makeAnalysisCanvas(int width, int height, const SkSurfaceProps& props,
sk_sp<SkColorSpace> colorSpace, bool DFTSupport, bool DFTPerspSupport) { #if !defined(SK_DISABLE_SDF_TEXT) // These are copied from the defaults in GrContextOptions for historical reasons. // TODO(herb, jvanverth) pipe in parameters that can be used for both Ganesh and Graphite // backends instead of just using the defaults.
constexpr float kMinDistanceFieldFontSize = 18.f;
#ifdefined(SK_BUILD_FOR_ANDROID)
constexpr float kGlyphsAsPathsFontSize = 384.f; #elifdefined(SK_BUILD_FOR_MAC)
constexpr float kGlyphsAsPathsFontSize = 256.f; #else
constexpr float kGlyphsAsPathsFontSize = 324.f; #endif // There is no need to set forcePathAA for the remote glyph cache as that control impacts // *how* the glyphs are rendered as paths, not *when* they are rendered as paths. auto control = sktext::gpu::SubRunControl{DFTSupport,
props.isUseDeviceIndependentFonts(),
DFTPerspSupport,
kMinDistanceFieldFontSize,
kGlyphsAsPathsFontSize}; #else auto control = sktext::gpu::SubRunControl{}; #endif
// Change the path count to track the line number of the failing read. // TODO: change __LINE__ back to glyphPathsCount when bug chromium:1287356 is closed. #define READ_FAILURE \
{ \
SkDebugf("Bad font data serialization line: %d", __LINE__); \
SkStrikeClient::DiscardableHandleManager::ReadFailureData data = { \
memorySize, deserializer.bytesRead(), typefaceSize, \
strikeCount, glyphImagesCount, __LINE__}; \
fDiscardableHandleManager->notifyReadFailure(data); \ returnfalse; \
}
// We do not need to set any SkDeserialProcs here because SkStrikeServerImpl::writeStrikeData // did not encode any SkImages.
SkReadBuffer buffer{const_cast<constvoid*>(memory), memorySize}; // Limit the kinds of effects that appear in a glyph's drawable (crbug.com/1442140):
buffer.setAllowSkSL(false);
// Read the number of typefaces sent. constint typefaceCount = buffer.readInt(); for (curTypeface = 0; curTypeface < typefaceCount; ++curTypeface) { auto proto = SkTypefaceProxyPrototype::MakeFromBuffer(buffer); if (proto) {
this->addTypeface(proto.value());
} else {
postError(__LINE__); returnfalse;
}
}
// Read the number of strikes sent. constint stirkeCount = buffer.readInt(); for (curStrike = 0; curStrike < stirkeCount; ++curStrike) {
if (!this->translateTypefaceID(&serverDescriptor.value())) {
postError(__LINE__); returnfalse;
}
SkDescriptor* clientDescriptor = serverDescriptor->getDesc(); auto strike = fStrikeCache->findStrike(*clientDescriptor);
if (strike == nullptr) { // Metrics are only sent the first time. If creating a new strike, then the metrics // are not initialized. if (fontMetricsInitialized) {
postError(__LINE__); returnfalse;
}
SkStrikeSpec strikeSpec{*clientDescriptor, *clientTypeface};
strike = fStrikeCache->createStrike(
strikeSpec, &fontMetrics.value(),
std::make_unique<DiscardableStrikePinner>(
discardableHandleID, fDiscardableHandleManager));
}
// Make sure this strike is pinned on the GPU side.
strike->verifyPinnedStrike();
if (!strike->mergeFromBuffer(buffer)) {
postError(__LINE__); returnfalse;
}
}
// Rewrite the typefaceID in the rec.
{
uint32_t size; // findEntry returns a const void*, remove the const in order to update in place. void* ptr = const_cast<void *>(descriptor.findEntry(kRec_SkDescriptorTag, &size));
SkScalerContextRec rec; if (!ptr || size != sizeof(rec)) { returnfalse; }
std::memcpy((void*)&rec, ptr, size); // Get the local typeface from remote typefaceID. auto* tfPtr = fServerTypefaceIdToTypeface.find(rec.fTypefaceID); // Received a strike for a typeface which doesn't exist. if (!tfPtr) { returnfalse; } // Update the typeface id to work with the client side.
rec.fTypefaceID = tfPtr->get()->uniqueID();
std::memcpy(ptr, &rec, size);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.