Files
NebulaBrowser/renderer/gpu-diagnostics.html
T
andrew fbd9ba8a1b Add GPU error handling and performance optimizations
Introduces a comprehensive GPU configuration and fallback system to resolve GPU process launch failures (Error 18), including new modules for GPU management and performance monitoring. Adds a GPU diagnostics HTML page, optimized CSS for rendering, and a diagnostic startup script. Updates main and preload scripts for improved stability, async file operations, and enhanced API exposure. Site history and bookmarks handling are optimized for performance and reliability.
2025-07-26 14:38:05 +12:00

216 lines
7.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>GPU Diagnostics - Nebula Browser</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
}
.status.good { background: #d4edda; color: #155724; }
.status.warning { background: #fff3cd; color: #856404; }
.status.error { background: #f8d7da; color: #721c24; }
button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}
button:hover { background: #0056b3; }
pre {
background: #f8f9fa;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
font-size: 12px;
}
.canvas-test {
border: 1px solid #ccc;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>GPU Diagnostics</h1>
<div id="gpu-status" class="status">
<h3>GPU Status</h3>
<p>Loading GPU information...</p>
</div>
<div class="status">
<h3>WebGL Test</h3>
<canvas id="webgl-canvas" class="canvas-test" width="300" height="150"></canvas>
<p id="webgl-status">Testing WebGL...</p>
</div>
<div class="status">
<h3>Canvas 2D Acceleration Test</h3>
<canvas id="canvas2d" class="canvas-test" width="300" height="150"></canvas>
<p id="canvas2d-status">Testing Canvas 2D...</p>
</div>
<div>
<h3>Actions</h3>
<button onclick="refreshGPUInfo()">Refresh GPU Info</button>
<button onclick="forceGC()">Force Garbage Collection</button>
<button onclick="applyFallback(1)">Apply GPU Fallback Level 1</button>
<button onclick="applyFallback(2)">Apply GPU Fallback Level 2</button>
</div>
<div>
<h3>Detailed GPU Information</h3>
<pre id="gpu-details">Loading...</pre>
</div>
</div>
<script>
async function refreshGPUInfo() {
try {
const gpuInfo = await window.electronAPI.invoke('get-gpu-info');
const statusDiv = document.getElementById('gpu-status');
const detailsDiv = document.getElementById('gpu-details');
if (gpuInfo.error) {
statusDiv.className = 'status error';
statusDiv.innerHTML = `<h3>GPU Status</h3><p>Error: ${gpuInfo.error}</p>`;
} else {
const isGPUWorking = checkGPUFeatures(gpuInfo.featureStatus);
statusDiv.className = `status ${isGPUWorking ? 'good' : 'warning'}`;
statusDiv.innerHTML = `
<h3>GPU Status</h3>
<p><strong>Hardware Acceleration:</strong> ${isGPUWorking ? 'Enabled' : 'Disabled/Limited'}</p>
<p><strong>Fallback Level:</strong> ${gpuInfo.fallbackStatus?.fallbackLevel || 0}</p>
<p><strong>GPU Enabled:</strong> ${gpuInfo.fallbackStatus?.gpuEnabled ? 'Yes' : 'No'}</p>
`;
}
detailsDiv.textContent = JSON.stringify(gpuInfo, null, 2);
} catch (err) {
console.error('Failed to get GPU info:', err);
document.getElementById('gpu-status').innerHTML = `<h3>GPU Status</h3><p>Error: ${err.message}</p>`;
}
}
function checkGPUFeatures(features) {
const criticalFeatures = ['gpu_compositing', 'webgl', 'webgl2'];
return criticalFeatures.some(feature =>
features[feature] && !features[feature].includes('disabled')
);
}
async function forceGC() {
try {
await window.electronAPI.invoke('force-gc');
alert('Garbage collection completed');
} catch (err) {
alert('Failed to force GC: ' + err.message);
}
}
async function applyFallback(level) {
try {
const result = await window.electronAPI.invoke('apply-gpu-fallback', level);
if (result.success) {
alert(`Applied GPU fallback level ${level}. App restart may be required.`);
} else {
alert('Failed to apply fallback: ' + result.error);
}
} catch (err) {
alert('Failed to apply fallback: ' + err.message);
}
}
// Test WebGL
function testWebGL() {
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
const status = document.getElementById('webgl-status');
if (gl) {
// Draw a simple triangle
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
precision mediump float;
void main() {
gl_Color = vec4(0.0, 1.0, 0.0, 1.0);
}
`);
gl.compileShader(fragmentShader);
status.textContent = 'WebGL: Available ✓';
status.parentElement.className = 'status good';
// Clear with green color to show it's working
gl.clearColor(0.0, 0.8, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
} else {
status.textContent = 'WebGL: Not Available ✗';
status.parentElement.className = 'status error';
}
}
// Test Canvas 2D
function testCanvas2D() {
const canvas = document.getElementById('canvas2d');
const ctx = canvas.getContext('2d');
const status = document.getElementById('canvas2d-status');
try {
// Draw some graphics to test acceleration
const gradient = ctx.createLinearGradient(0, 0, 300, 0);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(1, '#0000ff');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 300, 150);
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText('Canvas 2D Working!', 50, 80);
status.textContent = 'Canvas 2D: Working ✓';
status.parentElement.className = 'status good';
} catch (err) {
status.textContent = 'Canvas 2D: Error - ' + err.message;
status.parentElement.className = 'status error';
}
}
// Initialize tests
window.addEventListener('DOMContentLoaded', () => {
refreshGPUInfo();
testWebGL();
testCanvas2D();
});
</script>
</body>
</html>