import { Aard } from './Aard'; import { AardLegacy } from './AardLegacy'; import { AardPerformanceData } from './AardTimers'; import { FallbackCanvas } from './gl/FallbackCanvas'; export class AardDebugUi { aard: any; uiAnchorElement: HTMLDivElement; pauseOnArCheck: boolean = false; uiVisibility: any = {}; constructor(aard: any) { this.aard = aard; this.uiVisibility = { detectionDetails: aard.settings.active.ui.dev.aardDebugOverlay.showDetectionDetails }; (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 = `

Aard debug overlay

AARD IN
Debug results:

            
AARD RESULT
`; document.body.appendChild(div); this.uiAnchorElement = div; document.getElementById('uw-aard-debug-ui_enable-stop-on-change').onclick = () => this.changePauseOnCheck(true); document.getElementById('uw-aard-debug-ui_disable-stop-on-change').onclick = () => this.changePauseOnCheck(false); document.getElementById('uw-aard-debug-ui_resume-video').onclick = () => this.resumeVideo(); document.getElementById('uw-aard-debug-ui_enable-step').onclick = () => this.aard.step(); document.getElementById('uw-aard-debug-ui_enable-step-nocache').onclick = () => this.aard.step({noCache: true}); document.getElementById('uw-aard-debug-ui_close-overlay').onclick = () => (this.aard as any).hideDebugCanvas(); 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(); } 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(); } private updatePerformanceResults() { const previewDiv = document.getElementById('uw-aard-debug_performance-mini'); const popupDiv = document.getElementById('uw-aard-debug_performance-popup'); const previewContent = `
Current:
${this.generateMiniGraphBar(this.aard.timer.current)}
Average:
${this.generateMiniGraphBar(this.aard.timer.average)}
Last chg.:
${this.generateMiniGraphBar(this.aard.timer.lastChange)}
`; const popupContent = `

Detailed performance analysis:

About:
Aard version: ${this.aard instanceof AardLegacy ? 'legacy' : this.aard instanceof Aard ? 'experimental' : 'unknown'} (instanceof AardLegacy? ${this.aard instanceof AardLegacy}, Aard? ${this.aard instanceof Aard})
canvas type: ${!this.aard.canvasStore.main ? '' : this.aard.canvasStore.main instanceof FallbackCanvas ? '2dCanvas' : 'webgl'} | legacy default: ${this.aard.settings.active.aardLegacy.aardType}, experimental default: ${this.aard.settings.active.aard.aardType}

${this.generateRawTimes(this.aard.timer.current)}
Stage times (not cumulative):
Current:
${this.generateMiniGraphBar(this.aard.timer.current, true)}
${this.generateRawTimes(this.aard.timer.average)}
Stage times (not cumulative):
Average:
${this.generateMiniGraphBar(this.aard.timer.average, true)}
${this.generateRawTimes(this.aard.timer.lastChange)}
Last change:
${this.generateMiniGraphBar(this.aard.timer.lastChange, true)}
` 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 `
${label}
`; } private generateRawTimes(timer) { return ` Raw times (cumulative; -1 = test was skipped):
draw ${timer.draw.toFixed(2)}ms get data ${timer.getImage.toFixed(2)}ms black lv. ${timer.fastBlackLevel.toFixed(2)}ms guard/image ${timer.guardLine.toFixed(3)}ms edge ${timer.edgeScan.toFixed(2)}ms gradient ${timer.gradient.toFixed(3)}ms post ${timer.scanResults.toFixed(2)}ms subtitle ${timer.subtitleScan.toFixed(2)}ms `; } 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; const guardLine = (perf.guardLine !== undefined && perf.guardLine !== -1) ? Math.max(perf.guardLine - total, 0) : 0; total += guardLine; const edgeScanStart = guardLineStart + guardLine; const edgeScan = (perf.edgeScan !== undefined && perf.edgeScan !== -1) ? Math.max(perf.edgeScan - total, 0) : 0; total += edgeScan; const gradientStart = edgeScanStart + edgeScan; const gradient = (perf.gradient !== undefined && perf.gradient !== -1) ? Math.max(perf.gradient - total, 0) : 0; total += gradient; const scanResultsStart = gradientStart + gradient; const scanResults = (perf.scanResults !== undefined && perf.scanResults !== -1) ? Math.max(perf.scanResults - total, 0) : 0; total += scanResults; const subtitleScanStart = scanResultsStart + scanResults; const subtitleScan = Math.max(perf.subtitleScan - total, 0); total += subtitleScan; return `
${detailed ? '' : `${total.toFixed()} ms`}
${detailed ? `
` : ''}
${this.getBarLabel(draw, 0, 2, `draw: ${draw.toFixed(2)} ms`, detailed)}
${this.getBarLabel(getImage, getImageStart, 14, `get data: ${getImage.toFixed(2)} ms`, detailed)}
${this.getBarLabel(fastBlackLevel, fastBlackLevelStart, 26, `black level: ${fastBlackLevel.toFixed(2)} ms`, detailed)};
${this.getBarLabel(guardLine, guardLineStart, 38, `guard/image line: ${guardLine.toFixed(2)} ms`, detailed)}
${this.getBarLabel(edgeScan, edgeScanStart, 50, `edge scan (/w validation): ${edgeScan.toFixed(2)} ms`, detailed)}
${this.getBarLabel(gradient, gradientStart, 62, `gradient: ${gradient.toFixed(2)} ms`, detailed)}
${this.getBarLabel(scanResults, scanResultsStart, 74, `scan results processing: ${scanResults.toFixed(2)} ms`, detailed)}
${this.getBarLabel(subtitleScan, subtitleScanStart, 86, `subtitle scan: ${subtitleScan.toFixed(2)} ms`, detailed)} ${this.getBarLabel(0, subtitleScan + subtitleScanStart, 98, `total: ${total.toFixed(2)} ms`, detailed, 'color: #fff;')}
60fps
30fps
`; } _lastAr: undefined; updateTestResults(testResults, timers) { this.updatePerformanceResults(); if (testResults.aspectRatioUpdated && this.pauseOnArCheck) { (this.aard as any).video.pause(); this.aard.stop(); } const resultsDiv = document.getElementById('uw-aard-results'); const ar = testResults.activeAspectRatio.toFixed(3); let out = ` LAST STAGE: ${testResults.lastStage} | black level: ${testResults.blackLevel}, threshold: ${testResults.blackThreshold} -- ASPECT RATIO Active: ${ar}, changed since last check? ${testResults.aspectRatioUpdated} letterbox width: ${testResults.letterboxWidth} offset ${testResults.letterboxOffset}
(last: ${this._lastAr}) Paused until? ${Date.now() < timers.pauseUntil ? ((timers.pauseUntil - Date.now()) / 1000) + 's' : 'not paused'}; now: ${Date.now()}ms; until:${timers.pauseUntil}ms; diff: ${(+timers.pauseUntil - Date.now())} image in black level probe (aka "not letterbox"): ${testResults.notLetterbox} `; this._lastAr = ar; resultsDiv.innerHTML = out; } 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' : ''; } }