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.
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
<!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>
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Performance optimizations for renderer CSS - GPU Error 18 compatible */
|
||||
|
||||
/* Conservative hardware acceleration for animations */
|
||||
.tab, .bookmark, .icon-item {
|
||||
/* Only enable will-change when actually needed */
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.tab:hover, .bookmark:hover, .icon-item:hover {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.tab:not(:hover), .bookmark:not(:hover), .icon-item:not(:hover) {
|
||||
will-change: auto;
|
||||
}
|
||||
|
||||
/* Optimize scrolling - more conservative approach */
|
||||
#webviews, #bookmarkList, #iconGrid {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
/* Use layout containment only, avoid paint containment which can cause GPU issues */
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
/* Use CSS containment for better performance - conservative approach */
|
||||
.tab-content {
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
/* Optimize transitions - reduced complexity */
|
||||
.tab {
|
||||
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Reduce paint areas - more conservative transforms */
|
||||
.tab:hover, .bookmark:hover {
|
||||
transform: scale(1.01); /* Reduced scale to minimize GPU load */
|
||||
}
|
||||
|
||||
/* Use efficient selectors */
|
||||
.material-symbols-outlined {
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Optimize text rendering - conservative settings */
|
||||
body {
|
||||
text-rendering: optimizeSpeed;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* Conditional subpixel rendering for retina displays */
|
||||
@media (-webkit-min-device-pixel-ratio: 2) {
|
||||
body {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
}
|
||||
|
||||
/* Additional GPU-safe optimizations */
|
||||
* {
|
||||
/* Prevent unnecessary repaints */
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* Safe animation performance */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
Reference in New Issue
Block a user