mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
fix(ui): disable modal backdrop blur under software rendering (#1092)
With hardware acceleration disabled, Chrome rasterizes in software and a full-viewport backdrop-filter forces a per-frame CPU blur over everything behind the modal, freezing the whole browser. Detect software rendering via the unmasked WebGL renderer string at app startup and drop the backdrop blur in that case. Also route the download modal's sticky toolbar through the shared --modal-backdrop-blur variable instead of a hardcoded blur(8px).
This commit is contained in:
@@ -13,6 +13,16 @@
|
|||||||
overflow: auto; /* Change from hidden to auto to allow scrolling */
|
overflow: auto; /* Change from hidden to auto to allow scrolling */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Software-rendering fallback (set by applyModalBackdropBlurPolicy): a
|
||||||
|
full-viewport backdrop-filter forces per-frame CPU rasterization of
|
||||||
|
everything behind the modal and freezes the browser (issue #1092) */
|
||||||
|
html.no-modal-backdrop-blur .modal,
|
||||||
|
html.no-modal-backdrop-blur .delete-modal,
|
||||||
|
html.no-modal-backdrop-blur .batch-preview-select-all {
|
||||||
|
backdrop-filter: none;
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prevent body scroll when modal is open */
|
/* Prevent body scroll when modal is open */
|
||||||
body.modal-open {
|
body.modal-open {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -921,8 +921,8 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(var(--modal-backdrop-blur, 6px));
|
||||||
-webkit-backdrop-filter: blur(8px);
|
-webkit-backdrop-filter: blur(var(--modal-backdrop-blur, 6px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.batch-preview-select-all input[type="checkbox"] {
|
.batch-preview-select-all input[type="checkbox"] {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { helpManager } from './managers/HelpManager.js';
|
|||||||
import { doctorManager } from './managers/DoctorManager.js';
|
import { doctorManager } from './managers/DoctorManager.js';
|
||||||
import { bannerService } from './managers/BannerService.js';
|
import { bannerService } from './managers/BannerService.js';
|
||||||
import { initTheme, initBackToTop } from './utils/uiHelpers.js';
|
import { initTheme, initBackToTop } from './utils/uiHelpers.js';
|
||||||
|
import { applyModalBackdropBlurPolicy } from './utils/renderingCapability.js';
|
||||||
import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
|
import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
|
||||||
import { i18n } from './i18n/index.js';
|
import { i18n } from './i18n/index.js';
|
||||||
import { onboardingManager } from './managers/OnboardingManager.js';
|
import { onboardingManager } from './managers/OnboardingManager.js';
|
||||||
@@ -34,6 +35,10 @@ export class AppCore {
|
|||||||
|
|
||||||
console.log('AppCore: Initializing...');
|
console.log('AppCore: Initializing...');
|
||||||
|
|
||||||
|
// Disable full-viewport backdrop blur under software rendering before
|
||||||
|
// anything can open a modal (issue #1092)
|
||||||
|
applyModalBackdropBlurPolicy();
|
||||||
|
|
||||||
// Initialize i18n first
|
// Initialize i18n first
|
||||||
window.i18n = i18n;
|
window.i18n = i18n;
|
||||||
// Wait for i18n to be ready
|
// Wait for i18n to be ready
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Software-rendering detection for degrading expensive visual effects.
|
||||||
|
*
|
||||||
|
* With hardware acceleration disabled (or a GPU blocklisted), Chrome rasterizes
|
||||||
|
* in software. A full-viewport `backdrop-filter: blur()` then forces a per-frame
|
||||||
|
* CPU blur over everything painted behind the modal, freezing the entire
|
||||||
|
* browser (issue #1092). When software rendering is detected we add the
|
||||||
|
* `no-modal-backdrop-blur` class to <html>, and CSS drops the backdrop blur.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SOFTWARE_RENDERER_PATTERN = /swiftshader|llvmpipe|softpipe|software|basic render/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check a WebGL renderer string against known software rasterizers.
|
||||||
|
* @param {string} renderer - UNMASKED_RENDERER_WEBGL string
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isSoftwareRendererString(renderer) {
|
||||||
|
return SOFTWARE_RENDERER_PATTERN.test(renderer || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the unmasked WebGL renderer string, or null when unavailable/masked.
|
||||||
|
* @returns {string|null}
|
||||||
|
*/
|
||||||
|
function getWebGLRendererString() {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
||||||
|
if (!gl) return null;
|
||||||
|
|
||||||
|
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
||||||
|
const renderer = debugInfo
|
||||||
|
? String(gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || '')
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const loseContext = gl.getExtension('WEBGL_lose_context');
|
||||||
|
if (loseContext) loseContext.loseContext();
|
||||||
|
|
||||||
|
return renderer || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heuristic: is the browser rasterizing in software?
|
||||||
|
* - No WebGL at all: no evidence of GPU acceleration, assume software.
|
||||||
|
* - Masked renderer string or detection failure: cannot tell, keep effects on.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isSoftwareRendering() {
|
||||||
|
try {
|
||||||
|
const renderer = getWebGLRendererString();
|
||||||
|
if (renderer === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return isSoftwareRendererString(renderer);
|
||||||
|
} catch (error) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the blur-disabling class on <html>. Runs once at app startup.
|
||||||
|
* @param {boolean} [isSoftware] - Override for tests; defaults to detection.
|
||||||
|
*/
|
||||||
|
export function applyModalBackdropBlurPolicy(isSoftware = isSoftwareRendering()) {
|
||||||
|
document.documentElement.classList.toggle('no-modal-backdrop-blur', isSoftware);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
|
import {
|
||||||
|
isSoftwareRendererString,
|
||||||
|
applyModalBackdropBlurPolicy,
|
||||||
|
} from '../../../static/js/utils/renderingCapability.js';
|
||||||
|
|
||||||
|
describe('isSoftwareRendererString', () => {
|
||||||
|
it('detects SwiftShader (Chrome with hardware acceleration disabled)', () => {
|
||||||
|
expect(isSoftwareRendererString(
|
||||||
|
'WebKit WebGL SwiftShader'
|
||||||
|
)).toBe(true);
|
||||||
|
expect(isSoftwareRendererString(
|
||||||
|
'ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)'
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects Mesa software rasterizers (Linux)', () => {
|
||||||
|
expect(isSoftwareRendererString('llvmpipe (LLVM 17.0.6, 256 bits)')).toBe(true);
|
||||||
|
expect(isSoftwareRendererString('softpipe')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects generic software renderer strings', () => {
|
||||||
|
expect(isSoftwareRendererString('Software Renderer')).toBe(true);
|
||||||
|
expect(isSoftwareRendererString('Microsoft Basic Render Driver')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts hardware GPU strings', () => {
|
||||||
|
expect(isSoftwareRendererString(
|
||||||
|
'ANGLE (NVIDIA, NVIDIA GeForce RTX 4090 Direct3D11 vs_5_0 ps_5_0, D3D11)'
|
||||||
|
)).toBe(false);
|
||||||
|
expect(isSoftwareRendererString(
|
||||||
|
'ANGLE (AMD, AMD Radeon RX 7900 XTX (0x0000744C) Direct3D11 vs_5_0 ps_5_0, D3D11)'
|
||||||
|
)).toBe(false);
|
||||||
|
expect(isSoftwareRendererString('Apple M4 Pro')).toBe(false);
|
||||||
|
expect(isSoftwareRendererString('Mesa Intel(R) UHD Graphics 620 (KBL GT2)')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty input', () => {
|
||||||
|
expect(isSoftwareRendererString('')).toBe(false);
|
||||||
|
expect(isSoftwareRendererString(null)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('applyModalBackdropBlurPolicy', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
document.documentElement.classList.remove('no-modal-backdrop-blur');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds the disabling class under software rendering', () => {
|
||||||
|
applyModalBackdropBlurPolicy(true);
|
||||||
|
expect(document.documentElement.classList.contains('no-modal-backdrop-blur')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes the disabling class under hardware rendering', () => {
|
||||||
|
document.documentElement.classList.add('no-modal-backdrop-blur');
|
||||||
|
applyModalBackdropBlurPolicy(false);
|
||||||
|
expect(document.documentElement.classList.contains('no-modal-backdrop-blur')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user