�?4.1章:WebGL兼容性技�?

WebGL作为Web平台的图形API,在不同浏览器和设备上存在兼容性差异。本教程将深入讲解如何处理WebGL兼容性问题,确保着色器在各种环境中正常运行�?

🎯 学习目标

  • 理解WebGL版本差异和兼容性问�?- 掌握跨浏览器着色器适配技�?- 学会处理不同GPU厂商的兼容性差�?- 了解WebGL扩展的检测和使用方法

📋 前置知识

  • 熟悉WebGL基础概念
  • 理解GLSL着色器语言
  • 掌握浏览器开发工具使�?

🌐 WebGL版本兼容�?

WebGL 1.0 vs WebGL 2.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// WebGL兼容性检测器
class WebGLCompatibilityDetector {
private canvas: HTMLCanvasElement;
private supportInfo: WebGLSupportInfo;

interface WebGLSupportInfo {
webgl1: boolean;
webgl2: boolean;
version: string;
vendor: string;
renderer: string;
extensions: string[];
maxTextureSize: number;
maxCubeMapSize: number;
maxVertexUniforms: number;
maxFragmentUniforms: number;
maxVaryingVectors: number;
maxVertexAttributes: number;
maxTextureUnits: number;
precision: {
vertexShader: PrecisionInfo;
fragmentShader: PrecisionInfo;
};
}

interface PrecisionInfo {
highpFloat: boolean;
mediumpFloat: boolean;
lowpFloat: boolean;
highpInt: boolean;
mediumpInt: boolean;
lowpInt: boolean;
}

constructor() {
this.canvas = document.createElement('canvas');
this.detectWebGLSupport();
}

private detectWebGLSupport(): void {
console.log('🔍 检测WebGL支持情况...');

// 检测WebGL 1.0
let gl1: WebGLRenderingContext | null = null;
try {
gl1 = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl') as WebGLRenderingContext;
} catch (e) {
console.warn('WebGL 1.0 获取失败:', e);
}

// 检测WebGL 2.0
let gl2: WebGL2RenderingContext | null = null;
try {
gl2 = this.canvas.getContext('webgl2') as WebGL2RenderingContext;
} catch (e) {
console.warn('WebGL 2.0 获取失败:', e);
}

const gl = gl2 || gl1;
if (!gl) {
this.supportInfo = this.getUnsupportedInfo();
return;
}

this.supportInfo = {
webgl1: !!gl1,
webgl2: !!gl2,
version: gl.getParameter(gl.VERSION),
vendor: gl.getParameter(gl.VENDOR),
renderer: gl.getParameter(gl.RENDERER),
extensions: gl.getSupportedExtensions() || [],
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxCubeMapSize: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE),
maxVertexUniforms: gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS),
maxFragmentUniforms: gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS),
maxVaryingVectors: gl.getParameter(gl.MAX_VARYING_VECTORS),
maxVertexAttributes: gl.getParameter(gl.MAX_VERTEX_ATTRIBS),
maxTextureUnits: gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS),
precision: this.detectPrecisionSupport(gl)
};

console.log('�?WebGL检测完�?', this.supportInfo);
}

private detectPrecisionSupport(gl: WebGLRenderingContext | WebGL2RenderingContext): { vertexShader: PrecisionInfo; fragmentShader: PrecisionInfo; } {
const checkPrecision = (shaderType: number): PrecisionInfo => {
return {
highpFloat: gl.getShaderPrecisionFormat(shaderType, gl.HIGH_FLOAT)?.precision > 0,
mediumpFloat: gl.getShaderPrecisionFormat(shaderType, gl.MEDIUM_FLOAT)?.precision > 0,
lowpFloat: gl.getShaderPrecisionFormat(shaderType, gl.LOW_FLOAT)?.precision > 0,
highpInt: gl.getShaderPrecisionFormat(shaderType, gl.HIGH_INT)?.precision > 0,
mediumpInt: gl.getShaderPrecisionFormat(shaderType, gl.MEDIUM_INT)?.precision > 0,
lowpInt: gl.getShaderPrecisionFormat(shaderType, gl.LOW_INT)?.precision > 0
};
};

return {
vertexShader: checkPrecision(gl.VERTEX_SHADER),
fragmentShader: checkPrecision(gl.FRAGMENT_SHADER)
};
}

public generateCompatibilityReport(): string {
const info = this.supportInfo;
let report = '📊 WebGL兼容性报告\n';
report += '=' * 50 + '\n';
report += `WebGL 1.0 支持: ${info.webgl1 ? '�? : '�?}\n`;
report += `WebGL 2.0 支持: ${info.webgl2 ? '�? : '�?}\n`;
report += `版本: ${info.version}\n`;
report += `厂商: ${info.vendor}\n`;
report += `渲染�? ${info.renderer}\n`;
report += `\n📐 限制信息:\n`;
report += `最大纹理尺�? ${info.maxTextureSize}x${info.maxTextureSize}\n`;
report += `最大立方体贴图尺寸: ${info.maxCubeMapSize}x${info.maxCubeMapSize}\n`;
report += `顶点着色器最大Uniform�? ${info.maxVertexUniforms}\n`;
report += `片段着色器最大Uniform�? ${info.maxFragmentUniforms}\n`;
report += `最大Varying�? ${info.maxVaryingVectors}\n`;
report += `最大顶点属性数: ${info.maxVertexAttributes}\n`;
report += `最大纹理单元数: ${info.maxTextureUnits}\n`;

report += `\n🎯 精度支持:\n`;
report += `片段着色器highp: ${info.precision.fragmentShader.highpFloat ? '�? : '�?}\n`;
report += `片段着色器mediump: ${info.precision.fragmentShader.mediumpFloat ? '�? : '�?}\n`;

report += `\n🔌 扩展支持: (${info.extensions.length}�?\n`;
info.extensions.slice(0, 10).forEach(ext => {
report += ` - ${ext}\n`;
});
if (info.extensions.length > 10) {
report += ` ... 还有${info.extensions.length - 10}个扩展\n`;
}

return report;
}

public getRecommendedShaderVersion(): 'webgl1' | 'webgl2' | 'unsupported' {
if (this.supportInfo.webgl2) return 'webgl2';
if (this.supportInfo.webgl1) return 'webgl1';
return 'unsupported';
}

public hasExtension(extensionName: string): boolean {
return this.supportInfo.extensions.includes(extensionName);
}
}

GLSL版本适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// WebGL兼容性着色器宏定�?#define WEBGL1_COMPAT 1
#define WEBGL2_COMPAT 1

// WebGL 1.0兼容性宏
#if WEBGL1_COMPAT
#define PRECISION_HIGH highp
#define PRECISION_MEDIUM mediump
#define PRECISION_LOW lowp

// WebGL 1.0不支持这些功能,提供fallback
#define texture texture2D
#define textureLod texture2DLodEXT

// 精度声明
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif

// 扩展声明
#extension GL_OES_standard_derivatives : enable
#extension GL_EXT_shader_texture_lod : enable
#extension GL_EXT_frag_depth : enable

// 输入输出声明
#define in attribute
#define out varying
#define VARYING varying
#define FRAG_COLOR gl_FragColor

// 布局限定符不支持
#define layout(x)
#endif

// WebGL 2.0兼容性宏
#if WEBGL2_COMPAT
#version 300 es
precision highp float;

// WebGL 2.0支持现代GLSL
#define VARYING in
#define FRAG_COLOR fragColor

// 输出声明
out vec4 fragColor;
#endif

// 跨版本兼容的工具函数
vec4 compatTexture(sampler2D tex, vec2 uv) {
#if WEBGL2_COMPAT
return texture(tex, uv);
#else
return texture2D(tex, uv);
#endif
}

vec4 compatTextureLod(sampler2D tex, vec2 uv, float lod) {
#if WEBGL2_COMPAT
return textureLod(tex, uv, lod);
#else
#ifdef GL_EXT_shader_texture_lod
return texture2DLodEXT(tex, uv, lod);
#else
return texture2D(tex, uv); // fallback,忽略LOD
#endif
#endif
}

// 导数函数兼容�?float compatDFdx(float value) {
#ifdef GL_OES_standard_derivatives
return dFdx(value);
#else
return 0.0; // fallback
#endif
}

float compatDFdy(float value) {
#ifdef GL_OES_standard_derivatives
return dFdy(value);
#else
return 0.0; // fallback
#endif
}

// 深度写入兼容�?void compatSetFragDepth(float depth) {
#if WEBGL2_COMPAT
gl_FragDepth = depth;
#else
#ifdef GL_EXT_frag_depth
gl_FragDepthEXT = depth;
#endif
// 如果不支持,则无法设置深�? #endif
}

🔧 浏览器特定适配

Chrome/Chromium适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Chrome浏览器特定优�?class ChromeWebGLOptimizer {
private gl: WebGLRenderingContext | WebGL2RenderingContext;

constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) {
this.gl = gl;
this.applyChromiumOptimizations();
}

private applyChromiumOptimizations(): void {
// Chrome的ANGLE驱动优化
if (this.isChromiumBased()) {
console.log('🔧 应用Chromium优化...');

// 1. 使用ANGLE的优化提�? this.enableANGLEOptimizations();

// 2. 纹理格式优化
this.optimizeTextureFormats();

// 3. 着色器编译优化
this.optimizeShaderCompilation();
}
}

private isChromiumBased(): boolean {
const renderer = this.gl.getParameter(this.gl.RENDERER).toLowerCase();
return renderer.includes('angle') ||
renderer.includes('chrome') ||
renderer.includes('chromium');
}

private enableANGLEOptimizations(): void {
// ANGLE特定的扩�? const angleExtensions = [
'ANGLE_instanced_arrays',
'ANGLE_depth_texture',
'ANGLE_texture_compression_dxt1',
'ANGLE_texture_compression_dxt3',
'ANGLE_texture_compression_dxt5'
];

angleExtensions.forEach(ext => {
if (this.hasExtension(ext)) {
console.log(`�?启用ANGLE扩展: ${ext}`);
}
});
}

private optimizeTextureFormats(): void {
// Chrome/ANGLE偏好的纹理格�? const preferredFormats = [
{ internal: this.gl.RGBA8, format: this.gl.RGBA, type: this.gl.UNSIGNED_BYTE },
{ internal: this.gl.RGB8, format: this.gl.RGB, type: this.gl.UNSIGNED_BYTE },
{ internal: this.gl.RG8, format: this.gl.RG, type: this.gl.UNSIGNED_BYTE }
];

console.log('🎨 Chrome优化的纹理格�?', preferredFormats);
}
}

Safari/WebKit适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Safari浏览器特定适配
class SafariWebGLAdapter {
private gl: WebGLRenderingContext | WebGL2RenderingContext;
private isSafari: boolean;

constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) {
this.gl = gl;
this.isSafari = this.detectSafari();

if (this.isSafari) {
this.applySafariWorkarounds();
}
}

private detectSafari(): boolean {
const userAgent = navigator.userAgent.toLowerCase();
const vendor = this.gl.getParameter(this.gl.VENDOR).toLowerCase();

return userAgent.includes('safari') &&
!userAgent.includes('chrome') &&
(vendor.includes('apple') || vendor.includes('webkit'));
}

private applySafariWorkarounds(): void {
console.log('🍎 应用Safari WebGL适配...');

// 1. Safari的WebGL 2.0兼容性问�? this.handleWebGL2Compatibility();

// 2. Safari的纹理格式限�? this.handleTextureFormatLimitations();

// 3. Safari的精度问�? this.handlePrecisionIssues();

// 4. Safari的扩展支持问�? this.handleExtensionLimitations();
}

private handleWebGL2Compatibility(): void {
// Safari对某些WebGL 2.0特性支持有�? if (this.gl instanceof WebGL2RenderingContext) {
// 检查Transform Feedback支持
try {
const tf = this.gl.createTransformFeedback();
if (!tf) {
console.warn('⚠️ Safari Transform Feedback支持有限');
}
} catch (e) {
console.warn('⚠️ Safari Transform Feedback不支�?', e);
}
}
}

private handleTextureFormatLimitations(): void {
// Safari对某些纹理格式支持有�? const limitedFormats = [
'RGBA32F',
'RGB32F',
'RG32F',
'R32F'
];

limitedFormats.forEach(format => {
console.log(`⚠️ Safari�?{format}支持可能有限,建议使�?6位精度`);
});
}

private handlePrecisionIssues(): void {
// Safari的片段着色器精度问题
const fragPrecision = this.gl.getShaderPrecisionFormat(this.gl.FRAGMENT_SHADER, this.gl.HIGH_FLOAT);

if (fragPrecision && fragPrecision.precision === 0) {
console.warn('⚠️ Safari片段着色器不支持highp,强制使用mediump');
// 在着色器中需要条件编译处�? }
}
}

Firefox适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Firefox浏览器特定适配
class FirefoxWebGLAdapter {
private gl: WebGLRenderingContext | WebGL2RenderingContext;
private isFirefox: boolean;

constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) {
this.gl = gl;
this.isFirefox = navigator.userAgent.toLowerCase().includes('firefox');

if (this.isFirefox) {
this.applyFirefoxOptimizations();
}
}

private applyFirefoxOptimizations(): void {
console.log('🦊 应用Firefox WebGL优化...');

// 1. Firefox的WebGL实现优化
this.optimizeForFirefox();

// 2. Firefox的内存管�? this.handleMemoryManagement();

// 3. Firefox的着色器编译优化
this.optimizeShaderCompilation();
}

private optimizeForFirefox(): void {
// Firefox原生WebGL实现的优�? console.log('🔧 Firefox WebGL原生实现优化');

// Firefox对某些扩展有更好的支�? const firefoxFriendlyExtensions = [
'EXT_color_buffer_float',
'EXT_float_blend',
'OES_texture_float_linear'
];

firefoxFriendlyExtensions.forEach(ext => {
if (this.hasExtension(ext)) {
console.log(`�?Firefox优质扩展支持: ${ext}`);
}
});
}
}

📱 移动端WebGL适配

移动端特有问题处�?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 移动端兼容性着色器
CCProgram mobile-compat-vs %{
precision highp float;

// 移动端顶点属性限制(通常最�?个)
in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;
in vec4 a_color; // 限制使用过多属�?
// 移动端Varying限制(通常最�?个)
out vec3 v_worldPos;
out vec3 v_normal;
out vec2 v_uv;
out vec4 v_color;

uniform CCGlobal {
mat4 cc_matViewProj;
};

uniform CCLocal {
mat4 cc_matWorld;
mat4 cc_matWorldIT;
};

void vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1.0);
v_worldPos = worldPos.xyz;

v_normal = normalize((cc_matWorldIT * vec4(a_normal, 0.0)).xyz);
v_uv = a_texCoord;
v_color = a_color;

gl_Position = cc_matViewProj * worldPos;
}
}%

CCProgram mobile-compat-fs %{
// 移动端精度声明策�? #ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#define USE_HIGHP 1
#else
precision mediump float;
#define USE_HIGHP 0
#endif

in vec3 v_worldPos;
in vec3 v_normal;
in vec2 v_uv;
in vec4 v_color;

layout(location = 0) out vec4 fragColor;

uniform sampler2D mainTexture;

// 移动端优化的光照计算
vec3 mobileLighting(vec3 normal, vec3 lightDir, vec3 lightColor) {
// 简化的光照模型,减少计算复杂度
float NdotL = max(dot(normal, lightDir), 0.0);

#if USE_HIGHP
// 高精度设备可以使用更复杂的计�? float smoothNdotL = smoothstep(0.0, 1.0, NdotL);
return lightColor * smoothNdotL;
#else
// 低精度设备使用简化计�? return lightColor * NdotL;
#endif
}

void frag() {
vec4 baseColor = texture(mainTexture, v_uv);
baseColor *= v_color;

// 简化的光照
vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
vec3 lighting = mobileLighting(normal, lightDir, vec3(1.0));

fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
}
}%

TypeScript移动端适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// 移动端WebGL适配�?class MobileWebGLAdapter {
private gl: WebGLRenderingContext | WebGL2RenderingContext;
private deviceInfo: MobileDeviceInfo;

interface MobileDeviceInfo {
isIOS: boolean;
isAndroid: boolean;
gpuVendor: string;
performanceTier: 'low' | 'medium' | 'high';
memoryLimit: number;
textureLimit: number;
}

constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) {
this.gl = gl;
this.deviceInfo = this.detectMobileDevice();
this.applyMobileOptimizations();
}

private detectMobileDevice(): MobileDeviceInfo {
const userAgent = navigator.userAgent.toLowerCase();
const renderer = this.gl.getParameter(this.gl.RENDERER).toLowerCase();

const isIOS = /iphone|ipad|ipod/.test(userAgent);
const isAndroid = /android/.test(userAgent);

let gpuVendor = 'unknown';
if (renderer.includes('adreno')) gpuVendor = 'qualcomm';
else if (renderer.includes('mali')) gpuVendor = 'arm';
else if (renderer.includes('powervr')) gpuVendor = 'imagination';
else if (renderer.includes('apple')) gpuVendor = 'apple';

return {
isIOS: isIOS,
isAndroid: isAndroid,
gpuVendor: gpuVendor,
performanceTier: this.estimatePerformanceTier(renderer),
memoryLimit: this.estimateMemoryLimit(),
textureLimit: this.gl.getParameter(this.gl.MAX_TEXTURE_SIZE)
};
}

private estimatePerformanceTier(renderer: string): 'low' | 'medium' | 'high' {
// 基于GPU型号估算性能等级
if (renderer.includes('apple a1') || renderer.includes('adreno 6')) {
return 'high';
} else if (renderer.includes('apple a') || renderer.includes('adreno 5') || renderer.includes('mali-g7')) {
return 'medium';
} else {
return 'low';
}
}

private estimateMemoryLimit(): number {
// 估算可用显存(MB�? const performanceTier = this.deviceInfo?.performanceTier || 'medium';

switch (performanceTier) {
case 'high': return 512;
case 'medium': return 256;
case 'low': return 128;
default: return 256;
}
}

private applyMobileOptimizations(): void {
console.log(`📱 应用移动端优�?(${this.deviceInfo.performanceTier}级设�?`);

// 1. 根据性能等级调整质量设置
this.adjustQualitySettings();

// 2. 移动端特定的纹理优化
this.optimizeTexturesForMobile();

// 3. 着色器复杂度控�? this.controlShaderComplexity();

// 4. 内存管理优化
this.optimizeMemoryUsage();
}

private adjustQualitySettings(): void {
const settings = {
low: {
textureQuality: 0.5,
shaderComplexity: 'simple',
enablePostProcessing: false,
maxLights: 1
},
medium: {
textureQuality: 0.75,
shaderComplexity: 'medium',
enablePostProcessing: false,
maxLights: 2
},
high: {
textureQuality: 1.0,
shaderComplexity: 'complex',
enablePostProcessing: true,
maxLights: 4
}
};

const currentSettings = settings[this.deviceInfo.performanceTier];
console.log(`⚙️ 移动端质量设�?`, currentSettings);
}

public getOptimalTextureFormat(): { internalFormat: number; format: number; type: number; } {
// 移动端优化的纹理格式
if (this.deviceInfo.performanceTier === 'low') {
// 低端设备使用16位格�? return {
internalFormat: this.gl.RGB,
format: this.gl.RGB,
type: this.gl.UNSIGNED_SHORT_5_6_5
};
} else {
// 中高端设备使用标准格�? return {
internalFormat: this.gl.RGBA,
format: this.gl.RGBA,
type: this.gl.UNSIGNED_BYTE
};
}
}
}

🧪 兼容性测试工�?

自动化兼容性测�?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// WebGL兼容性测试套�?class WebGLCompatibilityTestSuite {
private gl: WebGLRenderingContext | WebGL2RenderingContext;
private testResults: TestResult[] = [];

interface TestResult {
testName: string;
passed: boolean;
error?: string;
performance?: number;
recommendation?: string;
}

public async runAllTests(): Promise<TestReport> {
console.log('🧪 开始WebGL兼容性测�?..');

const tests = [
this.testBasicWebGLSupport.bind(this),
this.testExtensionSupport.bind(this),
this.testTextureFormatSupport.bind(this),
this.testShaderComplexity.bind(this),
this.testPerformanceLimits.bind(this),
this.testMemoryConstraints.bind(this)
];

for (const test of tests) {
try {
await test();
} catch (error) {
console.error(`测试失败:`, error);
}
}

return this.generateTestReport();
}

private async testBasicWebGLSupport(): Promise<void> {
const testName = '基础WebGL支持';

try {
// 测试基本WebGL功能
const program = this.createSimpleTestProgram();
const buffer = this.gl.createBuffer();
const texture = this.gl.createTexture();

if (program && buffer && texture) {
this.testResults.push({
testName: testName,
passed: true,
recommendation: 'WebGL基础功能正常'
});
} else {
throw new Error('基础WebGL对象创建失败');
}
} catch (error) {
this.testResults.push({
testName: testName,
passed: false,
error: error.message
});
}
}

private async testExtensionSupport(): Promise<void> {
const testName = '扩展支持测试';

const criticalExtensions = [
'OES_vertex_array_object',
'ANGLE_instanced_arrays',
'OES_standard_derivatives',
'OES_element_index_uint'
];

const supportedExtensions = this.gl.getSupportedExtensions() || [];
const missingExtensions = criticalExtensions.filter(ext => !supportedExtensions.includes(ext));

this.testResults.push({
testName: testName,
passed: missingExtensions.length === 0,
error: missingExtensions.length > 0 ? `缺少扩展: ${missingExtensions.join(', ')}` : undefined,
recommendation: missingExtensions.length > 0 ? '考虑提供fallback实现' : '扩展支持良好'
});
}

private async testShaderComplexity(): Promise<void> {
const testName = '着色器复杂度测�?;

const complexShaderSource = `
precision highp float;
uniform sampler2D tex;
varying vec2 uv;

void main() {
vec4 color = vec4(0.0);

// 测试循环支持
for(int i = 0; i < 16; i++) {
color += texture2D(tex, uv + vec2(float(i) * 0.01));
}

// 测试复杂数学运算
color.rgb = normalize(color.rgb);
color.rgb = pow(color.rgb, vec3(2.2));

gl_FragColor = color;
}
`;

const startTime = performance.now();
const shader = this.compileShader(this.gl.FRAGMENT_SHADER, complexShaderSource);
const endTime = performance.now();

this.testResults.push({
testName: testName,
passed: shader !== null,
performance: endTime - startTime,
recommendation: shader ? '支持复杂着色器' : '建议简化着色器复杂�?
});
}

private generateTestReport(): TestReport {
const passed = this.testResults.filter(r => r.passed).length;
const total = this.testResults.length;
const score = (passed / total) * 100;

let compatibilityLevel: 'excellent' | 'good' | 'fair' | 'poor';
if (score >= 90) compatibilityLevel = 'excellent';
else if (score >= 75) compatibilityLevel = 'good';
else if (score >= 60) compatibilityLevel = 'fair';
else compatibilityLevel = 'poor';

return {
score: score,
compatibilityLevel: compatibilityLevel,
testResults: this.testResults,
recommendations: this.generateRecommendations()
};
}

private generateRecommendations(): string[] {
const recommendations: string[] = [];

this.testResults.forEach(result => {
if (!result.passed && result.recommendation) {
recommendations.push(result.recommendation);
}
});

return recommendations;
}
}

interface TestReport {
score: number;
compatibilityLevel: 'excellent' | 'good' | 'fair' | 'poor';
testResults: TestResult[];
recommendations: string[];
}

📝 本章小结

通过本教程,你应该掌握了�?

  1. WebGL版本差异: 理解WebGL 1.0�?.0的兼容性问�?2. 浏览器适配: 掌握主流浏览器的特定优化策略
  2. *移动端兼�?: 学会处理移动设备的特殊限�?4. 测试工具: 了解如何系统性地测试WebGL兼容�?

🚀 下一步学�?

继续学习移动平台着色器优化!📱✨