From e0983cb1c63b7970b839121c7af6fda9a1725395 Mon Sep 17 00:00:00 2001 From: Olivier Guyot Date: Sat, 18 May 2019 15:40:27 +0200 Subject: [PATCH] Webgl worker / add tests, some typing and documentation The worker currently works by receiving GENERATE_BUFFERS messages and will send back the same kind of message, with the generated buffers attached. All properties of the original message are kept, so that when a GENERATE_BUFFERS message comes back to the main thread it is possible to know what and how the buffers where generated. This is typically used for the `projectionTransform` matrix, and will also be necessary when working with tiles. --- src/ol/renderer/webgl/Layer.js | 20 ++++++++++++ src/ol/renderer/webgl/PointsLayer.js | 25 +++++++++------ src/ol/worker/webgl.js | 29 +++++++++++------- test/spec/ol/worker/webgl.test.js | 46 ++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 test/spec/ol/worker/webgl.test.js diff --git a/src/ol/renderer/webgl/Layer.js b/src/ol/renderer/webgl/Layer.js index 2f34eb2f93..441c455e3f 100644 --- a/src/ol/renderer/webgl/Layer.js +++ b/src/ol/renderer/webgl/Layer.js @@ -5,6 +5,26 @@ import LayerRenderer from '../Layer.js'; import WebGLHelper from '../../webgl/Helper.js'; +/** + * @enum {string} + */ +export const WebGLWorkerMessageType = { + GENERATE_BUFFERS: 'GENERATE_BUFFERS' +}; + +/** + * @typedef {Object} WebGLWorkerGenerateBuffersMessage + * This message will trigger the generation of a vertex and an index buffer based on the given render instructions. + * When the buffers are generated, the worked will send a message of the same type to the main thread, with + * the generated buffers in it. + * Note that any addition properties present in the message *will* be sent back to the main thread. + * @property {WebGLWorkerMessageType} type Message type + * @property {ArrayBuffer} renderInstructions Render instructions raw binary buffer. + * @property {ArrayBuffer=} vertexBuffer Vertices array raw binary buffer (sent by the worker). + * @property {ArrayBuffer=} indexBuffer Indices array raw binary buffer (sent by the worker). + * @property {number=} customAttributesCount Amount of custom attributes count in the render instructions. + */ + /** * @typedef {Object} PostProcessesOptions * @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than diff --git a/src/ol/renderer/webgl/PointsLayer.js b/src/ol/renderer/webgl/PointsLayer.js index 6befa215f6..e35fbbfd26 100644 --- a/src/ol/renderer/webgl/PointsLayer.js +++ b/src/ol/renderer/webgl/PointsLayer.js @@ -7,7 +7,7 @@ import {DefaultAttrib, DefaultUniform} from '../../webgl/Helper.js'; import GeometryType from '../../geom/GeometryType.js'; import WebGLLayerRenderer, { getBlankTexture, - POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE, + POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE, WebGLWorkerMessageType, writePointFeatureInstructions } from './Layer.js'; import ViewHint from '../../ViewHint.js'; @@ -276,10 +276,11 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer { this.worker_ = createWebGLWorker(); this.worker_.addEventListener('message', function(event) { - if (event.data.type === 'buffers-generated') { - const projectionTransform = event.data.projectionTransform; - this.verticesBuffer_.fromArrayBuffer(event.data.vertexBuffer); - this.indicesBuffer_.fromArrayBuffer(event.data.indexBuffer); + const received = event.data; + if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) { + const projectionTransform = received.projectionTransform; + this.verticesBuffer_.fromArrayBuffer(received.vertexBuffer); + this.indicesBuffer_.fromArrayBuffer(received.indexBuffer); this.helper_.flushBufferData(this.verticesBuffer_); this.helper_.flushBufferData(this.indicesBuffer_); @@ -415,11 +416,15 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer { ); } - this.worker_.postMessage({ - type: 'generate-buffer', - renderInstructions: this.renderInstructions_.buffer, - projectionTransform: projectionTransform - }, [this.renderInstructions_.buffer]); + /** @type import('./Layer').WebGLWorkerGenerateBuffersMessage */ + const message = { + type: WebGLWorkerMessageType.GENERATE_BUFFERS, + renderInstructions: this.renderInstructions_.buffer + }; + // additional properties will be sent back as-is by the worker + message['projectionTransform'] = projectionTransform; + + this.worker_.postMessage(message, [this.renderInstructions_.buffer]); } diff --git a/src/ol/worker/webgl.js b/src/ol/worker/webgl.js index 046bbb7ca9..4e5662a174 100644 --- a/src/ol/worker/webgl.js +++ b/src/ol/worker/webgl.js @@ -1,15 +1,21 @@ /** + * A worker that does cpu-heavy tasks related to webgl rendering. * @module ol/worker/webgl - * A worker that does cpu-heavy tasks related to webgl rendering */ -import {POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE, writePointFeatureToBuffers} from '../renderer/webgl/Layer.js'; +import { + POINT_INSTRUCTIONS_COUNT, + POINT_VERTEX_STRIDE, + WebGLWorkerMessageType, + writePointFeatureToBuffers +} from '../renderer/webgl/Layer.js'; +import {assign} from '../obj.js'; onmessage = event => { - if (event.data.type === 'generate-buffer') { - const renderInstructions = new Float32Array(event.data.renderInstructions); - const customAttributesCount = event.data.customAttributesCount || 0; + const received = event.data; + if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) { + const renderInstructions = new Float32Array(received.renderInstructions); + const customAttributesCount = received.customAttributesCount || 0; const instructionsCount = POINT_INSTRUCTIONS_COUNT + customAttributesCount; - const projectionTransform = event.data.projectionTransform; const elementsCount = renderInstructions.length / instructionsCount; const indexBuffer = new Uint32Array(elementsCount * 6); @@ -26,13 +32,14 @@ onmessage = event => { instructionsCount); } - postMessage({ - type: 'buffers-generated', + /** @type {import('../renderer/webgl/Layer').WebGLWorkerGenerateBuffersMessage} */ + const message = assign({ vertexBuffer: vertexBuffer.buffer, indexBuffer: indexBuffer.buffer, - renderInstructions: renderInstructions.buffer, - projectionTransform - }, [vertexBuffer.buffer, indexBuffer.buffer, renderInstructions.buffer]); + renderInstructions: renderInstructions.buffer + }, received); + + postMessage(message, [vertexBuffer.buffer, indexBuffer.buffer, renderInstructions.buffer]); } }; diff --git a/test/spec/ol/worker/webgl.test.js b/test/spec/ol/worker/webgl.test.js new file mode 100644 index 0000000000..426125e960 --- /dev/null +++ b/test/spec/ol/worker/webgl.test.js @@ -0,0 +1,46 @@ +import {create} from '../../../../src/ol/worker/webgl.js'; +import {WebGLWorkerMessageType, writePointFeatureInstructions} from '../../../../src/ol/renderer/webgl/Layer'; + + +describe('ol/worker/webgl', function() { + + let worker; + beforeEach(function() { + worker = create(); + }); + + afterEach(function() { + if (worker) { + worker.terminate(); + } + worker = null; + }); + + describe('messaging', function() { + it('responds to GENERATE_BUFFERS message type', function(done) { + worker.addEventListener('error', done); + + worker.addEventListener('message', function(event) { + expect(event.data.type).to.eql(WebGLWorkerMessageType.GENERATE_BUFFERS); + expect(event.data.renderInstructions.byteLength).to.greaterThan(0); + expect(event.data.indexBuffer.byteLength).to.greaterThan(0); + expect(event.data.vertexBuffer.byteLength).to.greaterThan(0); + expect(event.data.testInt).to.be(101); + expect(event.data.testString).to.be('abcd'); + done(); + }); + + const instructions = new Float32Array(100); + + const message = { + type: WebGLWorkerMessageType.GENERATE_BUFFERS, + renderInstructions: instructions, + testInt: 101, + testString: 'abcd' + }; + + worker.postMessage(message); + }); + }); + +});