WebGL (Shaders优化工具)

全栈WebGL性能优化(含WASM加速、智能LOD、动态批处理)

// ==UserScript==
// @name         WebGL (Shaders优化工具)
// @namespace    http://tampermonkey.net/
// @version      2.1.9
// @description  全栈WebGL性能优化(含WASM加速、智能LOD、动态批处理)
// @author       KiwiFruit
// @match        *://*/*
// @license      MIT
// @grant        GM.addStyle
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.xmlHttpRequest
// @grant        GM.getResourceUrl
// @connect      wasm-optimizer.example.com
// @resource     APIKEY https://yourdomain.com/apikey.txt
// @resource     optimizer.wasm https://wasm-optimizer.example.com/optimizer.wasm
// ==/UserScript==

(function() {
    'use strict';
    /* global OctreeNode,options,DynamicBatcher */

    // 核心常量
    const CONSTANTS = {
        MAX_TEXTURE_SIZE: 2048,
        DEFAULT_LOD_LEVELS: 4,
        WASM_CHUNK_SIZE: 512 * 1024,
        PLUGIN_PREFIX: 'wgo_',
        CORS_HEADERS: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + GM.getResourceText('APIKEY')
        }
    };

    // WebGL上下文检测
    function createContext(canvas, options) {
        const versions = [
            { version: 2, context: 'webgl2', extensions: ['EXT_color_buffer_float'] },
            { version: 1, context: 'webgl', extensions: ['OES_texture_float'] }
        ];
        for (const config of versions) {
            try {
                const gl = canvas.getContext(config.context, {
                    antialias: true,
                    depth: true,
                    stencil: true,
                    preserveDrawingBuffer: false
                });
                if (gl) {
                    return {
                        gl,
                        version: config.version,
                        extensions: getSupportedExtensions(gl, config.extensions)
                    };
                }
            } catch (e) {}
        }
        throw new Error('No WebGL context available');
    }

    // 扩展支持检测
    function getSupportedExtensions(gl, required) {
        return required.filter(ext => gl.getExtension(ext));
    }

    // 核心优化器类
    class WebGLOptimizer {
        constructor() {
            this.config = this.loadConfig();
            this.glContext = null;
            this.wasmModule = null;
            this.stats = {
                frameTime: 0,
                drawCalls: 0,
                memoryUsage: 0,
                lodChanges: 0
            };
            this.sceneGraph = null;
            this.uiManager = null;
            this.resourceLoader = null;
            this.extensionManager = null;
        }

        // 配置加载系统
        async loadConfig() {
            const defaults = {
                lodStrategy: 'distance',
                batchThreshold: 50,
                textureQuality: 0.75,
                maxDrawDistance: 1000,
                pluginEnabled: []
            };
            return {
                ...defaults,
                ...(await GM.getValue('webgl_config', defaults))
            };
        }

        // WASM加载优化
        async loadWASM() {
            const importObject = {
                env: {
                    memory: new WebAssembly.Memory({ initial: 256 }),
                    _log: console.log.bind(console),
                    _error: console.error.bind(console)
                }
            };
            const wasmCode = await GM.getResourceText('optimizer.wasm');
            this.wasmModule = await WebAssembly.instantiate(
                new Uint8Array(wasmCode),
                importObject
            );
        }

        // 性能监控
        initPerformanceMonitor() {
            this.statsMonitor = new PerformanceMonitor({
                updateFrequency: 30,
                metrics: ['fps', 'memory', 'drawcalls'],
                uiContainer: document.createElement('div')
            });
            // 内存泄漏检测
            setInterval(() => {
                const used = performance.memory.usedJSHeapSize;
                const limit = performance.memory.jsHeapSizeLimit;
                if (used > limit * 0.85) {
                    this.triggerGC();
                }
            }, 60000);
        }

        // 资源加载系统
        async initResourceLoader() {
            this.resourceLoader = new ResourceLoader({
                maxConcurrency: navigator.hardwareConcurrency || 4,
                cacheStrategy: 'lru',
                maxCacheSize: 1024 * 1024 * 128 // 128MB
            });
            // 预加载核心资源
            await Promise.all([
                this.resourceLoader.loadShader('vertex', '/shaders/vert.glsl'),
                this.resourceLoader.loadShader('fragment', '/shaders/frag.glsl'),
                this.resourceLoader.loadModel('octree', '/models/octree.gltf')
            ]);
        }

        // 场景优化核心
        optimizeScene(sceneData) {
            const optimized = {
                meshes: this.applyBatching(sceneData.meshes),
                textures: this.optimizeTextures(sceneData.textures),
                lights: this.optimizeLights(sceneData.lights),
                camera: sceneData.camera
            };
            // 空间分割优化
            this.sceneGraph = new OctreeSpacePartitioning({
                root: optimized.meshes,
                maxDepth: this.config.lodLevels,
                splitThreshold: 8
            });
            return optimized;
        }

        // 动态批处理算法
        applyBatching(meshes) {
            const batches = new DynamicBatcher({
                maxVertices: 65536,
                maxIndices: 32768,
                materialThreshold: 0.95
            }).processMeshes(meshes);
            // 批处理优化统计
            this.stats.drawCalls = meshes.length;
            this.stats.lodChanges = 0;
            return batches;
        }

        // 纹理优化系统
        optimizeTextures(textures) {
            return textures.map(tex => ({
                ...tex,
                mipmaps: this.generateMipmaps(tex.data),
                format: this.selectFormat(tex.type),
                compression: this.config.textureQuality > 0.8 ? 'BC7' : 'BC3'
            }));
        }

        // 格式选择算法
        selectFormat(type) {
            const formatMap = {
                'float': WebGL2RenderingContext.RG32F,
                'int': WebGL2RenderingContext.RGBA8UI,
                'uint': WebGL2RenderingContext.RGBA8UI,
                'default': WebGL2RenderingContext.RGBA
            };
            return formatMap[type] || formatMap.default;
        }

        // 错误处理系统
        handleError(stage, error) {
            const handler = this.errorHandlers[stage] || this.defaultErrorHandler;
            handler(error);
            // 严重错误处理
            if (error.severity === 'critical') {
                this.triggerFallbackMode();
            }
        }

        // 回退模式
        triggerFallbackMode() {
            this.config.lodStrategy = 'none';
            this.config.batchThreshold = 20;
            this.resourceLoader.clearCache();
            this.statsMonitor.triggerWarning('Fallback mode activated');
        }

        // 插件系统
        loadPlugin(name) {
            const plugin = GM.getResourceText(`${CONSTANTS.PLUGIN_PREFIX}${name}`);
            const module = new Function('return ' + plugin)();
            return new module.PluginAPI(this);
        }

        // 内存管理
        async releaseResources() {
            if (this.wasmModule) {
                this.wasmModule.instance.exports._free();
                this.wasmModule = null;
            }
            this.resourceLoader.clearCache();
            this.glContext.gl?.deleteProgram(this.shaderProgram);
        }
    }

    // 性能监控组件
    class PerformanceMonitor {
        constructor(options) {
            this.options = options;
            this.metrics = new Map();
            this.uiElement = document.createElement('div');
            this.initUI();
        }

        initUI() {
            this.uiElement.style.cssText = `
                position: fixed;
                top: 10px;
                right: 10px;
                background: rgba(0,0,0,0.8);
                color: white;
                padding: 10px;
                border-radius: 5px;
                z-index: 9999;
            `;
            document.body.appendChild(this.uiElement);
        }

        updateMetrics() {
            const now = performance.now();
            const frameTime = (now - this.lastFrame) || 16;
            this.metrics.set('fps', 1000 / frameTime);
            // 内存采样
            const mem = performance.memory;
            this.metrics.set('memory', (mem.usedJSHeapSize / 1024 / 1024).toFixed(1));
            // 绘制调用统计
            this.metrics.set('drawcalls', this.glContext?.gl?.getParameter(WebGL2RenderingContext.DRAW_CALLS) || 0);
            this.lastFrame = now;
            this.renderUI();
        }

        renderUI() {
            let html = '<div style="font-family: monospace">';
            this.metrics.forEach((value, key) => {
                html += `<div>${key}: ${value}</div>`;
            });
            html += '</div>';
            this.uiElement.innerHTML = html;
        }
    }

    // 资源加载器
    class ResourceLoader {
        constructor(options) {
            this.options = options;
            this.queue = [];
            this.activeLoads = 0;
            this.cache = new Map();
        }

        async loadShader(type, url) {
            const response = await fetch(url);
            const shaderSource = await response.text();
            return this.compileShader(type, shaderSource);
        }

        compileShader(type, source) {
            const gl = this.optimizer.glContext.gl;
            const shader = gl.createShader(type === 'vertex' ?
                gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                throw new Error(gl.getShaderInfoLog(shader));
            }
            return shader;
        }

        // 批量加载
        async loadBatch(urls) {
            return Promise.all(urls.map(url =>
                fetch(url).then(res => res.arrayBuffer())
            ));
        }
    }

    // 空间分割系统
    class OctreeSpacePartitioning {
        constructor(options) {
            this.root = this.buildOctree(options.root, 0, options.maxDepth);
            this.bounds = this.calculateBounds(options.root);
        }

        buildOctree(nodes, depth, maxDepth) {
            if (depth >= maxDepth || nodes.length < options.splitThreshold) {
                return new OctreeNode(nodes, this.bounds);
            }
            const center = this.calculateCenter(this.bounds);
            const children = [];
            for (let i = 0; i < 8; i++) {
                const childBounds = this.createChildBounds(center, i);
                const childNodes = nodes.filter(node =>
                    this.isInsideBounds(node.position, childBounds)
                );
                children.push(this.buildOctree(childNodes, depth + 1, maxDepth));
            }
            return new OctreeNode(children, this.bounds);
        }
    }

    // 初始化流程
    const canvas = document.createElement('canvas');
    const optimizer = new WebGLOptimizer();

    // 异步初始化
    (async () => {
        try {
            const context = createContext(canvas, {
                version: 2,
                extensions: ['EXT_color_buffer_float']
            });
            optimizer.glContext = context;
            await optimizer.loadWASM();
            await optimizer.initResourceLoader();
            optimizer.initPerformanceMonitor();

            // 事件监听
            window.addEventListener('resize', () => {
                optimizer.glContext.gl.viewport(0, 0, canvas.width, canvas.height);
            });

            // 首次场景渲染
            const sampleScene = await fetch('/sample_scene.json').then(res => res.json());
            optimizer.optimizeScene(sampleScene);
        } catch (error) {
            optimizer.handleError('init', error);
        }
    })();
})();