diff --git a/src/gui/src/displayControls.cpp b/src/gui/src/displayControls.cpp index 2ed68ad82f1..cf226299217 100644 --- a/src/gui/src/displayControls.cpp +++ b/src/gui/src/displayControls.cpp @@ -2124,8 +2124,10 @@ void DisplayControls::techInit(odb::dbTech* tech) std::mt19937 gen_color(1); auto generate_next_color = [&gen_color]() -> QColor { - return QColor( - 50 + gen_color() % 200, 50 + gen_color() % 200, 50 + gen_color() % 200); + const int blue = 50 + gen_color() % 200; + const int green = 50 + gen_color() % 200; + const int red = 50 + gen_color() % 200; + return QColor(red, green, blue); }; // Iterate through the layers and set default colors diff --git a/src/web/src/tile_generator.cpp b/src/web/src/tile_generator.cpp index 197bde30f4e..3a4c0de8449 100644 --- a/src/web/src/tile_generator.cpp +++ b/src/web/src/tile_generator.cpp @@ -939,9 +939,12 @@ static odb::PtrMap buildLayerColorMap( std::mt19937 rng(1); auto random_color = [&rng]() { - return Color{.r = static_cast(50 + rng() % 200), - .g = static_cast(50 + rng() % 200), - .b = static_cast(50 + rng() % 200), + const int blue = 50 + rng() % 200; + const int green = 50 + rng() % 200; + const int red = 50 + rng() % 200; + return Color{.r = static_cast(red), + .g = static_cast(green), + .b = static_cast(blue), .a = 180}; }; diff --git a/src/web/test/cpp/TestTileGenerator.cpp b/src/web/test/cpp/TestTileGenerator.cpp index d54a0f60049..e9eb187d98a 100644 --- a/src/web/test/cpp/TestTileGenerator.cpp +++ b/src/web/test/cpp/TestTileGenerator.cpp @@ -183,55 +183,111 @@ TEST_F(TileGeneratorTest, GetLayers) } // Layer colors must mirror gui::DisplayControls::techInit so the GUI and the -// web frontend show the same color for the same layer. Spot-check the first -// few entries of each palette and exercise the type-based assignment rules. +// web frontend show the same color for the same layer. Nangate45 only has 10 +// routing + 9 cut layers, all within the 14-entry built-in palettes, so we +// extend the tech to 20 routing + 19 cut layers to also exercise the overflow +// path: layers past the palette get deterministic mt19937(1)-seeded random +// colors. The expected RGB values below were computed by replaying the exact +// blue/green/red draw order (matching gui::DisplayControls::techInit) over the +// full getLayers() iteration, including the MASTERSLICE/OVERLAP layers that +// also consume random draws. TEST_F(TileGeneratorTest, GetLayerColorMapMatchesGuiPalette) { - makeTileGen(); - const auto& colors = tile_gen_->getLayerColorMap(); - odb::dbTech* tech = getDb()->getTech(); ASSERT_NE(tech, nullptr); - odb::dbTechLayer* metal1 = tech->findLayer("metal1"); - odb::dbTechLayer* metal2 = tech->findLayer("metal2"); - odb::dbTechLayer* metal3 = tech->findLayer("metal3"); - odb::dbTechLayer* via1 = tech->findLayer("via1"); - odb::dbTechLayer* via2 = tech->findLayer("via2"); - ASSERT_NE(metal1, nullptr); - ASSERT_NE(metal2, nullptr); - ASSERT_NE(metal3, nullptr); - ASSERT_NE(via1, nullptr); - ASSERT_NE(via2, nullptr); - - // First three metals match the GUI's seeded #00F, #F00, #0D0 entries. - const Color m1 = colors.at(metal1); - EXPECT_EQ(m1.r, 0); - EXPECT_EQ(m1.g, 0); - EXPECT_EQ(m1.b, 254); - EXPECT_EQ(m1.a, 180); - - const Color m2 = colors.at(metal2); - EXPECT_EQ(m2.r, 254); - EXPECT_EQ(m2.g, 0); - EXPECT_EQ(m2.b, 0); - - const Color m3 = colors.at(metal3); - EXPECT_EQ(m3.r, 9); - EXPECT_EQ(m3.g, 221); - EXPECT_EQ(m3.b, 0); - - // First two cuts match the GUI's cut palette (light blue, light red). - const Color v1 = colors.at(via1); - EXPECT_EQ(v1.r, 126); - EXPECT_EQ(v1.g, 126); - EXPECT_EQ(v1.b, 255); - EXPECT_EQ(v1.a, 180); - - const Color v2 = colors.at(via2); - EXPECT_EQ(v2.r, 255); - EXPECT_EQ(v2.g, 126); - EXPECT_EQ(v2.b, 126); + // Grow the stack to 20 routing + 19 cut layers (metal11..metal20 + + // via10..via19), created interleaved (metalN, via(N-1)) just like a real + // LEF, so getLayers() yields them in that order. + for (int i = 11; i <= 20; ++i) { + odb::dbTechLayer::create(tech, + ("metal" + std::to_string(i)).c_str(), + odb::dbTechLayerType::ROUTING); + odb::dbTechLayer::create(tech, + ("via" + std::to_string(i - 1)).c_str(), + odb::dbTechLayerType::CUT); + } + + makeTileGen(); + const auto& colors = tile_gen_->getLayerColorMap(); + + // Helper: assert a layer's color matches an expected RGB (alpha is always + // 180 in both the GUI and the web palette). + auto expectColor = [&](const char* name, int r, int g, int b) { + odb::dbTechLayer* layer = tech->findLayer(name); + ASSERT_NE(layer, nullptr) << "missing layer " << name; + const Color c = colors.at(layer); + EXPECT_EQ(c.r, r) << name << " red"; + EXPECT_EQ(c.g, g) << name << " green"; + EXPECT_EQ(c.b, b) << name << " blue"; + EXPECT_EQ(c.a, 180) << name << " alpha"; + }; + + struct LayerColor + { + const char* name; + int r; + int g; + int b; + }; + + // All 20 routing layers: metal1..metal14 are the seeded kMetalColors palette + // (#00F, #F00, #0D0, ...), metal15..metal20 are the mt19937(1) overflow. + const LayerColor kRouting[] = { + {"metal1", 0, 0, 254}, + {"metal2", 254, 0, 0}, + {"metal3", 9, 221, 0}, + {"metal4", 190, 244, 81}, + {"metal5", 222, 33, 96}, + {"metal6", 32, 216, 253}, + {"metal7", 253, 108, 160}, + {"metal8", 117, 63, 194}, + {"metal9", 128, 155, 49}, + {"metal10", 234, 63, 252}, + {"metal11", 9, 96, 19}, + {"metal12", 214, 120, 239}, + {"metal13", 192, 222, 164}, + {"metal14", 110, 68, 107}, + // Overflow (random_color past the 14-entry palette). + {"metal15", 99, 98, 82}, + {"metal16", 63, 193, 166}, + {"metal17", 200, 166, 92}, + {"metal18", 124, 126, 173}, + {"metal19", 137, 246, 68}, + {"metal20", 242, 216, 153}, + }; + + // All 19 cut layers: via1..via14 are the seeded kCutColors palette, + // via15..via19 are the mt19937(1) overflow. + const LayerColor kCut[] = { + {"via1", 126, 126, 255}, + {"via2", 255, 126, 126}, + {"via3", 4, 110, 0}, + {"via4", 95, 122, 40}, + {"via5", 111, 17, 48}, + {"via6", 16, 108, 126}, + {"via7", 126, 54, 80}, + {"via8", 58, 32, 97}, + {"via9", 225, 255, 136}, + {"via10", 117, 32, 126}, + {"via11", 18, 192, 38}, + {"via12", 107, 60, 119}, + {"via13", 96, 111, 82}, + {"via14", 220, 136, 214}, + // Overflow (random_color past the 14-entry palette). + {"via15", 171, 152, 190}, + {"via16", 54, 196, 143}, + {"via17", 104, 79, 102}, + {"via18", 123, 187, 153}, + {"via19", 179, 175, 160}, + }; + + for (const LayerColor& lc : kRouting) { + expectColor(lc.name, lc.r, lc.g, lc.b); + } + for (const LayerColor& lc : kCut) { + expectColor(lc.name, lc.r, lc.g, lc.b); + } } TEST_F(TileGeneratorTest, GetLayerColorMapIsCached)