Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  GlyphVector.h

  Sprache: C
 

/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#ifndef sktext_gpu_GlyphVector_DEFINED
#define sktext_gpu_GlyphVector_DEFINED

#include "include/core/SkSpan.h"
#include "src/core/SkGlyph.h"
#include "src/core/SkStrike.h"  // IWYU pragma: keep
#include "src/gpu/MaskFormat.h"
#include "src/text/gpu/StrikeCache.h"

#include <cstddef>
#include <cstdint>
#include <functional>
#include <optional>

class SkReadBuffer;
class SkStrikeClient;
class SkWriteBuffer;

namespace sktext::gpu {
class SubRunAllocator;
class StrikeCache;

/**
 * Concepts used to describe backend-specific (Ganesh v. Graphite) data stored in GlyphVector.
 * The backend stores a type conforming to BackendData in each GlyphVector. This pertains to
 * the whole vector. The instance of the BackendData type is then used to convert from
 * SkPackedGlyphID to a backend-specific type conforming to GlyphType. The instances of
 * the type conforming to GlyphType actually overwrite the packed IDs. However, GlyphType
 * has a requirement to that it can convert back to packed id.
 *
 * Specific requirements for each type (other than size and alignment):
 * BackendData:
 * 1) Has a static method FindStrike that returns a sk_sp<T> where T is a subclass of
 *    TextStrikeBase.
 * 2) Has a member function makeGlyphFromID that takes SkPackedGlyphID and yields
 *    an instance of a type conforming to GlyphType.
 * GlyphType:
 * 1) Is trivially destructible. We could relax this by adding calls to the destructor
 *    if needed it proved useful.
 * 2) Has a method packedID() const that yields (something convertible to)
 *    SkPackedGlyphID.
 *
 * We use concepts rather than a base class for BackendData because it allows us to
 * require the static method on BackendData and it allows us to require that
 * makeFromGlyphID() yields any type that convert back to packedID() without requiring
 * a virtual function/vtable for GlyphType.
 */

namespace GlyphVector_Concepts {

// Both backends currently store pointer-sized types for glyphs and 88 is currently sufficient for
// Ganesh and Graphite's BackendData.
static constexpr size_t kMaxGlyphTypeSize = sizeof(void*);
static constexpr size_t kMaxBackendDataSize = 88;

template <typename T>
concept GlyphType = requires(const T& t) {
    requires sizeof(T)  <= kMaxGlyphTypeSize;
    // We store these in an array with kMaxGlyphTypeSize per entry. So that alignment must be
    // sufficient.
    requires alignof(T) <= kMaxGlyphTypeSize;

    std::is_trivially_destructible_v<T>;

    { t.packedID() } -> std::convertible_to<SkPackedGlyphID>;
};

template <typename T, template <typename...> class Template>
constexpr bool is_specialization_of_v = false;

template <template <typename...> class Template, typename... Args>
constexpr bool is_specialization_of_v<Template<Args...>, Template> = true;

template <typename T>
concept BackendData = requires(T& t,
                               StrikeCache* cache,
                               const SkStrikeSpec& spec,
                               SkPackedGlyphID id,
                               skgpu::MaskFormat maskFormat) {
    requires alignof(T) <= alignof(max_align_t);
    requires sizeof(T)  <= kMaxBackendDataSize;

    T::FindStrike(cache, spec);
    requires is_specialization_of_v<decltype(T::FindStrike(cache, spec)), sk_sp>;
    requires std::derived_from<typename decltype(T::FindStrike(cache, spec))::element_type, TextStrikeBase>;

    // Must have a makeGlyphFromID that returns a GlyphType
    { t.makeGlyphFromID(id, maskFormat) } -> GlyphType;
};
}  // namespace GlyphVector_Concepts

// -- GlyphVector ----------------------------------------------------------------------------------
// GlyphVector provides a way to delay the lookup of Glyphs until the code is running on the GPU
// in single threaded mode. The GlyphVector is created in a multi-threaded environment, but the
// StrikeCache is only single threaded (and must be single threaded because of the atlas).
//
// Once in the single-threaded GPU environment the glyph packed IDs are converted into a GPU backend
// specific entry type from which each glyph's atlas location can be determined.
class GlyphVector {
    using GlyphBytes = std::array<std::byte, GlyphVector_Concepts::kMaxGlyphTypeSize>;
    using BackendDataBytes = std::array<std::byte, GlyphVector_Concepts::kMaxBackendDataSize>;

    // Get the specific TextStrikeBase-derived strike class and GlyphType-conforming types yieled
    // by a BackendData-conforming type.
    template <GlyphVector_Concepts::BackendData B>
    using Strike = std::invoke_result_t<decltype(B::FindStrike), StrikeCache*, const SkStrikeSpec&>;

    template <GlyphVector_Concepts::BackendData B>
    using Glyph = decltype(std::declval<B>().makeGlyphFromID(SkPackedGlyphID{},
                                                             skgpu::MaskFormat::kARGB));

public:
    static size_t Size(int numGlyphs) {
        SkASSERT(numGlyphs >= 0);
        return SkAlignTo(sizeof(GlyphVector), alignof(max_align_t)) + sizeof(GlyphBytes) * numGlyphs;
    }

    GlyphVector(SkStrikePromise&& strikePromise, SkSpan<GlyphBytes> glyphs);

    // To move in to AtlasSubRun constructor
    GlyphVector(GlyphVector&&);

    GlyphVector(const GlyphVector&&)           = delete;
    GlyphVector& operator=(const GlyphVector&) = delete;
    GlyphVector& operator=(GlyphVector&&)      = delete;

    ~GlyphVector();

    static GlyphVector Make(SkStrikePromise&& promise,
                            SkSpan<const SkPackedGlyphID> glyphs,
                            SubRunAllocator* alloc);

    int glyphCount() const { return SkToInt(fGlyphs.size()); }

    static std::optional<GlyphVector> MakeFromBuffer(SkReadBuffer& buffer,
                                                     const SkStrikeClient* strikeClient,
                                                     SubRunAllocator* alloc);
    void flatten(SkWriteBuffer& buffer) const;

    // This doesn't need to include sizeof(GlyphVector) because this is embedded in each of
    // the sub runs.
    int unflattenSize() const { return Size(fGlyphs.size()); }

    bool hasBackendData() const {
        SkASSERT(SkToBool(fBackendDataReleaser) == SkToBool(fGetGlyphID));
        return SkToBool(fBackendDataReleaser);
    }

    template <GlyphVector_Concepts::BackendData B> const B& accessBackendData() const {
        SkASSERT(this->hasBackendData());
        return *reinterpret_cast<const B*>(fBackendDataBytes.data());
    }

    template <GlyphVector_Concepts::BackendData B> B& accessBackendData() {
        SkASSERT(this->hasBackendData());
        return *reinterpret_cast<B*>(fBackendDataBytes.data());
    }

    template <GlyphVector_Concepts::GlyphType G> SkSpan<const G> accessBackendGlyphs() const {
        SkASSERT(this->hasBackendData());
        auto* first = reinterpret_cast<const G*>(fGlyphs.front().data());
        return {first, fGlyphs.size()};
    }

    template <GlyphVector_Concepts::BackendData B>
    void initBackendData(StrikeCache* cache, skgpu::MaskFormat maskFormat, auto&&... args)
        requires std::is_constructible_v<B, Strike<B>, decltype(args)...> {
        SkASSERT(!this->hasBackendData());
        SkASSERT(cache);

        SkStrike* strike = fStrikePromise.strike();
        const SkStrikeSpec& spec = strike->strikeSpec();
        auto backendStrike = B::FindStrike(cache, spec);

        auto backendData = new (fBackendDataBytes.data()) B{
            std::move(backendStrike),
            std::forward<decltype(args)>(args)...
        };

        using G = Glyph<B>;

        for (auto& g : fGlyphs) {
            auto id = *reinterpret_cast<SkPackedGlyphID*>(g.data());
            new (g.data()) G{backendData->makeGlyphFromID(id, maskFormat)};
        }

        fBackendDataReleaser = [](std::byte* p) { reinterpret_cast<B*>(p)->~B(); };

        fGetGlyphID = [](const std::byte* b) {
            auto* g = reinterpret_cast<const G*>(b);
            return g->packedID();
        };

        strike->verifyPinnedStrike();
        fStrikePromise.resetStrike();
    }

private:
    friend class GlyphVectorTestingPeer;

    using Releaser = void(std::byte*);

    using GetGlyphID = SkPackedGlyphID(const std::byte*);

    alignas(max_align_t) BackendDataBytes fBackendDataBytes;

    Releaser*   fBackendDataReleaser = nullptr;
    GetGlyphID* fGetGlyphID          = nullptr;

    SkStrikePromise fStrikePromise;

    SkSpan<GlyphBytes> fGlyphs;
};
}  // namespace sktext::gpu
#endif  // sktext_gpu_GlyphVector_DEFINED

Messung V0.5 in Prozent
C=86 H=99 G=92

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002