Merge branch 'pymod' into pymod-splitting

This commit is contained in:
Matthias Köfferlein 2018-10-22 18:15:02 +02:00 committed by GitHub
commit 1150ffbbb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 292 additions and 141 deletions

View File

@ -15,7 +15,7 @@
DEF reader did not pull vias from LEF
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/174
Performance issue with many layers with width >1
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/175
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/176
Painting issue with texts
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/185
Hash values available as __hash__ standard method now

293
setup.py
View File

@ -54,13 +54,15 @@ and won't find them. So we need to take away the path with
"-Wl,-soname" on Linux (see Config.link_args).
"""
from setuptools import setup, Extension, Distribution, find_packages
from setuptools import setup, Distribution, find_packages
from setuptools.extension import Extension, Library
import glob
import os
import platform
import distutils.sysconfig as sysconfig
from distutils.errors import CompileError
import distutils.command.build_ext
import setuptools.command.build_ext
import multiprocessing
N_cores = multiprocessing.cpu_count()
@ -104,6 +106,8 @@ if sys.version_info[0] * 10 + sys.version_info[1] > 26:
distutils.ccompiler.CCompiler.compile = parallelCCompile
# TODO: delete (Obsolete)
# patch get_ext_filename
from distutils.command.build_ext import build_ext
_old_get_ext_filename = build_ext.get_ext_filename
@ -121,6 +125,50 @@ def patched_get_ext_filename(self, ext_name):
distutils.command.build_ext.build_ext.get_ext_filename = patched_get_ext_filename
# end patch get_ext_filename
# patch CCompiler's library_filename for _dbpi libraries (SOs)
# Its default is to have .so for shared objects, instead of dylib,
# hence the patch
from distutils.ccompiler import CCompiler
old_library_filename = CCompiler.library_filename
def patched_library_filename(self, libname, lib_type='static', # or 'shared'
strip_dir=0, output_dir=''):
if platform.system() == "Darwin" and '_dbpi' in libname:
lib_type = 'dylib'
return old_library_filename(self, libname, lib_type=lib_type,
strip_dir=strip_dir, output_dir=output_dir)
distutils.ccompiler.CCompiler.library_filename = patched_library_filename
# end patch CCompiler's library_filename for _dbpi libraries (SOs)
# despite its name, setuptools.command.build_ext.link_shared_object won't
# link a shared object on Linux, but a static library and patches distutils
# for this ... We're patching this back now.
def always_link_shared_object(
self, objects, output_libname, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
self.link(
self.SHARED_LIBRARY, objects, output_libname,
output_dir, libraries, library_dirs, runtime_library_dirs,
export_symbols, debug, extra_preargs, extra_postargs,
build_temp, target_lang
)
setuptools.command.build_ext.libtype = "shared"
setuptools.command.build_ext.link_shared_object = always_link_shared_object
# ----------------------------------------------------------------------------------------
@ -137,36 +185,76 @@ class Config(object):
build_cmd = Distribution().get_command_obj('build')
build_cmd.finalize_options()
self.build_platlib = build_cmd.build_platlib
self.build_temp = build_cmd.build_temp
if platform.system() == "Windows":
# Windows uses separate temp build folders for debug and release
if build_cmd.debug:
self.build_temp = os.path.join(self.build_temp, "Debug")
else:
self.build_temp = os.path.join(self.build_temp, "Release")
self.ext_suffix = sysconfig.get_config_var("EXT_SUFFIX")
build_ext_cmd = Distribution().get_command_obj('build_ext')
if self.ext_suffix is None:
self.ext_suffix = ".so"
build_ext_cmd.initialize_options()
build_ext_cmd.setup_shlib_compiler()
self.build_ext_cmd = build_ext_cmd
self.root = "klayout"
def libname_of(self, mod):
def add_extension(self, ext):
self.build_ext_cmd.ext_map[ext.name] = ext
def libname_of(self, mod, is_lib=None):
"""
Returns the library name for a given module
The library name is usually decorated (i.e. "tl" -> "tl.cpython-35m-x86_64-linux-gnu.so").
This code was extracted from the source in setuptools.command.build_ext.build_ext
"""
ext_suffix = self.ext_suffix
if platform.system() == "Darwin" and '_dbpi' in mod:
ext_suffix = ext_suffix.replace('.so', '.dylib')
return mod + ext_suffix
libtype = setuptools.command.build_ext.libtype
full_mod = self.root + '.' + mod
if is_lib is True:
# Here we are guessing it is a library and that the filename
# is to be computed by shlib_compiler.
# See source code of setuptools.command.build_ext.build_ext.get_ext_filename
filename = self.build_ext_cmd.get_ext_filename(full_mod)
fn, ext = os.path.splitext(filename)
ext_path = self.build_ext_cmd.shlib_compiler.library_filename(fn, libtype)
else:
# This assumes that the Extension/Library object was added to the
# ext_map dictionary via config.add_extension.
assert full_mod in self.build_ext_cmd.ext_map
ext_path = self.build_ext_cmd.get_ext_filename(full_mod)
ext_filename = os.path.basename(ext_path)
def path_of(self, mod):
# Exception for database plugins, which will always be dylib.
if platform.system() == "Darwin" and '_dbpi' in mod:
ext_filename = ext_filename.replace('.so', '.dylib')
return ext_filename
def path_of(self, mod, mod_src_path):
"""
Returns the build path of the library for a given module
"""
return os.path.join(self.build_platlib, self.root, self.libname_of(mod))
if platform.system() == "Windows":
# On Windows, the library to link is the import library
(dll_name, dll_ext) = os.path.splitext(self.libname_of(mod))
return os.path.join(self.build_temp, mod_src_path, dll_name + ".lib")
else:
return os.path.join(self.build_platlib, self.root, self.libname_of(mod))
def compile_args(self, mod):
"""
Gets additional compiler arguments
"""
if platform.system() == "Windows":
return []
bits = os.getenv("KLAYOUT_BITS")
if bits:
return ["\"-I" + os.path.join(bits, "zlib", "include") + "\"",
"\"-I" + os.path.join(bits, "ptw", "include") + "\"",
"\"-I" + os.path.join(bits, "expat", "include") + "\"",
"\"-I" + os.path.join(bits, "curl", "include") + "\""]
else:
return []
elif platform.system() == "Darwin":
return []
else:
@ -174,18 +262,37 @@ class Config(object):
"-std=c++11", # because we use unordered_map/unordered_set
]
def libraries(self, mod):
"""
Gets the libraries to add
"""
if platform.system() == "Windows":
if mod == "_tl":
return [ "libcurl", "expat", "pthreadVCE2", "zlib", "wsock32" ]
else:
if mod == "_tl":
return ['curl', 'expat']
return []
def link_args(self, mod):
"""
Gets additional linker arguments
"""
if platform.system() == "Windows":
return []
args = ["/DLL"]
bits = os.getenv("KLAYOUT_BITS")
if bits:
args += ["\"/LIBPATH:" + os.path.join(bits, "zlib", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "ptw", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "expat", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "curl", "libraries") + "\""]
return args
elif platform.system() == "Darwin":
# For the dependency modules, make sure we produce a dylib.
# We can only link against such, but the bundles produced otherwise.
args = []
if mod[0] == "_":
args += ["-Wl,-dylib", '-Wl,-install_name,@rpath/%s' % self.libname_of(mod)]
args += ["-Wl,-dylib", '-Wl,-install_name,@rpath/%s' % self.libname_of(mod, is_lib=True)]
args += ['-Wl,-rpath,@loader_path/']
return args
else:
@ -195,7 +302,7 @@ class Config(object):
# will look for the path-qualified library. But that's the
# build path and the loader will fail.
args = []
args += ['-Wl,-soname,' + self.libname_of(mod)]
args += ['-Wl,-soname,' + self.libname_of(mod, is_lib=True)]
if '_dbpi' not in mod:
loader_path = '$ORIGIN'
else:
@ -213,7 +320,7 @@ class Config(object):
"""
Gets the version string
"""
return "0.26.0.dev5"
return "0.26.0.dev7"
config = Config()
@ -222,7 +329,6 @@ config = Config()
# _tl dependency library
_tl_path = os.path.join("src", "tl", "tl")
_tl_sources = set(glob.glob(os.path.join(_tl_path, "*.cc")))
# Exclude sources which are compatible with Qt only
@ -233,41 +339,47 @@ _tl_sources.discard(os.path.join(_tl_path, "tlHttpStreamNoQt.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlFileSystemWatcher.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlDeferredExecutionQt.cc"))
_tl = Extension(config.root + '._tl',
define_macros=config.macros() + [('MAKE_TL_LIBRARY', 1)],
language='c++',
libraries=['curl', 'expat'],
extra_link_args=config.link_args('_tl'),
extra_compile_args=config.compile_args('_tl'),
sources=list(_tl_sources))
_tl = Library(config.root + '._tl',
define_macros=config.macros() + [('MAKE_TL_LIBRARY', 1)],
language='c++',
libraries=config.libraries('_tl'),
extra_link_args=config.link_args('_tl'),
extra_compile_args=config.compile_args('_tl'),
sources=list(_tl_sources))
config.add_extension(_tl)
# ------------------------------------------------------------------
# _gsi dependency library
_gsi_sources = glob.glob("src/gsi/gsi/*.cc")
_gsi_path = os.path.join("src", "gsi", "gsi")
_gsi_sources = set(glob.glob(os.path.join(_gsi_path, "*.cc")))
_gsi = Extension(config.root + '._gsi',
define_macros=config.macros() + [('MAKE_GSI_LIBRARY', 1)],
include_dirs=['src/tl/tl'],
extra_objects=[config.path_of('_tl')],
language='c++',
extra_link_args=config.link_args('_gsi'),
extra_compile_args=config.compile_args('_gsi'),
sources=_gsi_sources)
_gsi = Library(config.root + '._gsi',
define_macros=config.macros() + [('MAKE_GSI_LIBRARY', 1)],
include_dirs=[_tl_path],
extra_objects=[config.path_of('_tl', _tl_path)],
language='c++',
extra_link_args=config.link_args('_gsi'),
extra_compile_args=config.compile_args('_gsi'),
sources=list(_gsi_sources))
config.add_extension(_gsi)
# ------------------------------------------------------------------
# _pya dependency library
_pya_sources = glob.glob("src/pya/pya/*.cc")
_pya_path = os.path.join("src", "pya", "pya")
_pya_sources = set(glob.glob(os.path.join(_pya_path, "*.cc")))
_pya = Extension(config.root + '._pya',
define_macros=config.macros() + [('MAKE_PYA_LIBRARY', 1)],
include_dirs=['src/tl/tl', 'src/gsi/gsi'],
extra_objects=[config.path_of('_tl'), config.path_of('_gsi')],
language='c++',
extra_link_args=config.link_args('_pya'),
extra_compile_args=config.compile_args('_pya'),
sources=_pya_sources)
_pya = Library(config.root + '._pya',
define_macros=config.macros() + [('MAKE_PYA_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
extra_link_args=config.link_args('_pya'),
extra_compile_args=config.compile_args('_pya'),
sources=list(_pya_sources))
config.add_extension(_pya)
# ------------------------------------------------------------------
# _db dependency library
@ -280,93 +392,98 @@ _db_sources = set(glob.glob(os.path.join(_db_path, "*.cc")))
# not exist. So we need an error-free discard method instead of list's remove.
_db_sources.discard(os.path.join(_db_path, "fonts.cc"))
_db = Extension(config.root + '._db',
define_macros=config.macros() + [('MAKE_DB_LIBRARY', 1)],
include_dirs=['src/tl/tl', 'src/gsi/gsi', 'src/db/db'],
extra_objects=[config.path_of('_tl'), config.path_of('_gsi')],
language='c++',
extra_link_args=config.link_args('_db'),
extra_compile_args=config.compile_args('_db'),
sources=list(_db_sources))
_db = Library(config.root + '._db',
define_macros=config.macros() + [('MAKE_DB_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path, _db_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
extra_link_args=config.link_args('_db'),
extra_compile_args=config.compile_args('_db'),
sources=list(_db_sources))
config.add_extension(_db)
# ------------------------------------------------------------------
# _rdb dependency library
_rdb_sources = glob.glob("src/rdb/rdb/*.cc")
_rdb_path = os.path.join("src", "rdb", "rdb")
_rdb_sources = set(glob.glob(os.path.join(_rdb_path, "*.cc")))
_rdb = Extension(config.root + '._rdb',
define_macros=config.macros() + [('MAKE_RDB_LIBRARY', 1)],
include_dirs=['src/db/db', 'src/tl/tl', 'src/gsi/gsi'],
extra_objects=[config.path_of('_tl'), config.path_of(
'_gsi'), config.path_of('_db')],
language='c++',
extra_link_args=config.link_args('_rdb'),
extra_compile_args=config.compile_args('_rdb'),
sources=_rdb_sources)
_rdb = Library(config.root + '._rdb',
define_macros=config.macros() + [('MAKE_RDB_LIBRARY', 1)],
include_dirs=[_db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
extra_link_args=config.link_args('_rdb'),
extra_compile_args=config.compile_args('_rdb'),
sources=list(_rdb_sources))
config.add_extension(_rdb)
# ------------------------------------------------------------------
# dependency libraries from db_plugins
db_plugins = []
for pi in glob.glob("src/plugins/*/db_plugin") + glob.glob("src/plugins/*/*/db_plugin"):
dbpi_dirs = glob.glob(os.path.join("src", "plugins", "*", "db_plugin"))
dbpi_dirs += glob.glob(os.path.join("src", "plugins", "*", "*", "db_plugin"))
for pi in dbpi_dirs:
mod_name = "_" + os.path.split(os.path.split(pi)[-2])[-1] + "_dbpi"
pi_sources = glob.glob(pi + "/*.cc")
pi_sources = glob.glob(os.path.join(pi, "*.cc"))
pi_ext = Extension(config.root + '.db_plugins.' + mod_name,
define_macros=config.macros() + [('MAKE_DB_PLUGIN_LIBRARY', 1)],
include_dirs=['src/plugins/common',
'src/db/db', 'src/tl/tl', 'src/gsi/gsi'],
extra_objects=[config.path_of('_tl'), config.path_of(
'_gsi'), config.path_of('_db')],
language='c++',
extra_link_args=config.link_args(mod_name),
extra_compile_args=config.compile_args(mod_name),
sources=pi_sources)
pi_ext = Library(config.root + '.db_plugins.' + mod_name,
define_macros=config.macros() + [('MAKE_DB_PLUGIN_LIBRARY', 1)],
include_dirs=[os.path.join("src", "plugins", "common"),
_db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
extra_link_args=config.link_args(mod_name),
extra_compile_args=config.compile_args(mod_name),
sources=pi_sources)
db_plugins.append(pi_ext)
config.add_extension(pi_ext)
# ------------------------------------------------------------------
# tl extension library
tl_sources = glob.glob("src/pymod/tl/*.cc")
tl_path = os.path.join("src", "pymod", "tl")
tl_sources = set(glob.glob(os.path.join(tl_path, "*.cc")))
tl = Extension(config.root + '.tlcore',
define_macros=config.macros(),
include_dirs=['src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'],
extra_objects=[config.path_of('_tl'), config.path_of(
'_gsi'), config.path_of('_pya')],
include_dirs=[_tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('tlcore'),
sources=tl_sources)
sources=list(tl_sources))
# ------------------------------------------------------------------
# db extension library
db_sources = glob.glob("src/pymod/db/*.cc")
db_path = os.path.join("src", "pymod", "db")
db_sources = set(glob.glob(os.path.join(db_path, "*.cc")))
db = Extension(config.root + '.dbcore',
define_macros=config.macros(),
include_dirs=['src/db/db', 'src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'],
extra_objects=[config.path_of('_db'), config.path_of(
'_tl'), config.path_of('_gsi'), config.path_of('_pya')],
include_dirs=[_db_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_db', _db_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('dbcore'),
sources=db_sources)
sources=list(db_sources))
# ------------------------------------------------------------------
# rdb extension library
rdb_sources = glob.glob("src/pymod/rdb/*.cc")
rdb_path = os.path.join("src", "pymod", "rdb")
rdb_sources = set(glob.glob(os.path.join(rdb_path, "*.cc")))
rdb = Extension(config.root + '.rdbcore',
define_macros=config.macros(),
include_dirs=['src/rdb/rdb', 'src/db/db',
'src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'],
extra_objects=[config.path_of('_rdb'), config.path_of(
'_gsi'), config.path_of('_pya')],
include_dirs=[_rdb_path, _db_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('rdbcore'),
sources=rdb_sources)
sources=list(rdb_sources))
# ------------------------------------------------------------------
# Core setup function

View File

@ -386,13 +386,18 @@ render_scanline_cross (const uint32_t *dp, unsigned int ds, const lay::Bitmap *p
}
}
static void create_precursor_bitmaps (const std::vector<lay::ViewOp> &view_ops_in, const std::vector<lay::Bitmap *> &pbitmaps_in, const lay::LineStyles &ls, unsigned int width, unsigned int height, std::map<unsigned int, lay::Bitmap> &precursors, QMutex *mutex)
static void create_precursor_bitmaps (const std::vector<lay::ViewOp> &view_ops_in, const std::vector <unsigned int> &vo_map, const std::vector<lay::Bitmap *> &pbitmaps_in, const std::vector<unsigned int> &bm_map, const lay::LineStyles &ls, unsigned int width, unsigned int height, std::map<unsigned int, lay::Bitmap> &precursors, QMutex *mutex)
{
tl_assert (bm_map.size () == vo_map.size ());
// Styled lines with width > 1 are not rendered directly, but through an intermediate step.
// We prepare the necessary precursor bitmaps now
for (unsigned int i = 0; i < view_ops_in.size (); ++i) {
for (unsigned int i = 0; i < vo_map.size (); ++i) {
const ViewOp &op = view_ops_in [i];
unsigned int vo_index = vo_map [i];
unsigned int bm_index = bm_map [i];
const ViewOp &op = view_ops_in [vo_index];
if (op.width () > 1 && ls.style (op.line_style_index ()).width () > 0) {
// lock bitmaps against change by the redraw thread
@ -400,12 +405,12 @@ static void create_precursor_bitmaps (const std::vector<lay::ViewOp> &view_ops_i
mutex->lock ();
}
lay::Bitmap &bp = precursors.insert (std::make_pair (i, lay::Bitmap (width, height, 1.0))).first->second;
lay::Bitmap &bp = precursors.insert (std::make_pair (bm_index, lay::Bitmap (width, height, 1.0))).first->second;
LineStyleInfo ls_info = ls.style (op.line_style_index ());
ls_info.scale_pattern (op.width ());
for (unsigned int y = 0; y < height; y++) {
render_scanline_std_edge (ls_info.pattern (), ls_info.pattern_stride (), pbitmaps_in [i], y, width, height, bp.scanline (y));
render_scanline_std_edge (ls_info.pattern (), ls_info.pattern_stride (), pbitmaps_in [bm_index], y, width, height, bp.scanline (y));
}
if (mutex) {
@ -418,7 +423,7 @@ static void create_precursor_bitmaps (const std::vector<lay::ViewOp> &view_ops_i
}
static void
bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
@ -427,29 +432,33 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
bool transparent,
QMutex *mutex)
{
unsigned int n_in = (unsigned int) view_ops_in.size ();
std::vector<unsigned int> bm_map;
std::vector<unsigned int> vo_map;
vo_map.reserve (n_in);
for (unsigned int i = 0; i < n_in; ++i) {
vo_map.push_back (i);
}
vo_map.reserve (view_ops_in.size ());
bm_map.reserve (view_ops_in.size ());
unsigned int n_in = 0;
if (! use_bitmap_index) {
bm_map = vo_map;
} else {
bm_map.reserve (n_in);
for (unsigned int i = 0; i < n_in; ++i) {
bm_map.push_back (view_ops_in [i].bitmap_index () < 0 ? i : view_ops_in [i].bitmap_index ());
// drop invisible and empty bitmaps, build bitmap mask
for (unsigned int i = 0; i < view_ops_in.size (); ++i) {
const lay::ViewOp &vop = view_ops_in [i];
unsigned int bi = (use_bitmap_index && vop.bitmap_index () >= 0) ? (unsigned int) vop.bitmap_index () : i;
const lay::Bitmap *pb = bi < pbitmaps_in.size () ? pbitmaps_in [bi] : 0;
if ((vop.ormask () | ~vop.andmask ()) != 0 && pb && ! pb->empty ()) {
vo_map.push_back (i);
bm_map.push_back (bi);
++n_in;
}
}
// Styled lines with width > 1 are not rendered directly, but through an intermediate step.
// We prepare the necessary precursor bitmaps now
std::map<unsigned int, lay::Bitmap> precursors;
create_precursor_bitmaps (view_ops_in, pbitmaps_in, ls, width, height, precursors, mutex);
create_precursor_bitmaps (view_ops_in, vo_map, pbitmaps_in, bm_map, ls, width, height, precursors, mutex);
std::vector<lay::ViewOp> view_ops;
std::vector<const lay::Bitmap *> pbitmaps;
@ -489,12 +498,13 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
unsigned int w = vop.width ();
const lay::Bitmap *pb = 0;
unsigned int bm_index = bm_map[i];
if (bm_map [i] < pbitmaps_in.size ()) {
if (w > 1 && ls.style (vop.line_style_index ()).width () > 0) {
tl_assert (precursors.find (i) != precursors.end ());
pb = &precursors [i];
tl_assert (precursors.find (bm_index) != precursors.end ());
pb = &precursors [bm_index];
} else {
pb = pbitmaps_in [bm_map[i]];
pb = pbitmaps_in [bm_index];
}
}
@ -660,29 +670,33 @@ bitmaps_to_image_mono (const std::vector<lay::ViewOp> &view_ops_in,
bool use_bitmap_index,
QMutex *mutex)
{
unsigned int n_in = (unsigned int) view_ops_in.size ();
std::vector<unsigned int> bm_map;
std::vector<unsigned int> vo_map;
vo_map.reserve (n_in);
for (unsigned int i = 0; i < n_in; ++i) {
vo_map.push_back (i);
}
vo_map.reserve (view_ops_in.size ());
bm_map.reserve (view_ops_in.size ());
unsigned int n_in = 0;
if (! use_bitmap_index) {
bm_map = vo_map;
} else {
bm_map.reserve (n_in);
for (unsigned int i = 0; i < n_in; ++i) {
bm_map.push_back (view_ops_in [i].bitmap_index () < 0 ? i : view_ops_in [i].bitmap_index ());
// drop invisible and empty bitmaps, build bitmap mask
for (unsigned int i = 0; i < view_ops_in.size (); ++i) {
const lay::ViewOp &vop = view_ops_in [i];
unsigned int bi = (use_bitmap_index && vop.bitmap_index () >= 0) ? (unsigned int) vop.bitmap_index () : i;
const lay::Bitmap *pb = bi < pbitmaps_in.size () ? pbitmaps_in [bi] : 0;
if ((vop.ormask () | ~vop.andmask ()) != 0 && pb && ! pb->empty ()) {
vo_map.push_back (i);
bm_map.push_back (bi);
++n_in;
}
}
// Styled lines with width > 1 are not rendered directly, but through an intermediate step.
// We prepare the necessary precursor bitmaps now
std::map<unsigned int, lay::Bitmap> precursors;
create_precursor_bitmaps (view_ops_in, pbitmaps_in, ls, width, height, precursors, mutex);
create_precursor_bitmaps (view_ops_in, vo_map, pbitmaps_in, bm_map, ls, width, height, precursors, mutex);
std::vector<lay::ViewOp> view_ops;
std::vector<const lay::Bitmap *> pbitmaps;
@ -722,16 +736,17 @@ bitmaps_to_image_mono (const std::vector<lay::ViewOp> &view_ops_in,
unsigned int w = vop.width ();
const lay::Bitmap *pb = 0;
unsigned int bm_index = bm_map[i];
if (bm_map [i] < pbitmaps_in.size ()) {
if (w > 1 && ls.style (vop.line_style_index ()).width () > 0) {
tl_assert (precursors.find (i) != precursors.end ());
pb = &precursors [i];
tl_assert (precursors.find (bm_index) != precursors.end ());
pb = &precursors [bm_index];
} else {
pb = pbitmaps_in [bm_map[i]];
pb = pbitmaps_in [bm_index];
}
}
if (pb != 0
if (pb != 0
&& w > 0
&& ((pb->first_scanline () < y + slice && pb->last_scanline () > y) || w > 1)
&& (vop.ormask () | ~vop.andmask ()) != 0) {

View File

@ -74,9 +74,10 @@ struct RedrawLayerInfo
/**
* @brief The layer index
*
* The logical layer to draw. If this member is <0 and the cellview_index is <0, it is an invalid layer,
* which is ignored. If the cellview_index is >=0, it denotes a "cell frame" pseudo
* layer. It is set by the constructor.
* The logical layer to draw. The layer index can be <0 which indicates a
* layer with not layout source (cell_frame may be true to indicate a
* pseudo layer then).
* This attribute is set by the constructor.
*/
int layer_index;
@ -115,6 +116,14 @@ struct RedrawLayerInfo
* This member is set by the constructor.
*/
bool inverse_prop_sel;
/**
* @brief Returns true, if the layer needs to be drawn
*/
bool needs_drawing () const
{
return visible && enabled && (cell_frame || layer_index >= 0) && cellview_index >= 0;
}
};
}

View File

@ -307,7 +307,7 @@ RedrawThread::do_start (bool clear, const db::Vector *shift_vector, const std::v
}
for (int i = 0; i < m_nlayers; ++i) {
if (m_layers [i].visible && m_layers [i].enabled) {
if (m_layers [i].needs_drawing ()) {
schedule (new RedrawThreadTask (i));
}
}

View File

@ -1232,20 +1232,26 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
// do not draw, if there is nothing to draw
if (mp_layout->cells () <= ci || vp.empty ()) {
if (mp_layout->cells () <= ci || vp.empty () || mp_layout->cell (ci).bbox (m_layer).empty ()) {
return;
}
if (cell_var_cached (ci, trans)) {
return;
}
std::auto_ptr<lay::Bitmap> opt_bitmap;
lay::Bitmap *vertex_bitmap = dynamic_cast<lay::Bitmap *> (vertex);
if (m_text_lazy_rendering && vertex_bitmap) {
opt_bitmap.reset (new lay::Bitmap (vertex_bitmap->width (), vertex_bitmap->height (), vertex_bitmap->resolution ()));
}
for (std::vector<db::Box>::const_iterator b = vp.begin (); b != vp.end (); ++b) {
draw_text_layer (drawing_context, ci, trans, *b, level, fill, frame, vertex, text);
draw_text_layer (drawing_context, ci, trans, *b, level, fill, frame, vertex, text, opt_bitmap.get ());
}
}
void
RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, CanvasPlane *fill, CanvasPlane *frame, CanvasPlane *vertex, CanvasPlane *text)
RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, CanvasPlane *fill, CanvasPlane *frame, CanvasPlane *vertex, CanvasPlane *text, lay::Bitmap *opt_bitmap)
{
test_snapshot (0);
@ -1283,6 +1289,9 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
// paint the simplified box
if (anything) {
r.draw (trans * bbox, 0, frame, vertex, 0);
if (opt_bitmap) {
r.draw (trans * bbox, 0, 0, opt_bitmap, 0);
}
}
// do not dive further into hierarchy
@ -1318,6 +1327,9 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
test_snapshot (0);
r.draw (*shape, trans, fill, frame, vertex, text);
if (opt_bitmap) {
r.draw (*shape, trans, 0, 0, opt_bitmap, 0);
}
++shape;
--ntexts;
@ -1355,8 +1367,6 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
// dive down into the hierarchy ..
if (need_to_dive) {
const lay::Bitmap *vertex_bitmap = dynamic_cast<const lay::Bitmap *> (vertex);
// create a set of boxes to look into
std::vector<db::Box> vv = search_regions (cell_bbox, vp, level);
@ -1377,7 +1387,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
bool skip = false;
if (m_text_lazy_rendering && qid != current_quad_id) {
current_quad_id = qid;
skip = vertex_bitmap && skip_quad (inst.quad_box () & bbox, vertex_bitmap, trans);
skip = opt_bitmap && skip_quad (inst.quad_box () & bbox, opt_bitmap, trans);
}
if (skip) {
@ -1448,7 +1458,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
db::ICplxTrans t (cell_inst.complex_trans (*p));
db::Box new_vp = db::Box (t.inverted () * *v);
draw_text_layer (drawing_context, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text);
draw_text_layer (drawing_context, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text, opt_bitmap);
}
@ -1648,7 +1658,7 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
// skip this quad if we have drawn something here already
size_t qid = inst.quad_id ();
bool skip = false;
if (m_text_lazy_rendering && qid != current_quad_id) {
if (qid != current_quad_id) {
current_quad_id = qid;
skip = skip_quad (inst.quad_box () & bbox, vertex_bitmap, trans);
}

View File

@ -180,7 +180,7 @@ private:
void draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
void draw_layer_wo_cache (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vv, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, Bitmap *opt_bitmap);
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);