Improve sheet rendering performance
- Cache font markup parsing - Cache SCH_SYMBOL::GetOrientation - Don't construct new strings each time in GetDefaultFieldName
This commit is contained in:
parent
5b43dc4e7b
commit
7b3fd2113c
|
@ -24,6 +24,10 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <wx/font.h>
|
||||
#include <string_utils.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
|
@ -47,6 +51,75 @@ FONT* FONT::s_defaultFont = nullptr;
|
|||
|
||||
std::map< std::tuple<wxString, bool, bool>, FONT*> FONT::s_fontMap;
|
||||
|
||||
class MARKUP_CACHE
|
||||
{
|
||||
public:
|
||||
struct ENTRY
|
||||
{
|
||||
std::string source;
|
||||
std::unique_ptr<MARKUP::NODE> root;
|
||||
};
|
||||
|
||||
typedef std::pair<wxString, ENTRY> CACHE_ENTRY;
|
||||
|
||||
MARKUP_CACHE( size_t aMaxSize ) :
|
||||
m_maxSize( aMaxSize )
|
||||
{
|
||||
}
|
||||
|
||||
ENTRY& Put( const CACHE_ENTRY::first_type& aQuery, ENTRY&& aResult )
|
||||
{
|
||||
auto it = m_cache.find( aQuery );
|
||||
|
||||
m_cacheMru.emplace_front( CACHE_ENTRY( aQuery, std::move( aResult ) ) );
|
||||
|
||||
if( it != m_cache.end() )
|
||||
{
|
||||
m_cacheMru.erase( it->second );
|
||||
m_cache.erase( it );
|
||||
}
|
||||
|
||||
m_cache[aQuery] = m_cacheMru.begin();
|
||||
|
||||
if( m_cache.size() > m_maxSize )
|
||||
{
|
||||
auto last = m_cacheMru.end();
|
||||
last--;
|
||||
m_cache.erase( last->first );
|
||||
m_cacheMru.pop_back();
|
||||
}
|
||||
|
||||
return m_cacheMru.begin()->second;
|
||||
}
|
||||
|
||||
ENTRY* Get( const CACHE_ENTRY::first_type& aQuery )
|
||||
{
|
||||
auto it = m_cache.find( aQuery );
|
||||
|
||||
if( it == m_cache.end() )
|
||||
return nullptr;
|
||||
|
||||
m_cacheMru.splice( m_cacheMru.begin(), m_cacheMru, it->second );
|
||||
|
||||
return &m_cacheMru.begin()->second;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_cacheMru.clear();
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_maxSize;
|
||||
std::list<CACHE_ENTRY> m_cacheMru;
|
||||
std::unordered_map<wxString, std::list<CACHE_ENTRY>::iterator> m_cache;
|
||||
};
|
||||
|
||||
|
||||
static MARKUP_CACHE s_markupCache( 1024 );
|
||||
static std::mutex s_markupCacheMutex;
|
||||
|
||||
|
||||
FONT::FONT()
|
||||
{
|
||||
|
@ -186,7 +259,7 @@ void FONT::Draw( KIGFX::GAL* aGal, const wxString& aText, const VECTOR2I& aPosit
|
|||
* @return position of cursor for drawing next substring
|
||||
*/
|
||||
VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||
const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2I& aPosition,
|
||||
const MARKUP::NODE* aNode, const VECTOR2I& aPosition,
|
||||
const KIFONT::FONT* aFont, const VECTOR2I& aSize, const EDA_ANGLE& aAngle,
|
||||
bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle )
|
||||
{
|
||||
|
@ -221,8 +294,8 @@ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* a
|
|||
|
||||
for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
|
||||
{
|
||||
nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aFont, aSize,
|
||||
aAngle, aMirror, aOrigin, textStyle );
|
||||
nextPosition = drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
|
||||
aSize, aAngle, aMirror, aOrigin, textStyle );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,11 +308,24 @@ VECTOR2I FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYP
|
|||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
MARKUP::MARKUP_PARSER markupParser( TO_UTF8( aText ) );
|
||||
std::unique_ptr<MARKUP::NODE> root = markupParser.Parse();
|
||||
std::lock_guard<std::mutex> lock( s_markupCacheMutex );
|
||||
|
||||
return ::drawMarkup( aBoundingBox, aGlyphs, root, aPosition, this, aSize, aAngle, aMirror,
|
||||
aOrigin, aTextStyle );
|
||||
MARKUP_CACHE::ENTRY* markup = s_markupCache.Get( aText );
|
||||
|
||||
if( !markup || !markup->root )
|
||||
{
|
||||
MARKUP_CACHE::ENTRY& cached = s_markupCache.Put( aText, {} );
|
||||
|
||||
cached.source = TO_UTF8( aText );
|
||||
MARKUP::MARKUP_PARSER markupParser( &cached.source );
|
||||
cached.root = markupParser.Parse();
|
||||
markup = &cached;
|
||||
}
|
||||
|
||||
wxASSERT( markup && markup->root );
|
||||
|
||||
return ::drawMarkup( aBoundingBox, aGlyphs, markup->root.get(), aPosition, this, aSize, aAngle,
|
||||
aMirror, aOrigin, aTextStyle );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,13 @@ std::unique_ptr<NODE> MARKUP_PARSER::Parse()
|
|||
{
|
||||
try
|
||||
{
|
||||
auto root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( in );
|
||||
std::unique_ptr<NODE> root;
|
||||
|
||||
if( mem_in )
|
||||
root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( *mem_in );
|
||||
else
|
||||
root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( *in );
|
||||
|
||||
return root;
|
||||
}
|
||||
catch ( tao::pegtl::parse_error& )
|
||||
|
|
|
@ -36,16 +36,21 @@ using namespace TFIELD_T;
|
|||
#define FOOTPRINT_CANONICAL "Footprint"
|
||||
#define DATASHEET_CANONICAL "Datasheet"
|
||||
|
||||
static wxString s_CanonicalReference( REFERENCE_CANONICAL );
|
||||
static wxString s_CanonicalValue( VALUE_CANONICAL );
|
||||
static wxString s_CanonicalFootprint( FOOTPRINT_CANONICAL );
|
||||
static wxString s_CanonicalDatasheet( DATASHEET_CANONICAL );
|
||||
|
||||
const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx, bool aTranslateForHI )
|
||||
{
|
||||
if( !aTranslateForHI )
|
||||
{
|
||||
switch( aFieldNdx )
|
||||
{
|
||||
case REFERENCE_FIELD: return REFERENCE_CANONICAL; // The symbol reference, R1, C1, etc.
|
||||
case VALUE_FIELD: return VALUE_CANONICAL; // The symbol value
|
||||
case FOOTPRINT_FIELD: return FOOTPRINT_CANONICAL; // The footprint for use with Pcbnew
|
||||
case DATASHEET_FIELD: return DATASHEET_CANONICAL; // Link to a datasheet for symbol
|
||||
case REFERENCE_FIELD: return s_CanonicalReference; // The symbol reference, R1, C1, etc.
|
||||
case VALUE_FIELD: return s_CanonicalValue; // The symbol value
|
||||
case FOOTPRINT_FIELD: return s_CanonicalFootprint; // The footprint for use with Pcbnew
|
||||
case DATASHEET_FIELD: return s_CanonicalDatasheet; // Link to a datasheet for symbol
|
||||
default: return wxString::Format( wxT( "Field%d" ), aFieldNdx );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <hash.h>
|
||||
#include <macros.h>
|
||||
#include <trigo.h>
|
||||
#include <transform.h>
|
||||
|
@ -124,3 +125,9 @@ bool TRANSFORM::MapAngles( EDA_ANGLE* aAngle1, EDA_ANGLE* aAngle2 ) const
|
|||
}
|
||||
|
||||
|
||||
size_t std::hash<TRANSFORM>::operator()( const TRANSFORM& s ) const
|
||||
{
|
||||
size_t seed = std::hash<int>{}( s.x1 );
|
||||
hash_combine( seed, s.y1, s.x2, s.y2 );
|
||||
return seed;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
#include "plotters/plotter.h"
|
||||
|
||||
|
||||
std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
|
||||
|
||||
|
||||
/**
|
||||
* Convert a wxString to UTF8 and replace any control characters with a ~,
|
||||
* where a control character is one of the first ASCII values up to ' ' 32d.
|
||||
|
@ -1535,6 +1538,13 @@ void SCH_SYMBOL::SetOrientation( int aOrientation )
|
|||
|
||||
int SCH_SYMBOL::GetOrientation() const
|
||||
{
|
||||
/*
|
||||
* This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
|
||||
* now, so let's just cache it for the moment.
|
||||
*/
|
||||
if( s_transformToOrientationCache.count( m_transform ) )
|
||||
return s_transformToOrientationCache.at( m_transform );
|
||||
|
||||
int rotate_values[] =
|
||||
{
|
||||
SYM_ORIENT_0,
|
||||
|
@ -1560,8 +1570,11 @@ int SCH_SYMBOL::GetOrientation() const
|
|||
temp.SetOrientation( type_rotate );
|
||||
|
||||
if( transform == temp.GetTransform() )
|
||||
{
|
||||
s_transformToOrientationCache[m_transform] = type_rotate;
|
||||
return type_rotate;
|
||||
}
|
||||
}
|
||||
|
||||
// Error: orientation not found in list (should not happen)
|
||||
wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
|
||||
|
|
|
@ -798,6 +798,9 @@ private:
|
|||
// Defines the hierarchical path and reference of the symbol. This allows support
|
||||
// for multiple references to a single sub-sheet.
|
||||
std::vector<SCH_SYMBOL_INSTANCE> m_instanceReferences;
|
||||
|
||||
/// @see SCH_SYMBOL::GetOrientation
|
||||
static std::unordered_map<TRANSFORM, int> s_transformToOrientationCache;
|
||||
};
|
||||
|
||||
#endif /* __SYMBOL_H__ */
|
||||
|
|
|
@ -97,13 +97,20 @@ class MARKUP_PARSER
|
|||
{
|
||||
public:
|
||||
MARKUP_PARSER( const std::string& source ) :
|
||||
in( source, "from_input" )
|
||||
in( std::make_unique<string_input<>>( source, "from_input" ) ),
|
||||
mem_in()
|
||||
{}
|
||||
|
||||
MARKUP_PARSER( const std::string* source ) :
|
||||
in(),
|
||||
mem_in( std::make_unique<memory_input<>>( *source, "from_input" ) )
|
||||
{}
|
||||
|
||||
std::unique_ptr<NODE> Parse();
|
||||
|
||||
private:
|
||||
string_input<> in;
|
||||
std::unique_ptr<string_input<>> in;
|
||||
std::unique_ptr<memory_input<>> mem_in;
|
||||
};
|
||||
|
||||
} // namespace MARKUP
|
||||
|
|
|
@ -98,5 +98,12 @@ public:
|
|||
bool MapAngles( EDA_ANGLE* aAngle1, EDA_ANGLE* aAngle2 ) const;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<TRANSFORM>
|
||||
{
|
||||
size_t operator() ( const TRANSFORM& k ) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _TRANSFORM_H_
|
||||
|
|
Loading…
Reference in New Issue