Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
133 changes: 98 additions & 35 deletions lib/testing/AutoroutingPipelineDebugger.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
import { useState, useEffect, useMemo, useRef } from "react"
import { GraphicsObject, Line, Point, Rect } from "graphics-debug"
import {
InteractiveGraphics,
InteractiveGraphicsCanvas,
} from "graphics-debug/react"
import { BaseSolver } from "lib/solvers/BaseSolver"
import { combineVisualizations } from "lib/utils/combineVisualizations"
import { SimpleRouteJson } from "lib/types"
import { AssignableAutoroutingPipeline1Solver } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline1/AssignableAutoroutingPipeline1Solver"
import { AssignableAutoroutingPipeline2 } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline2/AssignableAutoroutingPipeline2"
import { AssignableAutoroutingPipeline3 } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline3/AssignableAutoroutingPipeline3"
import { AutoroutingPipeline1_OriginalUnravel } from "lib/autorouter-pipelines/AutoroutingPipeline1_OriginalUnravel/AutoroutingPipeline1_OriginalUnravel"
import {
AutoroutingPipelineSolver2_PortPointPathing,
CapacityMeshSolver,
} from "lib/autorouter-pipelines/AutoroutingPipeline2_PortPointPathing/AutoroutingPipelineSolver2_PortPointPathing"
import { AutoroutingPipelineSolver3_HgPortPointPathing } from "lib/autorouter-pipelines/AutoroutingPipeline2_PortPointPathing/AutoroutingPipelineSolver3_HgPortPointPathing"
import { AssignableAutoroutingPipeline1Solver } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline1/AssignableAutoroutingPipeline1Solver"
import { AutoroutingPipeline1_OriginalUnravel } from "lib/autorouter-pipelines/AutoroutingPipeline1_OriginalUnravel/AutoroutingPipeline1_OriginalUnravel"
import { GraphicsObject, Line, Point, Rect } from "graphics-debug"
import { limitVisualizations } from "lib/utils/limitVisualizations"
import { getNodesNearNode } from "lib/solvers/UnravelSolver/getNodesNearNode"
import { filterUnravelMultiSectionInput } from "./utils/filterUnravelMultiSectionInput"
import { convertToCircuitJson } from "./utils/convertToCircuitJson"
import { getDrcErrors } from "./getDrcErrors"
import { addVisualizationToLastStep } from "lib/utils/addVisualizationToLastStep"
import { SolveBreakpointDialog } from "./SolveBreakpointDialog"
import { CacheDebugger } from "./CacheDebugger"
import {
getGlobalInMemoryCache,
getGlobalLocalStorageCache,
} from "lib/cache/setupGlobalCaches"
import { CacheProvider } from "lib/cache/types"
import { BaseSolver } from "lib/solvers/BaseSolver"
import { getNodesNearNode } from "lib/solvers/UnravelSolver/getNodesNearNode"
import { SimpleRouteJson } from "lib/types"
import { addVisualizationToLastStep } from "lib/utils/addVisualizationToLastStep"
import { combineVisualizations } from "lib/utils/combineVisualizations"
import { limitVisualizations } from "lib/utils/limitVisualizations"
import { useEffect, useMemo, useRef, useState } from "react"
import {
AutoroutingPipelineMenuBar,
PIPELINE_OPTIONS,
type PipelineId,
EFFORT_LEVELS,
type EffortLevel,
LAYER_OVERRIDE_OPTIONS,
type LayerOverride,
PIPELINE_OPTIONS,
type PipelineId,
} from "./AutoroutingPipelineMenuBar"
import { AssignableAutoroutingPipeline2 } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline2/AssignableAutoroutingPipeline2"
import { AssignableAutoroutingPipeline3 } from "lib/autorouter-pipelines/AssignableAutoroutingPipeline3/AssignableAutoroutingPipeline3"
import { CacheDebugger } from "./CacheDebugger"
import { SolveBreakpointDialog } from "./SolveBreakpointDialog"
import { getDrcErrors } from "./getDrcErrors"
import { convertToCircuitJson } from "./utils/convertToCircuitJson"
import { filterUnravelMultiSectionInput } from "./utils/filterUnravelMultiSectionInput"

const PIPELINE_SOLVERS = {
AutoroutingPipelineSolver2_PortPointPathing,
Expand All @@ -48,6 +50,26 @@ const PIPELINE_SOLVERS = {

const PIPELINE_STORAGE_KEY = "selectedPipeline"
const EFFORT_STORAGE_KEY = "selectedEffort"
const LAYER_OVERRIDE_STORAGE_KEY = "selectedLayerOverride"

const parseLayerOverride = (value: string | null): LayerOverride => {
if (value === "auto") return "auto"
const parsed = value ? parseInt(value, 10) : Number.NaN
return LAYER_OVERRIDE_OPTIONS.includes(parsed as LayerOverride)
? (parsed as LayerOverride)
: "auto"
}

const applyLayerOverrideToSrj = (
srj: SimpleRouteJson,
layerOverride: LayerOverride,
): SimpleRouteJson => {
if (layerOverride === "auto") return srj
return {
...srj,
layerCount: layerOverride,
}
}

const sanitizeParamsForDownload = (
value: any,
Expand Down Expand Up @@ -199,23 +221,47 @@ export const AutoroutingPipelineDebugger = ({
}
}

const [layerOverride, setLayerOverrideState] = useState<LayerOverride>(() =>
parseLayerOverride(localStorage.getItem(LAYER_OVERRIDE_STORAGE_KEY)),
)

const setLayerOverride = (newLayerOverride: LayerOverride) => {
setLayerOverrideState(newLayerOverride)
try {
localStorage.setItem(LAYER_OVERRIDE_STORAGE_KEY, String(newLayerOverride))
} catch (e) {
console.warn("Could not save layer override to localStorage:", e)
}
}

const createNewSolver = (
opts: {
cacheProvider?: CacheProvider | null
pipelineId?: PipelineId
effort?: EffortLevel
layerOverride?: LayerOverride
} = {},
) => {
const cacheProviderToUse = opts.cacheProvider ?? cacheProvider
if (createSolverProp) {
return createSolverProp(srj, { cacheProvider, effort, ...opts })
return createSolverProp(
applyLayerOverrideToSrj(srj, opts.layerOverride ?? layerOverride),
{
cacheProvider: cacheProviderToUse,
effort: opts.effort ?? effort,
},
)
}
const pipelineToUse = opts.pipelineId ?? selectedPipelineId
const effortToUse = opts.effort ?? effort
const srjToUse = applyLayerOverrideToSrj(
srj,
opts.layerOverride ?? layerOverride,
)
const SolverClass = PIPELINE_SOLVERS[pipelineToUse]
return new SolverClass(srj, {
cacheProvider,
return new SolverClass(srjToUse, {
cacheProvider: cacheProviderToUse,
effort: effortToUse,
...opts,
})
}

Expand All @@ -232,29 +278,33 @@ export const AutoroutingPipelineDebugger = ({
const initialEffort = storedEffort
? (parseInt(storedEffort, 10) as EffortLevel)
: 1
const initialLayerOverride = parseLayerOverride(
localStorage.getItem(LAYER_OVERRIDE_STORAGE_KEY),
)
const initialSrj = applyLayerOverrideToSrj(srj, initialLayerOverride)
const SolverClass = PIPELINE_SOLVERS[initialPipelineId]

if (!SolverClass) {
// Fallback to default pipeline if stored ID is invalid
const fallbackClass =
PIPELINE_SOLVERS["AutoroutingPipelineSolver2_PortPointPathing"]
PIPELINE_SOLVERS.AutoroutingPipelineSolver2_PortPointPathing
return createSolverProp
? createSolverProp(srj, {
? createSolverProp(initialSrj, {
cacheProvider: initialCacheProvider,
effort: initialEffort,
})
: new fallbackClass(srj, {
: new fallbackClass(initialSrj, {
cacheProvider: initialCacheProvider,
effort: initialEffort,
})
}

return createSolverProp
? createSolverProp(srj, {
? createSolverProp(initialSrj, {
cacheProvider: initialCacheProvider,
effort: initialEffort,
})
: new SolverClass(srj, {
: new SolverClass(initialSrj, {
cacheProvider: initialCacheProvider,
effort: initialEffort,
})
Expand Down Expand Up @@ -296,6 +346,11 @@ export const AutoroutingPipelineDebugger = ({
useEffect(() => {
let intervalId: ReturnType<typeof setInterval> | undefined

if (isSolvingToBreakpointRef.current) {
setIsAnimating(false)
return
}

if (isAnimating && !solver.solved && !solver.failed) {
const speedDef = SPEED_DEFINITIONS[speedLevel]
// For speeds >= 1x (index 4+), we might still want to respect the passed-in animationSpeed prop
Expand All @@ -320,11 +375,6 @@ export const AutoroutingPipelineDebugger = ({
clearInterval(intervalId)
}
}

// Stop animation if breakpoint solving is active
if (isSolvingToBreakpointRef.current) {
setIsAnimating(false)
}
}, [isAnimating, speedLevel, solver, animationSpeed])

// Manual step function
Expand Down Expand Up @@ -755,8 +805,13 @@ export const AutoroutingPipelineDebugger = ({
selectedPipelineId={selectedPipelineId}
onSetPipelineId={(pipelineId: PipelineId) => {
setSelectedPipelineId(pipelineId)
const SolverClass = PIPELINE_SOLVERS[pipelineId]
setSolver(new SolverClass(srj, { cacheProvider, effort }))
setLayerOverride("auto")
setSolver(
createNewSolver({
pipelineId,
layerOverride: "auto",
}),
)
setDrcErrors(null)
setDrcErrorCount(0)
}}
Expand All @@ -767,6 +822,14 @@ export const AutoroutingPipelineDebugger = ({
setDrcErrors(null)
setDrcErrorCount(0)
}}
layerOverride={layerOverride}
defaultLayerCount={srj.layerCount}
onSetLayerOverride={(newLayerOverride: LayerOverride) => {
setLayerOverride(newLayerOverride)
setSolver(createNewSolver({ layerOverride: newLayerOverride }))
setDrcErrors(null)
setDrcErrorCount(0)
}}
/>
<div className="flex gap-2 mb-4 text-xs">
<button
Expand Down
40 changes: 38 additions & 2 deletions lib/testing/AutoroutingPipelineMenuBar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CacheProvider } from "lib/cache/types"
import {
Menubar,
MenubarContent,
Expand All @@ -12,10 +13,9 @@ import {
} from "lib/testing/ui/menubar" // Assuming shadcn components are here
import {
type CacheProviderName,
cacheProviderNames,
SPEED_DEFINITIONS,
cacheProviderNames,
} from "./AutoroutingPipelineDebugger"
import { CacheProvider } from "lib/cache/types"

const cacheProviders: CacheProviderName[] = [
"None",
Expand All @@ -25,6 +25,8 @@ const cacheProviders: CacheProviderName[] = [

export const EFFORT_LEVELS = [1, 2, 5, 10, 20, 50, 100] as const
export type EffortLevel = (typeof EFFORT_LEVELS)[number]
export const LAYER_OVERRIDE_OPTIONS = ["auto", 2, 4] as const
export type LayerOverride = (typeof LAYER_OVERRIDE_OPTIONS)[number]

export const PIPELINE_OPTIONS = [
{
Expand Down Expand Up @@ -73,6 +75,9 @@ interface AutoroutingPipelineMenuBarProps {
onSetPipelineId: (pipelineId: PipelineId) => void
effort: EffortLevel
onSetEffort: (effort: EffortLevel) => void
layerOverride: LayerOverride
defaultLayerCount: number
onSetLayerOverride: (layerOverride: LayerOverride) => void
}

export const AutoroutingPipelineMenuBar = ({
Expand All @@ -93,7 +98,15 @@ export const AutoroutingPipelineMenuBar = ({
onSetPipelineId,
effort,
onSetEffort,
layerOverride,
defaultLayerCount,
onSetLayerOverride,
}: AutoroutingPipelineMenuBarProps) => {
const layerOverrideLabel =
layerOverride === "auto"
? `auto (${defaultLayerCount})`
: String(layerOverride)

return (
<Menubar className="rounded-none border-b border-none px-2 lg:px-4 mb-4 light">
<MenubarMenu>
Expand Down Expand Up @@ -127,6 +140,29 @@ export const AutoroutingPipelineMenuBar = ({
))}
</MenubarSubContent>
</MenubarSub>
<MenubarSub>
<MenubarSubTrigger>Layers: {layerOverrideLabel}</MenubarSubTrigger>
<MenubarSubContent>
{LAYER_OVERRIDE_OPTIONS.map((option) => {
const label =
option === "auto"
? `auto (${defaultLayerCount})`
: String(option)
return (
<MenubarItem
key={option}
onClick={() => onSetLayerOverride(option)}
disabled={layerOverride === option}
>
{label}
{layerOverride === option && (
<MenubarShortcut>✓</MenubarShortcut>
)}
</MenubarItem>
)
})}
</MenubarSubContent>
</MenubarSub>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
Expand Down
Loading