Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to WebGL 2.0 #15136

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/webgl-layer-swipe.html
Expand Up @@ -4,8 +4,8 @@
shortdesc: Cropping a WebGL tile layer
docs: >
The <code>prerender</code> and <code>postrender</code> events on a WebGL tile layer can be
used to manipulate the WebGL context before and after rendering. In this case, the
<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor"><code>gl.scissor()</code></a>
used to manipulate the WebGL context before and after rendering. In this case, the
<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/scissor"><code>gl.scissor()</code></a>
method is called to clip the top layer based on the position of a slider.
tags: "swipe, webgl"
cloak:
Expand Down
14 changes: 14 additions & 0 deletions src/ol/layer/WebGLTile.js
Expand Up @@ -131,6 +131,20 @@ function parseStyle(style, bandCount) {
if (style.color !== undefined) {
const color = expressionToGlsl(context, style.color, ValueTypes.COLOR);
pipeline.push(`color = ${color};`);
} else if (bandCount === 1) {
const color = expressionToGlsl(
context,
['array', ['band', 1], ['band', 1], ['band', 1], 1],
ValueTypes.COLOR
);
pipeline.push(`color = ${color};`);
} else if (bandCount === 2) {
const color = expressionToGlsl(
context,
['array', ['band', 1], ['band', 1], ['band', 1], ['band', 2]],
ValueTypes.COLOR
);
pipeline.push(`color = ${color};`);
}

if (style.contrast !== undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/ol/render/Event.js
Expand Up @@ -10,7 +10,7 @@ class RenderEvent extends Event {
* @param {import("../transform.js").Transform} [inversePixelTransform] Transform for
* CSS pixels to rendered pixels.
* @param {import("../Map.js").FrameState} [frameState] Frame state.
* @param {?(CanvasRenderingContext2D|WebGLRenderingContext)} [context] Context.
* @param {?(CanvasRenderingContext2D|WebGL2RenderingContext)} [context] Context.
*/
constructor(type, inversePixelTransform, frameState, context) {
super(type);
Expand All @@ -34,7 +34,7 @@ class RenderEvent extends Event {
* Canvas context. Not available when the event is dispatched by the map. For Canvas 2D layers,
* the context will be the 2D rendering context. For WebGL layers, the context will be the WebGL
* context.
* @type {CanvasRenderingContext2D|WebGLRenderingContext|undefined}
* @type {CanvasRenderingContext2D|WebGL2RenderingContext|undefined}
* @api
*/
this.context = context;
Expand Down
10 changes: 5 additions & 5 deletions src/ol/renderer/webgl/Layer.js
Expand Up @@ -80,7 +80,7 @@ class WebGLLayerRenderer extends LayerRenderer {
}

/**
* @param {WebGLRenderingContext} context The WebGL rendering context.
* @param {WebGL2RenderingContext} context The WebGL rendering context.
* @param {import("../../Map.js").FrameState} frameState Frame state.
* @protected
*/
Expand All @@ -98,7 +98,7 @@ class WebGLLayerRenderer extends LayerRenderer {
}

/**
* @param {WebGLRenderingContext} context The WebGL rendering context.
* @param {WebGL2RenderingContext} context The WebGL rendering context.
* @param {import("../../Map.js").FrameState} frameState Frame state.
* @protected
*/
Expand Down Expand Up @@ -216,7 +216,7 @@ class WebGLLayerRenderer extends LayerRenderer {

/**
* @param {import("../../render/EventType.js").default} type Event type.
* @param {WebGLRenderingContext} context The rendering context.
* @param {WebGL2RenderingContext} context The rendering context.
* @param {import("../../Map.js").FrameState} frameState Frame state.
* @private
*/
Expand Down Expand Up @@ -245,7 +245,7 @@ class WebGLLayerRenderer extends LayerRenderer {
}

/**
* @param {WebGLRenderingContext} context The rendering context.
* @param {WebGL2RenderingContext} context The rendering context.
* @param {import("../../Map.js").FrameState} frameState Frame state.
* @protected
*/
Expand All @@ -254,7 +254,7 @@ class WebGLLayerRenderer extends LayerRenderer {
}

/**
* @param {WebGLRenderingContext} context The rendering context.
* @param {WebGL2RenderingContext} context The rendering context.
* @param {import("../../Map.js").FrameState} frameState Frame state.
* @protected
*/
Expand Down
23 changes: 7 additions & 16 deletions src/ol/webgl.js
Expand Up @@ -79,16 +79,10 @@ export const FLOAT = 0x1406;
/** end of goog.webgl constants
*/

/**
* @const
* @type {Array<string>}
*/
const CONTEXT_IDS = ['experimental-webgl', 'webgl', 'webkit-3d', 'moz-webgl'];

/**
* @param {HTMLCanvasElement} canvas Canvas.
* @param {Object} [attributes] Attributes.
* @return {WebGLRenderingContext} WebGL rendering context.
* @return {WebGL2RenderingContext} WebGL rendering context.
*/
export function getContext(canvas, attributes) {
attributes = Object.assign(
Expand All @@ -98,16 +92,13 @@ export function getContext(canvas, attributes) {
},
attributes
);
const ii = CONTEXT_IDS.length;
for (let i = 0; i < ii; ++i) {
try {
const context = canvas.getContext(CONTEXT_IDS[i], attributes);
if (context) {
return /** @type {!WebGLRenderingContext} */ (context);
}
} catch (e) {
// pass
try {
const context = canvas.getContext('webgl2', attributes);
if (context) {
return /** @type {!WebGL2RenderingContext} */ (context);
}
} catch (e) {
// pass
}
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ol/webgl/Buffer.js
Expand Up @@ -33,7 +33,7 @@ export const BufferUsage = {
* * A plain array using `#fromArray(array)`
*
* Note:
* See the documentation of [WebGLRenderingContext.bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData)
* See the documentation of [WebGL2RenderingContext.bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/bufferData)
* for more info on buffer usage.
*/
class WebGLArrayBuffer {
Expand Down
14 changes: 7 additions & 7 deletions src/ol/webgl/Helper.js
Expand Up @@ -111,7 +111,7 @@ export const AttributeType = {

/**
* @typedef {Object} CanvasCacheItem
* @property {WebGLRenderingContext} context The context of this canvas.
* @property {WebGL2RenderingContext} context The context of this canvas.
* @property {number} users The count of users of this canvas.
*/

Expand Down Expand Up @@ -141,7 +141,7 @@ function getUniqueCanvasCacheKey() {

/**
* @param {string} key The cache key for the canvas.
* @return {WebGLRenderingContext} The canvas.
* @return {WebGL2RenderingContext} The canvas.
*/
function getOrCreateContext(key) {
let cacheItem = canvasCache[key];
Expand Down Expand Up @@ -274,7 +274,7 @@ function releaseCanvas(key) {
* Attributes are used to specify these uses. Specify the attribute names with
* {@link module:ol/webgl/Helper~WebGLHelper#enableAttributes} (see code snippet below).
*
* Please note that you will have to specify the type and offset of the attributes in the data array. You can refer to the documentation of [WebGLRenderingContext.vertexAttribPointer](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer) for more explanation.
* Please note that you will have to specify the type and offset of the attributes in the data array. You can refer to the documentation of [WebGL2RenderingContext.vertexAttribPointer](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/vertexAttribPointer) for more explanation.
* ```js
* // here we indicate that the data array has the following structure:
* // [posX, posY, offsetX, offsetY, texCoordU, texCoordV, posX, posY, ...]
Expand Down Expand Up @@ -335,7 +335,7 @@ class WebGLHelper extends Disposable {

/**
* @private
* @type {WebGLRenderingContext}
* @type {WebGL2RenderingContext}
*/
this.gl_ = getOrCreateContext(this.canvasCacheKey_);

Expand Down Expand Up @@ -670,8 +670,8 @@ class WebGLHelper extends Disposable {
/**
* Apply the successive post process passes which will eventually render to the actual canvas.
* @param {import("../Map.js").FrameState} frameState current frame state
* @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing.
* @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing.
* @param {function(WebGL2RenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing.
* @param {function(WebGL2RenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing.
*/
finalizeDraw(frameState, preCompose, postCompose) {
// apply post processes using the next one as target
Expand Down Expand Up @@ -701,7 +701,7 @@ class WebGLHelper extends Disposable {

/**
* Get the WebGL rendering context
* @return {WebGLRenderingContext} The rendering context.
* @return {WebGL2RenderingContext} The rendering context.
*/
getGL() {
return this.gl_;
Expand Down
2 changes: 1 addition & 1 deletion src/ol/webgl/PaletteTexture.js
Expand Up @@ -19,7 +19,7 @@ class PaletteTexture {
}

/**
* @param {WebGLRenderingContext} gl Rendering context.
* @param {WebGL2RenderingContext} gl Rendering context.
* @return {WebGLTexture} The texture.
*/
getTexture(gl) {
Expand Down
20 changes: 10 additions & 10 deletions src/ol/webgl/PostProcessingPass.js
Expand Up @@ -6,13 +6,13 @@ import {getUid} from '../util.js';

const DEFAULT_VERTEX_SHADER = `
precision mediump float;

attribute vec2 a_position;
varying vec2 v_texCoord;
varying vec2 v_screenCoord;

uniform vec2 u_screenSize;

void main() {
v_texCoord = a_position * 0.5 + 0.5;
v_screenCoord = v_texCoord * u_screenSize;
Expand All @@ -22,20 +22,20 @@ const DEFAULT_VERTEX_SHADER = `

const DEFAULT_FRAGMENT_SHADER = `
precision mediump float;

uniform sampler2D u_image;
uniform float u_opacity;

varying vec2 v_texCoord;

void main() {
gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity;
}
`;

/**
* @typedef {Object} Options
* @property {WebGLRenderingContext} webGlContext WebGL context; mandatory.
* @property {WebGL2RenderingContext} webGlContext WebGL context; mandatory.
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
* the main canvas that will then be sampled up (useful for saving resource on blur steps).
* @property {string} [vertexShader] Vertex shader source
Expand Down Expand Up @@ -177,7 +177,7 @@ class WebGLPostProcessingPass {

/**
* Get the WebGL rendering context
* @return {WebGLRenderingContext} The rendering context.
* @return {WebGL2RenderingContext} The rendering context.
*/
getGL() {
return this.gl_;
Expand Down Expand Up @@ -261,8 +261,8 @@ class WebGLPostProcessingPass {
* Render to the next postprocessing pass (or to the canvas if final pass).
* @param {import("../Map.js").FrameState} frameState current frame state
* @param {WebGLPostProcessingPass} [nextPass] Next pass, optional
* @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing.
* @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing.
* @param {function(WebGL2RenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing.
* @param {function(WebGL2RenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing.
*/
apply(frameState, nextPass, preCompose, postCompose) {
const gl = this.getGL();
Expand Down
22 changes: 15 additions & 7 deletions src/ol/webgl/TileTexture.js
Expand Up @@ -13,7 +13,7 @@ import {createCanvasContext2D} from '../dom.js';
import {toSize} from '../size.js';

/**
* @param {WebGLRenderingContext} gl The WebGL context.
* @param {WebGL2RenderingContext} gl The WebGL context.
* @param {WebGLTexture} texture The texture.
* @param {boolean} interpolate Interpolate when resampling.
*/
Expand All @@ -27,7 +27,7 @@ function bindAndConfigure(gl, texture, interpolate) {
}

/**
* @param {WebGLRenderingContext} gl The WebGL context.
* @param {WebGL2RenderingContext} gl The WebGL context.
* @param {WebGLTexture} texture The texture.
* @param {import("../DataTile.js").ImageLike} image The image.
* @param {boolean} interpolate Interpolate when resampling.
Expand Down Expand Up @@ -57,9 +57,9 @@ function uploadDataTexture(
const gl = helper.getGL();
let textureType;
let canInterpolate;
if (data instanceof Float32Array) {
const isFloat32 = data instanceof Float32Array;
if (isFloat32) {
textureType = gl.FLOAT;
helper.getExtension('OES_texture_float');
const extension = helper.getExtension('OES_texture_float_linear');
canInterpolate = extension !== null;
} else {
Expand All @@ -78,21 +78,29 @@ function uploadDataTexture(
unpackAlignment = 2;
}

// See https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D
// And https://registry.khronos.org/webgl/specs/latest/2.0/
// "Sized internal formats are supported in WebGL 2.0 and internalformat is no longer required to be the same as format"
let format;
let internalFormat;
switch (bandCount) {
case 1: {
format = gl.LUMINANCE;
internalFormat = isFloat32 ? gl.R32F : gl.LUMINANCE;
format = isFloat32 ? gl.RED : gl.LUMINANCE;
break;
}
case 2: {
format = gl.LUMINANCE_ALPHA;
internalFormat = isFloat32 ? gl.RG32F : gl.LUMINANCE_ALPHA;
format = isFloat32 ? gl.RG : gl.LUMINANCE_ALPHA;
break;
}
case 3: {
internalFormat = isFloat32 ? gl.RGB32F : gl.RGB;
format = gl.RGB;
break;
}
case 4: {
internalFormat = isFloat32 ? gl.RGBA32F : gl.RGBA;
format = gl.RGBA;
break;
}
Expand All @@ -106,7 +114,7 @@ function uploadDataTexture(
gl.texImage2D(
gl.TEXTURE_2D,
0,
format,
internalFormat,
size[0],
size[1],
0,
Expand Down
6 changes: 3 additions & 3 deletions test/browser/spec/ol/layer/WebGLTile.test.js
Expand Up @@ -581,7 +581,7 @@ describe('ol/layer/WebGLTile', function () {
it('dispatches a precompose event with WebGL context', (done) => {
let called = false;
layer.on('precompose', (event) => {
expect(event.context).to.be.a(WebGLRenderingContext);
expect(event.context).to.be.a(WebGL2RenderingContext);
called = true;
});

Expand All @@ -596,7 +596,7 @@ describe('ol/layer/WebGLTile', function () {
it('dispatches a prerender event with WebGL context and inverse pixel transform', (done) => {
let called = false;
layer.on('prerender', (event) => {
expect(event.context).to.be.a(WebGLRenderingContext);
expect(event.context).to.be.a(WebGL2RenderingContext);
const mapSize = event.frameState.size;
const bottomLeft = getRenderPixel(event, [0, mapSize[1]]);
expect(bottomLeft).to.eql([0, 0]);
Expand All @@ -614,7 +614,7 @@ describe('ol/layer/WebGLTile', function () {
it('dispatches a postrender event with WebGL context and inverse pixel transform', (done) => {
let called = false;
layer.on('postrender', (event) => {
expect(event.context).to.be.a(WebGLRenderingContext);
expect(event.context).to.be.a(WebGL2RenderingContext);
const mapSize = event.frameState.size;
const topRight = getRenderPixel(event, [mapSize[1], 0]);
const pixelRatio = event.frameState.pixelRatio;
Expand Down
2 changes: 1 addition & 1 deletion test/browser/spec/ol/webgl/helper.test.js
Expand Up @@ -80,7 +80,7 @@ describe('ol/webgl/WebGLHelper', function () {
});

it('initialized WebGL context & canvas', function () {
expect(h.getGL() instanceof WebGLRenderingContext).to.eql(true);
expect(h.getGL() instanceof WebGL2RenderingContext).to.eql(true);
expect(h.getCanvas() instanceof HTMLCanvasElement).to.eql(true);
});

Expand Down