2025-10-14 18:52:22 +02:00
import { Aard } from './Aard' ;
import { AardLegacy } from './AardLegacy' ;
2025-04-15 18:51:34 +02:00
import { AardPerformanceData } from './AardTimers' ;
2025-10-14 18:52:22 +02:00
import { FallbackCanvas } from './gl/FallbackCanvas' ;
2025-04-15 18:51:34 +02:00
2025-04-05 01:31:06 +02:00
export class AardDebugUi {
aard : any ;
uiAnchorElement : HTMLDivElement ;
pauseOnArCheck : boolean = false ;
2025-04-21 22:24:32 +02:00
uiVisibility : any = { } ;
2025-04-05 01:31:06 +02:00
constructor ( aard : any ) {
this . aard = aard ;
2025-04-21 22:24:32 +02:00
this . uiVisibility = {
detectionDetails : aard.settings.active.ui.dev.aardDebugOverlay.showDetectionDetails
} ;
2025-04-05 01:31:06 +02:00
( window as any ) . ultrawidify_uw_aard_debug_tools = {
enableStopOnChange : ( ) = > this . changePauseOnCheck ( true ) ,
disableStopOnChange : ( ) = > this . changePauseOnCheck ( false ) ,
resumeVideo : ( ) = > this . resumeVideo ( ) ,
step : ( ) = > this . aard . step ( )
}
}
initContainer() {
const div = document . createElement ( 'div' ) ;
div . id = 'uw-aard-debug-ui-container' ;
div . innerHTML = `
< div style = "
2025-04-10 00:45:39 +02:00
position : fixed ; top : 0 ; left : 0 ; width : 100vw ; height : 100dvh ; display : flex ; flex - direction : column ; pointer - events : none ; z - index : 9999 ; font - size : 16px ; font - family : 'Overpass Mono' , monospace ;
2025-04-05 01:31:06 +02:00
" >
2025-04-10 00:45:39 +02:00
< div style = "width: 100%; display: flex; flex-direction: row; justify-content: space-between; backdrop-filter: blur(0.5rem) brightness(0.5);" >
2025-04-21 22:24:32 +02:00
< div style = "padding: 1rem; color: #fff" >
< h1 > Aard debug overlay < / h1 >
< / div >
< div style = "pointer-events: all; display: flex; flex-direction: column; margin-right: 1rem;" >
< button id = "uw-aard-debug_show-detection-details" > Show det . details < / button >
< button id = "uw-aard-debug_hide-detection-details" > Hide det . details < / button >
< / div >
2025-04-15 18:51:34 +02:00
< style >
# uw - aard - debug_performance - container # uw - aard - debug_performance - popup {
display : none ;
}
# uw - aard - debug_performance - container :hover # uw - aard - debug_performance - popup {
display : block ;
position : fixed ;
left : 0 ;
top : 3rem ;
width : 100vw ;
color : # aaa ;
background - color : # 000 ;
border : 2px solid # fa6 ;
padding : 16px ;
padding - right : 32px ;
box - sizing : border - box ;
backdrop - filter : blur ( 1 rem ) brightness ( 0.5 ) ;
pointer - events : none ;
font - size : 12px ;
}
< / style >
< div id = "uw-aard-debug_performance-container" style = "flex-grow: 1; position: relative; pointer-events: auto;" >
< div id = "uw-aard-debug_performance-mini" style = "width: 100%; color: #aaa; display: flex; flex-direction: column; font-size: 12px;" > < / div >
< div id = "uw-aard-debug_performance-popup" style = "position: fixed; top: 3rem; z-index: 3000;" >
< / div >
< / div >
2025-04-05 01:31:06 +02:00
< div style = "pointer-events: all" >
2025-04-10 00:45:39 +02:00
< button id = "uw-aard-debug-ui_close-overlay" > Close overlay < / button >
2025-04-05 01:31:06 +02:00
< / div >
< / div >
2025-04-21 22:24:32 +02:00
2025-10-14 18:52:22 +02:00
< div id = "uw-aard-debug-ui_body" style = "display: flex; flex-direction: row; width: 100%; margin-top: 8rem;" >
2025-04-10 00:45:39 +02:00
< div style = "" >
< div id = "uw-aard-debug_aard-sample-canvas" style = "min-width: 640px" > < / div >
< div style = "background: black; color: #fff" ; font - size : 24px ; " > AARD IN < / div >
< div style = "pointer-events: all" >
< button id = "uw-aard-debug-ui_enable-stop-on-change" style = "" > Pause video on aspect ratio change < / button >
< button id = "uw-aard-debug-ui_disable-stop-on-change" style = "display: none" > Stop pausing video on aspect ratio change < / button >
< button id = "uw-aard-debug-ui_resume-video" > Resume video < / button >
2025-04-15 18:51:34 +02:00
< button id = "uw-aard-debug-ui_enable-step" > Run ARD once < / button >
< button id = "uw-aard-debug-ui_enable-step-nocache" > Run ARD ( bypass cache ) < / button >
2025-04-05 01:31:06 +02:00
< / div >
< / div >
2025-04-10 00:45:39 +02:00
< div style = "flex-grow: 1" > < / div >
< div >
< div style = "background: black; color: #ccc;" >
< div style = "font-size: 24px; padding: 1rem;" >
Debug results :
< / div >
< pre id = "uw-aard-results" > < / pre >
< / div >
< / div >
2025-10-14 18:52:22 +02:00
< div style = "width: 1920px; border: 2px dotted #142; margin-right:2rem;" >
2025-04-10 00:45:39 +02:00
< div id = "uw-aard-debug_aard-output" style = "zoom: 3; image-rendering: pixelated;" > < / div >
< div style = "background: black; color: #fff; font-size: 24px;" > AARD RESULT < / div >
< / div >
2025-04-05 01:31:06 +02:00
< / div >
< / div >
` ;
document . body . appendChild ( div ) ;
this . uiAnchorElement = div ;
document . getElementById ( 'uw-aard-debug-ui_enable-stop-on-change' ) . onclick = ( ) = > this . changePauseOnCheck ( true ) ;
2025-04-10 00:45:39 +02:00
document . getElementById ( 'uw-aard-debug-ui_disable-stop-on-change' ) . onclick = ( ) = > this . changePauseOnCheck ( false ) ;
2025-04-05 01:31:06 +02:00
document . getElementById ( 'uw-aard-debug-ui_resume-video' ) . onclick = ( ) = > this . resumeVideo ( ) ;
document . getElementById ( 'uw-aard-debug-ui_enable-step' ) . onclick = ( ) = > this . aard . step ( ) ;
2025-04-15 18:51:34 +02:00
document . getElementById ( 'uw-aard-debug-ui_enable-step-nocache' ) . onclick = ( ) = > this . aard . step ( { noCache : true } ) ;
2025-04-10 00:45:39 +02:00
document . getElementById ( 'uw-aard-debug-ui_close-overlay' ) . onclick = ( ) = > ( this . aard as any ) . hideDebugCanvas ( ) ;
2025-04-21 22:24:32 +02:00
document . getElementById ( 'uw-aard-debug_show-detection-details' ) . onclick = ( ) = > { this . uiVisibility . detectionDetails = true ; this . setOverlayVisibility ( ) ; } ;
document . getElementById ( 'uw-aard-debug_hide-detection-details' ) . onclick = ( ) = > { this . uiVisibility . detectionDetails = false ; this . setOverlayVisibility ( ) ; } ;
this . setOverlayVisibility ( ) ;
2025-04-05 01:31:06 +02:00
}
changePauseOnCheck ( pauseOnChange : boolean ) {
this . pauseOnArCheck = pauseOnChange ;
document . getElementById ( "uw-aard-debug-ui_enable-stop-on-change" ) . style . display = pauseOnChange ? "none" : "" ;
document . getElementById ( "uw-aard-debug-ui_disable-stop-on-change" ) . style . display = pauseOnChange ? "" : "none" ;
}
destroyContainer() {
this . uiAnchorElement . remove ( ) ;
}
attachCanvases ( sample : HTMLCanvasElement , debug : HTMLCanvasElement ) {
const sampleCanvasParent = document . getElementById ( 'uw-aard-debug_aard-sample-canvas' ) ;
sampleCanvasParent . appendChild ( sample ) ;
const debugCanvasParent = document . getElementById ( 'uw-aard-debug_aard-output' ) ;
debugCanvasParent . appendChild ( debug ) ;
}
resumeVideo() {
( this . aard as any ) . video . play ( ) ;
this . aard . start ( ) ;
}
2025-04-15 18:51:34 +02:00
private updatePerformanceResults() {
const previewDiv = document . getElementById ( 'uw-aard-debug_performance-mini' ) ;
const popupDiv = document . getElementById ( 'uw-aard-debug_performance-popup' ) ;
const previewContent = `
< div style = "display: flex; flex-direction: row" >
< div style = "width: 120px" > Current : < / div >
< div style = "flex-grow: 1;" > $ { this . generateMiniGraphBar ( this . aard . timer . current ) } < / div >
< / div >
< div style = "display: flex; flex-direction: row" >
< div style = "width: 120px" > Average : < / div >
< div style = "flex-grow: 1" > $ { this . generateMiniGraphBar ( this . aard . timer . average ) } < / div >
< / div >
< div style = "display: flex; flex-direction: row" >
2025-06-16 21:58:35 +02:00
< div style = "width: 120px" > Last chg . : < / div >
< div > < / div >
< div style = "flex-grow: 1" > $ { this . generateMiniGraphBar ( this . aard . timer . lastChange ) } < / div >
2025-04-15 18:51:34 +02:00
< / div >
` ;
const popupContent = `
< h2 style = "color: #fa6; margin-bottom: 1rem" > Detailed performance analysis : < / h2 >
2025-10-14 18:52:22 +02:00
< div >
< span style = "color: #fff" > About : < / span > < br / >
Aard version : < span style = "color: #fa6" > $ { this . aard instanceof AardLegacy ? 'legacy' : this . aard instanceof Aard ? 'experimental' : 'unknown' } < / span > < small > ( instanceof AardLegacy ? $ { this . aard instanceof AardLegacy } , Aard ? $ { this . aard instanceof Aard } ) < / small > < br / >
canvas type : < span style = "color: #fa6" > $ { ! this . aard . canvasStore . main ? '<canvas not initialized>' : this . aard . canvasStore . main instanceof FallbackCanvas ? '2dCanvas' : 'webgl' } < / span > |
legacy default : < span style = "color: #fa6" > $ { this . aard . settings . active . aardLegacy . aardType } < / span > ,
experimental default : < span style = "color: #fa6" > $ { this . aard . settings . active . aard . aardType } < / span >
< / div >
< br / >
2025-04-15 18:51:34 +02:00
< div style = "width: 100%; display: flex; flex-direction: column" >
< div style = "margin-bottom: 1rem;" >
2025-10-14 18:52:22 +02:00
$ { this . generateRawTimes ( this . aard . timer . current ) }
2025-04-15 18:51:34 +02:00
< / div >
< div style = "color: #fff" > Stage times ( not cumulative ) : < / div >
< div style = "display: flex; flex-direction: row; width: 100%; height: 150px" >
< div style = "width: 160px; text-align: right; padding-right: 4px;" > Current : < / div >
< div style = "flex-grow: 1;" > $ { this . generateMiniGraphBar ( this . aard . timer . current , true ) } < / div >
< / div >
< div style = "margin-bottom: 1rem;" >
2025-10-12 22:03:55 +02:00
$ { this . generateRawTimes ( this . aard . timer . average ) }
2025-04-15 18:51:34 +02:00
< / div >
< div style = "color: #fff" > Stage times ( not cumulative ) : < / div >
< div style = "display: flex; flex-direction: row; width: 100%; height: 150px" >
< div style = "width: 160px; text-align: right; padding-right: 4px;" > Average : < / div >
< div style = "flex-grow: 1;" > $ { this . generateMiniGraphBar ( this . aard . timer . average , true ) } < / div >
< / div >
2025-10-12 22:03:55 +02:00
< div style = "margin-bottom: 1rem;" >
2025-10-14 18:52:22 +02:00
$ { this . generateRawTimes ( this . aard . timer . lastChange ) }
2025-10-12 22:03:55 +02:00
< / div >
2025-04-15 18:51:34 +02:00
< div style = "display: flex; flex-direction: row; width: 100%; height: 150px" >
< div style = "width: 160px; text-align: right; padding-right: 4px;" > Last change : < / div >
< div style = "flex-grow: 1;" > $ { this . generateMiniGraphBar ( this . aard . timer . lastChange , true ) } < / div >
< / div >
2025-10-14 18:52:22 +02:00
<!-- < pre > $ { JSON . stringify ( { current : this.aard.timer.current , average : this.aard.timer.average , lastChange : this.aard.timer.lastChange } , null , 2 ) } < / pre > -- >
2025-04-15 18:51:34 +02:00
< / div >
`
previewDiv . innerHTML = previewContent ;
popupDiv . innerHTML = popupContent ;
}
private getBarLabel ( width : number , leftOffset : number , topOffset : number , label : string , detailed : boolean , extraStyles? : string ) {
if ( ! detailed ) {
return '' ;
}
let offsets : string ;
let text : string = '' ;
if ( leftOffset + width < 80 ) {
// at the end of the bar
offsets = ` left: ${ leftOffset + width } %; ` ;
} else {
if ( width < 15 && leftOffset < 100 ) {
// before the bar
offsets = ` right: ${ 100 - leftOffset } %; ` ;
text = 'color: #fff;' ;
} else {
// inside the bar, aligned to right
offsets = ` right: ${ Math . max ( 100 - ( leftOffset + width ) , 0 ) } %; `
}
}
return `
< div style = "
position : absolute ;
$ { offsets } top : $ { topOffset } px ;
padding - left : 0.5rem ; padding - right : 0.5rem ; đ
$ { text }
text - shadow : 0 0 2 px # 000 , 0 0 2 px # 000 ; 0 0 2 px # 000 ; 0 0 2 px # 000 ;
$ { extraStyles }
" >
$ { label }
< / div >
` ;
}
2025-10-12 22:03:55 +02:00
private generateRawTimes ( timer ) {
return `
< span style = "color: #fff" > Raw times ( cumulative ; - 1 = test was skipped ) : < / span > < br / >
draw < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . draw . toFixed ( 2 ) } ms < / span >
get data < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . getImage . toFixed ( 2 ) } ms < / span >
black lv . < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . fastBlackLevel . toFixed ( 2 ) } ms < / span >
guard / image < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . guardLine . toFixed ( 3 ) } ms < / span >
edge < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . edgeScan . toFixed ( 2 ) } ms < / span >
gradient < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . gradient . toFixed ( 3 ) } ms < / span >
post < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . scanResults . toFixed ( 2 ) } ms < / span >
subtitle < span style = "color: #fa6; margin-right: 0.5rem;" > $ { timer . subtitleScan . toFixed ( 2 ) } ms < / span >
` ;
}
2025-04-15 18:51:34 +02:00
private generateMiniGraphBar ( perf : AardPerformanceData , detailed : boolean = false ) {
if ( ! perf ) {
return `
n / a
` ;
}
let total = 0 ;
const draw = Math . max ( perf . draw , 0 ) ;
total += draw ;
const getImageStart = draw ;
const getImage = Math . max ( perf . getImage - total , 0 ) ;
total += getImage ;
const fastBlackLevelStart = getImageStart + getImage ;
const fastBlackLevel = Math . max ( perf . fastBlackLevel - total , 0 ) ;
total += fastBlackLevel ;
const guardLineStart = fastBlackLevelStart + fastBlackLevel ;
2025-10-14 18:52:22 +02:00
const guardLine = ( perf . guardLine !== undefined && perf . guardLine !== - 1 ) ? Math . max ( perf . guardLine - total , 0 ) : 0 ;
2025-04-15 18:51:34 +02:00
total += guardLine ;
const edgeScanStart = guardLineStart + guardLine ;
2025-10-14 18:52:22 +02:00
const edgeScan = ( perf . edgeScan !== undefined && perf . edgeScan !== - 1 ) ? Math . max ( perf . edgeScan - total , 0 ) : 0 ;
2025-04-15 18:51:34 +02:00
total += edgeScan ;
const gradientStart = edgeScanStart + edgeScan ;
2025-10-14 18:52:22 +02:00
const gradient = ( perf . gradient !== undefined && perf . gradient !== - 1 ) ? Math . max ( perf . gradient - total , 0 ) : 0 ;
2025-04-15 18:51:34 +02:00
total += gradient ;
const scanResultsStart = gradientStart + gradient ;
2025-10-14 18:52:22 +02:00
const scanResults = ( perf . scanResults !== undefined && perf . scanResults !== - 1 ) ? Math . max ( perf . scanResults - total , 0 ) : 0 ;
2025-04-15 18:51:34 +02:00
total += scanResults ;
2025-10-12 22:03:55 +02:00
const subtitleScanStart = scanResultsStart + scanResults ;
2025-10-14 18:52:22 +02:00
const subtitleScan = Math . max ( perf . subtitleScan - total , 0 ) ;
2025-10-12 22:03:55 +02:00
total += subtitleScan ;
2025-04-15 18:51:34 +02:00
return `
2025-10-12 22:03:55 +02:00
< div style = "width: calc(100% - 2rem); position: relative; text-align: right;" >
2025-04-15 18:51:34 +02:00
$ { detailed ? '' : ` ${ total . toFixed ( ) } ms ` }
< div style = "position: absolute; top: 0; left: 0; width: ${total}%; background: #fff; height: 2px;" > < / div >
$ { detailed ? ` <div style="position: absolute; top: 0; left: ${ total } %; height: 100px; width: 1px; border-left: 1px dotted rgba(255,255,255,0.5)"></div> ` : '' }
< div style = "position: absolute; top: ${detailed ? '2px' : '2px'}; left: 0; min-width: 1px; width: ${draw}%; background: #007; height: 12px;" > < / div >
$ { this . getBarLabel ( draw , 0 , 2 , ` draw: ${ draw . toFixed ( 2 ) } ms ` , detailed ) }
< div style = "position: absolute; top: ${detailed ? '14px' : '2px'}; left: ${getImageStart}%; min-width: 1px; width: ${getImage}%; background: #00a; height: 12px;" > < / div >
$ { this . getBarLabel ( getImage , getImageStart , 14 , ` get data: ${ getImage . toFixed ( 2 ) } ms ` , detailed ) }
< div style = "position: absolute; top: ${detailed ? '26px' : '2px'}; left: ${fastBlackLevelStart}%; min-width: 1px; width: ${fastBlackLevel}%; background: #03a; height: 12px;" > < / div >
$ { this . getBarLabel ( fastBlackLevel , fastBlackLevelStart , 26 , ` black level: ${ fastBlackLevel . toFixed ( 2 ) } ms ` , detailed ) } ;
< div style = "position: absolute; top: ${detailed ? '38px' : '2px'}; left: ${guardLineStart}%; min-width: 1px; width: ${guardLine}%; background: #0f3; height: 12px;" > < / div >
$ { this . getBarLabel ( guardLine , guardLineStart , 38 , ` guard/image line: ${ guardLine . toFixed ( 2 ) } ms ` , detailed ) }
< div style = "position: absolute; top: ${detailed ? '50px' : '2px'}; left: ${edgeScanStart}%; min-width: 1px; width: ${edgeScan}%; background: #f51; height: 12px;" > < / div >
$ { this . getBarLabel ( edgeScan , edgeScanStart , 50 , ` edge scan (/w validation): ${ edgeScan . toFixed ( 2 ) } ms ` , detailed ) }
< div style = "position: absolute; top: ${detailed ? '62px' : '2px'}; left: ${gradientStart}%; min-width: 1px; width: ${gradient}%; background: #fa6; height: 12px;" > < / div >
$ { this . getBarLabel ( gradient , gradientStart , 62 , ` gradient: ${ gradient . toFixed ( 2 ) } ms ` , detailed ) }
< div style = "position: absolute; top: ${detailed ? '74px' : '2px'}; left: ${scanResultsStart}%; min-width: 1px; width: ${scanResults}%; background: #80f; height: 12px;" > < / div >
$ { this . getBarLabel ( scanResults , scanResultsStart , 74 , ` scan results processing: ${ scanResults . toFixed ( 2 ) } ms ` , detailed ) }
2025-10-14 18:52:22 +02:00
< div style = "position: absolute; top: ${detailed ? '86px' : '2px'}; left: ${subtitleScanStart}%; min-width: 1px; width: ${subtitleScan}%; background: rgba(234, 204, 84, 1); height: 12px;" > < / div >
$ { this . getBarLabel ( subtitleScan , subtitleScanStart , 86 , ` subtitle scan: ${ subtitleScan . toFixed ( 2 ) } ms ` , detailed ) }
2025-10-12 22:03:55 +02:00
2025-10-14 18:52:22 +02:00
$ { this . getBarLabel ( 0 , subtitleScan + subtitleScanStart , 98 , ` total: ${ total . toFixed ( 2 ) } ms ` , detailed , 'color: #fff;' ) }
2025-10-12 22:03:55 +02:00
2025-04-15 18:51:34 +02:00
<!-- 60 / 30 fps markers -- >
< div style = "position: absolute; top: ${detailed ? '-12px' : '0'}; left: 16.666%; width: 1px; border-left: 1px dashed #4f9; height: ${detailed ? '112px' : '12px'}; padding-left: 2px; background-color: rgba(0,0,0,0.5); z-index: ${detailed ? '5' : '2'}000;" > 60 fps < / div >
< div style = "position: absolute; top: ${detailed ? '-12px' : '0'}; left: 33.333%; width: 1px; border-left: 1px dashed #ff0; height: ${detailed ? '112px' : '12px'}; padding-left: 2px; background-color: #000; z-index: ${detailed ? '5' : '2'}000;" > 30 fps < / div >
< / div >
` ;
}
2025-10-12 22:03:55 +02:00
_lastAr : undefined ;
2025-10-14 18:52:22 +02:00
updateTestResults ( testResults , timers ) {
2025-04-15 18:51:34 +02:00
this . updatePerformanceResults ( ) ;
2025-04-05 01:31:06 +02:00
if ( testResults . aspectRatioUpdated && this . pauseOnArCheck ) {
( this . aard as any ) . video . pause ( ) ;
this . aard . stop ( ) ;
}
const resultsDiv = document . getElementById ( 'uw-aard-results' ) ;
2025-10-12 22:03:55 +02:00
const ar = testResults . activeAspectRatio . toFixed ( 3 ) ;
2025-04-05 01:31:06 +02:00
let out = `
LAST STAGE : $ { testResults . lastStage } | black level : $ { testResults . blackLevel } , threshold : $ { testResults . blackThreshold }
-- ASPECT RATIO
2025-10-12 22:03:55 +02:00
Active : $ { ar } , changed since last check ? $ { testResults . aspectRatioUpdated } letterbox width : $ { testResults . letterboxWidth } offset $ { testResults . letterboxOffset } < br / >
< sup > ( last : $ { this . _lastAr } ) < / sup >
2025-04-05 01:31:06 +02:00
2025-10-14 18:52:22 +02:00
Paused until ? $ { Date . now ( ) < timers . pauseUntil ? ( ( timers . pauseUntil - Date . now ( ) ) / 1000 ) + 's' : 'not paused' } ;
< sup > now : $ { Date . now ( ) } ms ; until :$ { timers . pauseUntil } ms ; diff : $ { ( + timers . pauseUntil - Date . now ( ) ) } < / sup >
2025-04-05 01:31:06 +02:00
2025-10-12 22:03:55 +02:00
image in black level probe ( aka "not letterbox" ) : $ { testResults . notLetterbox }
2025-04-05 01:31:06 +02:00
` ;
2025-10-12 22:03:55 +02:00
this . _lastAr = ar ;
resultsDiv . innerHTML = out ;
2025-04-05 01:31:06 +02:00
}
2025-04-21 22:24:32 +02:00
private setOverlayVisibility() {
document . getElementById ( 'uw-aard-debug-ui_body' ) . style . display = this . uiVisibility . detectionDetails ? 'flex' : 'none' ;
document . getElementById ( 'uw-aard-debug_hide-detection-details' ) . style . display = this . uiVisibility . detectionDetails ? '' : 'none' ;
document . getElementById ( 'uw-aard-debug_show-detection-details' ) . style . display = this . uiVisibility . detectionDetails ? 'none' : '' ;
}
2025-04-05 01:31:06 +02:00
}