@luma.gl/webgl2-polyfill
Version:
WebGL2 API Polyfills for WebGL1 WebGLRenderingContext
165 lines (154 loc) • 4.93 kB
JavaScript
import GL from '@luma.gl/constants';
import assert from './assert';
import {getParameterPolyfill} from './polyfills/get-parameter-polyfill';
const OES_vertex_array_object = 'OES_vertex_array_object';
const ANGLE_instanced_arrays = 'ANGLE_instanced_arrays';
const WEBGL_draw_buffers = 'WEBGL_draw_buffers';
const EXT_disjoint_timer_query = 'EXT_disjoint_timer_query';
const EXT_texture_filter_anisotropic = 'EXT_texture_filter_anisotropic';
const ERR_VAO_NOT_SUPPORTED = 'VertexArray requires WebGL2 or OES_vertex_array_object extension';
// Return true if WebGL2 context
function isWebGL2(gl) {
return Boolean(gl && gl._version === 2);
}
// Return object with webgl2 flag and an extension
function getExtensionData(gl, extension) {
return {
webgl2: isWebGL2(gl),
ext: gl.getExtension(extension)
};
}
// function mapExtensionConstant(gl, constant) {
// switch (constant) {
// case ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES: return GL.FRAGMENT_SHADER_DERIVATIVE_HINT;
// }
// }
export const WEBGL2_CONTEXT_POLYFILLS = {
// POLYFILL TABLE
[OES_vertex_array_object]: {
meta: {suffix: 'OES'},
// NEW METHODS
createVertexArray: () => {
assert(false, ERR_VAO_NOT_SUPPORTED);
},
deleteVertexArray: () => {},
bindVertexArray: () => {},
isVertexArray: () => false
},
[ANGLE_instanced_arrays]: {
meta: {
suffix: 'ANGLE'
// constants: {
// VERTEX_ATTRIB_ARRAY_DIVISOR: 'VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE'
// }
},
vertexAttribDivisor(location, divisor) {
// Accept divisor 0 even if instancing is not supported (0 = no instancing)
assert(divisor === 0, 'WebGL instanced rendering not supported');
},
drawElementsInstanced: () => {},
drawArraysInstanced: () => {}
},
[WEBGL_draw_buffers]: {
meta: {
suffix: 'WEBGL'
},
drawBuffers: () => {
assert(false);
}
},
[EXT_disjoint_timer_query]: {
meta: {suffix: 'EXT'},
// WebGL1: Polyfills the WebGL2 Query API
createQuery: () => {
assert(false);
},
deleteQuery: () => {
assert(false);
},
beginQuery: () => {
assert(false);
},
endQuery: () => {},
getQuery(handle, pname) {
return this.getQueryObject(handle, pname);
},
// The WebGL1 extension uses getQueryObject rather then getQueryParameter
getQueryParameter(handle, pname) {
return this.getQueryObject(handle, pname);
},
getQueryObject: () => {}
}
};
export const WEBGL2_CONTEXT_OVERRIDES = {
// Ensure readBuffer is a no-op
readBuffer: (gl, originalFunc, attachment) => {
if (isWebGL2(gl)) {
originalFunc(attachment);
} else {
// assert(attachment !== GL_COLOR_ATTACHMENT0 && attachment !== GL_FRONT);
}
},
// Override for getVertexAttrib that returns sane values for non-WebGL1 constants
getVertexAttrib: (gl, originalFunc, location, pname) => {
// const gl = this; // eslint-disable-line
const {webgl2, ext} = getExtensionData(gl, ANGLE_instanced_arrays);
let result;
switch (pname) {
// WebGL1 attributes will never be integer
case GL.VERTEX_ATTRIB_ARRAY_INTEGER:
result = !webgl2 ? false : undefined;
break;
// if instancing is not available, return 0 meaning divisor has not been set
case GL.VERTEX_ATTRIB_ARRAY_DIVISOR:
result = !webgl2 && !ext ? 0 : undefined;
break;
default:
}
return result !== undefined ? result : originalFunc(location, pname);
},
// Handle transform feedback and uniform block queries in WebGL1
getProgramParameter: (gl, originalFunc, program, pname) => {
if (!isWebGL2(gl)) {
switch (pname) {
case GL.TRANSFORM_FEEDBACK_BUFFER_MODE:
return GL.SEPARATE_ATTRIBS;
case GL.TRANSFORM_FEEDBACK_VARYINGS:
return 0;
case GL.ACTIVE_UNIFORM_BLOCKS:
return 0;
default:
}
}
return originalFunc(program, pname);
},
getInternalformatParameter: (gl, originalFunc, target, format, pname) => {
if (!isWebGL2(gl)) {
switch (pname) {
case GL.SAMPLES:
return new Int32Array([0]);
default:
}
}
return gl.getInternalformatParameter(target, format, pname);
},
getTexParameter(gl, originalFunc, target, pname) {
switch (pname) {
case GL.TEXTURE_MAX_ANISOTROPY_EXT:
const {extensions} = gl.luma;
const ext = extensions[EXT_texture_filter_anisotropic];
pname = (ext && ext.TEXTURE_MAX_ANISOTROPY_EXT) || GL.TEXTURE_MAX_ANISOTROPY_EXT;
break;
default:
}
return originalFunc(target, pname);
},
getParameter: getParameterPolyfill,
hint(gl, originalFunc, pname, value) {
// TODO - handle GL.FRAGMENT_SHADER_DERIVATIVE_HINT:
// switch (pname) {
// case GL.FRAGMENT_SHADER_DERIVATIVE_HINT:
// }
return originalFunc(pname, value);
}
};