mirror of
https://github.com/harfbuzz/harfbuzz.git
synced 2025-04-12 16:23:01 +00:00
Merge pull request #5031 from harfbuzz/aat-speedup
[aat] Add a class-cache to the machine & fix speed regression from 2023!
This commit is contained in:
commit
cafbdf4217
3 changed files with 59 additions and 66 deletions
|
@ -30,6 +30,7 @@
|
|||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-map.hh"
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-cache.hh"
|
||||
|
||||
namespace OT {
|
||||
struct GDEF;
|
||||
|
@ -43,6 +44,9 @@ using namespace OT;
|
|||
|
||||
struct ankr;
|
||||
|
||||
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
|
||||
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
|
||||
|
||||
struct hb_aat_apply_context_t :
|
||||
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
|
||||
{
|
||||
|
@ -62,9 +66,9 @@ struct hb_aat_apply_context_t :
|
|||
const OT::GDEF *gdef_table;
|
||||
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
|
||||
hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
|
||||
hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
|
||||
hb_set_digest_t left_set = hb_set_digest_t::full ();
|
||||
hb_set_digest_t right_set = hb_set_digest_t::full ();
|
||||
hb_aat_class_cache_t *machine_class_cache = nullptr;
|
||||
hb_mask_t subtable_flags = 0;
|
||||
|
||||
/* Unused. For debug tracing only. */
|
||||
|
@ -636,14 +640,16 @@ struct StateTable
|
|||
int new_state (unsigned int newState) const
|
||||
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
|
||||
|
||||
template <typename set_t>
|
||||
unsigned int get_class (hb_codepoint_t glyph_id,
|
||||
unsigned int num_glyphs,
|
||||
const set_t &glyphs) const
|
||||
hb_aat_class_cache_t *cache = nullptr) const
|
||||
{
|
||||
unsigned klass;
|
||||
if (cache && cache->get (glyph_id, &klass)) return klass;
|
||||
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
|
||||
if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
|
||||
return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
|
||||
klass = (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
|
||||
if (cache) cache->set (glyph_id, klass);
|
||||
return klass;
|
||||
}
|
||||
|
||||
const Entry<Extra> *get_entries () const
|
||||
|
@ -651,13 +657,14 @@ struct StateTable
|
|||
|
||||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
unsigned n_classes = nClasses;
|
||||
if (unlikely (klass >= n_classes))
|
||||
klass = CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
||||
unsigned int entry = states[state * nClasses + klass];
|
||||
unsigned int entry = states[state * n_classes + klass];
|
||||
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
|
||||
|
||||
return entries[entry];
|
||||
|
@ -934,7 +941,7 @@ struct StateTableDriver
|
|||
{
|
||||
const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
|
||||
return !c->is_actionable (ac->buffer, this, entry) &&
|
||||
machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
|
||||
machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
|
@ -977,7 +984,7 @@ struct StateTableDriver
|
|||
}
|
||||
|
||||
unsigned int klass = likely (buffer->idx < buffer->len) ?
|
||||
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
|
||||
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
|
||||
(unsigned) CLASS_END_OF_TEXT;
|
||||
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
|
||||
const EntryT &entry = machine.get_entry (state, klass);
|
||||
|
@ -1011,41 +1018,36 @@ struct StateTableDriver
|
|||
*
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/2860
|
||||
*/
|
||||
|
||||
const auto is_safe_to_break_extra = [&]()
|
||||
{
|
||||
/* 2c. */
|
||||
const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
|
||||
|
||||
/* 2c'. */
|
||||
if (c->is_actionable (buffer, this, wouldbe_entry))
|
||||
return false;
|
||||
|
||||
/* 2c". */
|
||||
return next_state == machine.new_state(wouldbe_entry.newState)
|
||||
&& (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
|
||||
};
|
||||
|
||||
const auto is_safe_to_break = [&]()
|
||||
{
|
||||
const EntryT *wouldbe_entry;
|
||||
bool is_safe_to_break =
|
||||
(
|
||||
/* 1. */
|
||||
if (c->is_actionable (buffer, this, entry))
|
||||
return false;
|
||||
!c->is_actionable (buffer, this, entry) &&
|
||||
|
||||
/* 2. */
|
||||
// This one is meh, I know...
|
||||
const auto ok =
|
||||
(
|
||||
state == StateTableT::STATE_START_OF_TEXT
|
||||
|| ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
|
||||
|| is_safe_to_break_extra();
|
||||
if (!ok)
|
||||
return false;
|
||||
|| (
|
||||
/* 2c. */
|
||||
wouldbe_entry = &machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass)
|
||||
,
|
||||
/* 2c'. */
|
||||
!c->is_actionable (buffer, this, *wouldbe_entry) &&
|
||||
/* 2c". */
|
||||
(
|
||||
next_state == machine.new_state(wouldbe_entry->newState) &&
|
||||
(entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
|
||||
)
|
||||
)
|
||||
) &&
|
||||
|
||||
/* 3. */
|
||||
return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
|
||||
};
|
||||
!c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT))
|
||||
);
|
||||
|
||||
if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
|
||||
if (!is_safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
|
||||
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
|
||||
|
||||
c->transition (buffer, this, entry);
|
||||
|
|
|
@ -171,10 +171,6 @@ struct RearrangementSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->face);
|
||||
|
||||
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
|
||||
!c->buffer_digest.may_have (c->machine_glyph_set))
|
||||
return_trace (false);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -336,10 +332,6 @@ struct ContextualSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->face);
|
||||
|
||||
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
|
||||
!c->buffer_digest.may_have (c->machine_glyph_set))
|
||||
return_trace (false);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -599,10 +591,6 @@ struct LigatureSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->face);
|
||||
|
||||
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
|
||||
!c->buffer_digest.may_have (c->machine_glyph_set))
|
||||
return_trace (false);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -875,10 +863,6 @@ struct InsertionSubtable
|
|||
|
||||
StateTableDriver<Types, EntryData> driver (machine, c->face);
|
||||
|
||||
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
|
||||
!c->buffer_digest.may_have (c->machine_glyph_set))
|
||||
return_trace (false);
|
||||
|
||||
driver.drive (&dc, c);
|
||||
|
||||
return_trace (dc.ret);
|
||||
|
@ -935,24 +919,17 @@ struct hb_accelerate_subtables_context_t :
|
|||
friend struct hb_aat_layout_lookup_accelerator_t;
|
||||
|
||||
public:
|
||||
hb_set_digest_t digest;
|
||||
|
||||
template <typename T>
|
||||
auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
|
||||
(
|
||||
obj_.machine.collect_glyphs (this->digest, num_glyphs)
|
||||
)
|
||||
|
||||
template <typename T>
|
||||
void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
|
||||
{
|
||||
digest = digest.full ();
|
||||
}
|
||||
mutable hb_aat_class_cache_t class_cache;
|
||||
|
||||
template <typename T>
|
||||
void init (const T &obj_, unsigned num_glyphs)
|
||||
{
|
||||
init_ (obj_, num_glyphs, hb_prioritize);
|
||||
class_cache.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
fini ()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -999,12 +976,21 @@ struct hb_aat_layout_chain_accelerator_t
|
|||
if (unlikely (!thiz))
|
||||
return nullptr;
|
||||
|
||||
thiz->count = count;
|
||||
|
||||
hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
|
||||
chain.dispatch (&c_accelerate_subtables);
|
||||
|
||||
return thiz;
|
||||
}
|
||||
|
||||
void destroy ()
|
||||
{
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
subtables[i].fini ();
|
||||
}
|
||||
|
||||
unsigned count;
|
||||
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
|
||||
};
|
||||
|
||||
|
@ -1156,7 +1142,7 @@ struct Chain
|
|||
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
|
||||
goto skip;
|
||||
c->subtable_flags = subtable->subFeatureFlags;
|
||||
c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
|
||||
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
|
||||
|
||||
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
|
||||
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
||||
|
@ -1317,7 +1303,11 @@ struct mortmorx
|
|||
~accelerator_t ()
|
||||
{
|
||||
for (unsigned int i = 0; i < this->chain_count; i++)
|
||||
{
|
||||
if (this->accels[i])
|
||||
this->accels[i]->destroy ();
|
||||
hb_free (this->accels[i]);
|
||||
}
|
||||
hb_free (this->accels);
|
||||
this->table.destroy ();
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ struct hb_atomic_ptr_t
|
|||
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
|
||||
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
|
||||
|
||||
operator bool () const { return get_acquire () != nullptr; }
|
||||
T * operator -> () const { return get_acquire (); }
|
||||
template <typename C> operator C * () const { return get_acquire (); }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue