Skip to content
Merged

Wip #2389

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b2afb55
Convenience constructor for Layout from a cell (hierarchical copy)
Jul 11, 2026
1cd9cbc
Enhancement: using PCell parameter 'name' won't break PCell's cell_na…
Jul 11, 2026
8fa97d7
Small issue fixed: when images are selected and images are turned off…
Jul 11, 2026
8eaf563
Improved the image pixel value display: favors selected image, faster
Jul 11, 2026
abe9479
Bugfix: removing a pin from a Circuit does not crash if the pin was n…
Jul 11, 2026
b21f253
Bugfix: entering '16:17' (or similar) into 'new layout' layer list ma…
Jul 17, 2026
c8d307c
Marek's bug: move interactive/copy interactive did not do anything wh…
Jul 17, 2026
edad8f5
Bugfix: update layer names in layer list (when used in secondary fash…
Jul 17, 2026
8b867bb
Fixing tests after layer names get loaded properly
Jul 17, 2026
b51187b
Merge branch 'master' into wip
Jul 19, 2026
a75f1d7
WIP: trying performance improvement of two-layer DRC checks (do merge…
Jul 19, 2026
484ab91
WIP: deep mode implementation of enhanced 2-layer check, tests
Jul 19, 2026
604db5a
Updating test data
Jul 19, 2026
b2b5df3
Some refactoring
Jul 19, 2026
5060d0f
Refactoring
Jul 19, 2026
93c43d0
Bugfix: Region#edges wasn't working properly in deep mode with proper…
Jul 19, 2026
b004cc2
Fixing name update - layer index needs to be valid
Jul 20, 2026
cb07b85
Merge branch 'xxx' into wip
Jul 20, 2026
116602f
Updating test data
Jul 20, 2026
a50319f
Updating test data
Jul 20, 2026
2d5d643
Preparing 0.30.10
Jul 20, 2026
5055d4f
Merge remote-tracking branch 'origin/master' into wip
Jul 20, 2026
5ae17c1
Updating Python stubs
Jul 20, 2026
a82f428
WIP: hardening DeepRegion against min_coherence toggles (IHP PDK opti…
Jul 21, 2026
7ed80e6
Bugfix: inserting a Shapes container into another one did not always …
Jul 22, 2026
51f39d7
WIP: hardening FlatRegion against min_coherence toggles (IHP PDK opti…
Jul 22, 2026
9382e25
Adding support for min_coherence toggling in OriginalLayerRegion
Jul 22, 2026
1e02ffe
More consistently inherit the min_coherence flag during flat Region o…
Jul 22, 2026
189ba72
Performance enhancements for two-layer DRC checks
Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
0.30.10 (2026-07-22):
* Bugfix: %GITHUB%/issues/2384 Deep DRC failure with scaled instances
* Enhancement: %GITHUB%/issues/2391 Grid Features: switching between coarser and finier grids with keyboard shortcut
* Bugfix: %GITHUB%/issues/2392 Wrong PCell instantiations when switching technologies
* Bugfix: %GITHUB%/issues/2396 Python objects did nott support weak refs
* Bugfix: Region#edges was not working properly when used on Regions with properties
enabled. Now, with properties enabled, the regions are consistently formed from polygons with
identical properties before generating the edges.
* Enhancement: DRC two-layer checks now do not necessarily require merging for the
first input. This in general speeds up the operation in certain cases.
As a side effect, the error markers may be split according to partial input
polygons, as is the case for plain "space" check already.
* Enhancement: Use multiple drawing workers for image_with_options rendering
* Bugfix: Update layer names in layer list (when used in addition to layer/datatypes) on reload
As a side effect, the layer properties nodes will update the "real source" according to
the actual name if the name is used in addition to layer/datatypes. Also, the layout readers
will update layer names in the layer properties of the Layout object.
* Bugfix: Marek's bug: move interactive/copy interactive did not do anything when the mouse wasn't moved
* Bugfix: Entering '16:17' (or other nonsense) into 'new layout' layer list made KLayout hang
* Bugfix: API: removing a pin from a Circuit does not crash if the pin was not disconnected before.
Now it's disconnected automatically
* Enhancement: Improved the image pixel value display: favors selected image, and follows mouse instantly
* Bugfix: When images are selected and images are turned off, the selection no longer persists
* Bugfix: Using PCell parameter name 'name' won't break PCell's cell_name_impl default implementation
* Enhancement: New API functions
* Create a Layout as a deep copy of a cell (Layout#new)
* PixelBuffer#to_bytes and PixelBuffer#from_bytes for zero-overhead RGBA pixel access

0.30.9 (2026-05-25):
* Bugfix: %GITHUB%/issues/2331 Screen size error (Assertion tlPixelBuffer.cc:260 n < m_height was not true)
* Enhancement: %GITHUB%/issues/2335 Editor Options (F3) behaviour has changed
Expand Down
7 changes: 7 additions & 0 deletions Changelog.Debian
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
klayout (0.30.10-1) unstable; urgency=low

* New features and bugfixes
- See changelog

-- Matthias Köfferlein <matthias@koefferlein.de> Mon, 20 Jul 2026 23:20:04 +0200

klayout (0.30.9-1) unstable; urgency=low

* New features and bugfixes
Expand Down
7 changes: 6 additions & 1 deletion src/db/db/built-in-macros/pcell_declaration_helper.lym
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ module RBA
alias_method :_layout_base, :layout
end

# makes PCellDeclaration's "name" method available
if ! self.method_defined?(:_name_base)
alias_method :_name_base, :name
end

# import the Type... constants from PCellParameterDeclaration
PCellParameterDeclaration.constants.each do |c|
if !const_defined?(c)
Expand Down Expand Up @@ -595,7 +600,7 @@ module RBA

# default implementation
def cell_name_impl
self.name
_name_base()
end

# default implementation
Expand Down
83 changes: 49 additions & 34 deletions src/db/db/dbAsIfFlatRegion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -631,14 +631,14 @@ namespace {
class OutputPairHolder
{
public:
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics)
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics, bool min_coherence)
{
if (output_mode == None) {
return;
}

if (output_mode == Positive || output_mode == Negative || output_mode == PositiveAndNegative) {
m_positive.reset (new FlatRegion (merged_semantics));
m_positive.reset (new FlatRegion (merged_semantics, 0.0, 0, min_coherence));
m_results.push_back (& m_positive->raw_polygons ());
} else {
m_results.push_back ((db::Shapes *) 0);
Expand Down Expand Up @@ -667,7 +667,7 @@ class OutputPairHolder
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
{
OutputPairHolder oph (output_mode, merged_semantics ());
OutputPairHolder oph (output_mode, merged_semantics (), min_coherence ());

if (output_mode == None) {
return oph.region_pair ();
Expand Down Expand Up @@ -717,7 +717,7 @@ AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode o
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());

if (output_mode == None) {
return oph.region_pair ();
Expand Down Expand Up @@ -756,7 +756,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
std::vector<generic_shape_iterator<db::Edge> > others;
others.push_back (counting ? other.begin_merged () : other.begin ());

std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics (), 0.0, 0, min_coherence ()));
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());

Expand All @@ -768,7 +768,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());

if (output_mode == None) {
return oph.region_pair ();
Expand Down Expand Up @@ -814,7 +814,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOut
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());

if (output_mode == None) {
return oph.region_pair ();
Expand Down Expand Up @@ -941,7 +941,7 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back (other.begin_merged ());

std::unique_ptr<FlatRegion> output (new FlatRegion (other.merged_semantics () || other.is_merged ()));
std::unique_ptr<FlatRegion> output (new FlatRegion (other.merged_semantics () || other.is_merged (), 0.0, 0, min_coherence ()));
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());

Expand Down Expand Up @@ -1106,7 +1106,7 @@ AsIfFlatRegion::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db
throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values")));
}

std::unique_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics ()));
std::unique_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics (), 0.0, 0, min_coherence ()));

gx = std::max (db::Coord (1), gx);
gy = std::max (db::Coord (1), gy);
Expand Down Expand Up @@ -1184,13 +1184,7 @@ AsIfFlatRegion::width_check (db::Coord d, const RegionCheckOptions &options) con
EdgePairsDelegate *
AsIfFlatRegion::space_or_isolated_check (db::Coord d, const RegionCheckOptions &options, bool isolated) const
{
if (options.opposite_filter != NoOppositeFilter || options.rect_filter != NoRectFilter || options.shielded) {
// NOTE: we have to use the "foreign" scheme with a filter because only this scheme
// guarantees that all subject shapes are visited.
return run_check (db::SpaceRelation, isolated, foreign_regionptr (), d, options);
} else {
return run_check (db::SpaceRelation, isolated, subject_regionptr (), d, options);
}
return run_check (db::SpaceRelation, isolated, 0, d, options);
}

EdgePairsDelegate *
Expand Down Expand Up @@ -1239,28 +1233,43 @@ EdgePairsDelegate *
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
{
// force different polygons in the different properties case to skip intra-polygon checks
if (pc_always_different (options.prop_constraint)) {
if (! other && pc_always_different (options.prop_constraint)) {
different_polygons = true;
}

bool needs_merged_primary = different_polygons || options.needs_merged ();
bool needs_merged_primary = (! other && different_polygons) || options.needs_merged ();
bool primary_is_merged = is_merged ();
db::RegionIterator polygons;

db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
if (! merged_semantics ()) {
primary_is_merged = true; // means: don't merge again
needs_merged_primary = false;
polygons = begin ();
} else if (! needs_merged_primary) {
// The implementation may run faster if the primary is not merged
primary_is_merged = false;
polygons = begin_unmerged ();
} else {
primary_is_merged = true;
polygons = begin_merged ();
}

EdgeRelationFilter check (rel, d, options);

std::vector<db::RegionIterator> others;
std::vector<bool> foreign;
bool has_other = false;
bool other_is_merged = true;

if (other == subject_regionptr () || other == foreign_regionptr ()) {
foreign.push_back (other == foreign_regionptr ());
if (! other) {

foreign.push_back (true);
others.push_back (polygons);
other_is_merged = primary_is_merged;

} else {

foreign.push_back (false);

if (! other->merged_semantics ()) {
others.push_back (other->begin ());
other_is_merged = true;
Expand All @@ -1272,7 +1281,13 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
others.push_back (other->begin ());
other_is_merged = other->is_merged ();
}
has_other = true;

// adds another intruder section to implement subject merging ("primary_intruders")
if (! primary_is_merged) {
foreign.push_back (true);
others.push_back (polygons);
}

}

std::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
Expand All @@ -1282,7 +1297,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,

if (pc_skip (options.prop_constraint)) {

db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, other != 0, other_is_merged, options);

db::local_processor<db::Polygon, db::Polygon, db::EdgePair> proc;
proc.set_base_verbosity (base_verbosity ());
Expand All @@ -1293,7 +1308,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,

} else {

db::check_local_operation_with_properties<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
db::check_local_operation_with_properties<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, other != 0, other_is_merged, options);

db::local_processor<db::PolygonWithProperties, db::PolygonWithProperties, db::EdgePairWithProperties> proc;
proc.set_base_verbosity (base_verbosity ());
Expand Down Expand Up @@ -1334,7 +1349,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
}

RegionDelegate *
AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
AsIfFlatRegion::merged (bool min_coh, unsigned int min_wc, bool join_properties_on_merge) const
{
if (empty ()) {

Expand All @@ -1351,8 +1366,8 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_prope

} else {

std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc, join_properties_on_merge);
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0, 0, min_coh));
merge_polygons_to (new_region->raw_polygons (), min_coh, min_wc, join_properties_on_merge);

return new_region.release ();

Expand Down Expand Up @@ -1695,7 +1710,7 @@ AsIfFlatRegion::and_or_not_with (bool is_and, const Region &other, PropertyConst
ep.insert (*p, n);
}

std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
db::BooleanOp op (is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
Expand Down Expand Up @@ -1772,12 +1787,12 @@ AsIfFlatRegion::andnot_with (const Region &other, PropertyConstraint property_co
ep.insert (*p, n);
}

std::unique_ptr<FlatRegion> new_region1 (new FlatRegion (true));
std::unique_ptr<FlatRegion> new_region1 (new FlatRegion (true, 0.0, 0, min_coherence ()));
db::BooleanOp op1 (db::BooleanOp::And);
db::ShapeGenerator pc1 (new_region1->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg1 (pc1, false /*don't resolve holes*/, min_coherence ());

std::unique_ptr<FlatRegion> new_region2 (new FlatRegion (true));
std::unique_ptr<FlatRegion> new_region2 (new FlatRegion (true, 0.0, 0, min_coherence ()));
db::BooleanOp op2 (db::BooleanOp::ANotB);
db::ShapeGenerator pc2 (new_region2->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg2 (pc2, false /*don't resolve holes*/, min_coherence ());
Expand Down Expand Up @@ -1860,7 +1875,7 @@ AsIfFlatRegion::xor_with (const Region &other, PropertyConstraint prop_constrain
ep.insert (*p, n);
}

std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
db::BooleanOp op (db::BooleanOp::Xor);
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
Expand Down Expand Up @@ -1916,7 +1931,7 @@ AsIfFlatRegion::or_with (const Region &other, PropertyConstraint /*prop_constrai
ep.insert (*p, n);
}

std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
db::BooleanOp op (db::BooleanOp::Or);
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
Expand Down
1 change: 1 addition & 0 deletions src/db/db/dbCircuit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ Pin &Circuit::add_pin (const std::string &name)
void Circuit::remove_pin (size_t id)
{
if (id < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [id])) {
connect_pin (id, 0);
m_pins.erase (m_pin_by_id [id]);
m_pin_by_id [id] = pin_list::iterator ();
}
Expand Down
53 changes: 40 additions & 13 deletions src/db/db/dbCommonReader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,31 +541,58 @@ CommonReaderBase::open_dl_uncached (db::Layout &layout, const LDPair &dl)
}

unsigned int nl = layout.insert_layer (lp);

// change OASIS layer name if a layer already exists by layer/datatype, but has a different name
if (! lp.name.empty () && layout.get_properties (nl).name != lp.name) {
layout.set_properties (nl, lp);
}

m_layer_map_out.map (dl, nl, lp);

m_layers_created.insert (nl);

return std::make_pair (true, nl);

} else if (li.size () == 1) {
} else {

m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ()));
for (auto i = li.begin (); i != li.end (); ++i) {

// change OASIS layer name if a layer exists by layer/datatype, but has a different name
const tl::interval_map <db::ld_type, std::string> *names_dmap = m_layer_names.mapped (dl.layer);
if (names_dmap != 0) {
const std::string *name = names_dmap->mapped (dl.datatype);
if (name != 0) {
db::LayerProperties lp_out = layout.get_properties (*i);
if (lp_out.name != *name) {
lp_out.name = *name;
layout.set_properties (*i, lp_out);
}
}
}

return std::make_pair (true, *li.begin ());
}

} else {
if (li.size () == 1) {

for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
m_layer_map_out.mmap (dl, *i, layout.get_properties (*i));
}
m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ()));

std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
if (mmp == m_multi_mapping_placeholders.end ()) {
// create a placeholder layer
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
}
return std::make_pair (true, *li.begin ());

} else {

for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
m_layer_map_out.mmap (dl, *i, layout.get_properties (*i));
}

return std::make_pair (true, mmp->second);
std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
if (mmp == m_multi_mapping_placeholders.end ()) {
// create a placeholder layer
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
}

return std::make_pair (true, mmp->second);

}

}
}
Expand Down
Loading
Loading