Skip to content

Commit

Permalink
support baseInstance/baseVertex draw and multidraw calls
Browse files Browse the repository at this point in the history
  • Loading branch information
micahscopes committed Apr 21, 2022
1 parent 151ef6d commit c7a541d
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 11 deletions.
150 changes: 150 additions & 0 deletions examples/multi-draw-base-instance.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<title>PicoGL.js: Multi-draw</title>
<meta charset="utf-8">
<script src="utils/compatibility.js"></script>
<script src="utils/utils.js"></script>
<link rel="stylesheet" href="../site/css/picogl-example.css">
</head>
<!--
The MIT License (MIT)
Copyright (c) 2017 Tarek Sherif
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
<body>
<div id="example-title">
PicoGL.js Example: Multi-draw with base instance offsets
<div>
<a href="https://github.com/tsherif/picogl.js/blob/master/examples/instanced.html">Source code</a>
</div>
</div>
<canvas id="gl-canvas"></canvas>
<script type="shader/vs" id="vs">
#version 300 es
#extension GL_ANGLE_multi_draw : require

layout(location=0) in vec4 position;
layout(location=1) in float verticalOffset;
layout(location=2) in vec4 color;

out vec4 vColor;
void main() {
vColor = color;
gl_Position = position;
gl_Position.xy += vec2(-0.6 + 0.4 * float(gl_DrawID), verticalOffset);
}
</script>
<script type="shader/fs" id="fs">
#version 300 es
precision highp float;

in vec4 vColor;

out vec4 fragColor;
void main() {
fragColor = vColor;
}
</script>

<script type="module">
import { PicoGL } from "../src/picogl.js";

if (!testExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance") || !testExtension("WEBGL_draw_instanced_base_vertex_base_instance")) {
document.body.innerHTML = 'This example requires extension <b>WEBGL_multi_draw_instanced_base_vertex_base_instance</b> which is not supported on this system. You may need to enable <b>WebGL Draft Extensions</b> in your browser, via <b><code>chrome://flags</code></b> in Google Chrome, or <b><code>about:config</code></b> in Firefox.';
}

let canvas = document.getElementById("gl-canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let app = PicoGL.createApp(canvas)
.clearColor(0.0, 0.0, 0.0, 1.0);

window.onresize = function() {
app.resize(window.innerWidth, window.innerHeight);
}

// PROGRAM
let vsSource = document.getElementById("vs").text;
let fsSource = document.getElementById("fs").text;

// PER-VERTEX POSITIONS
let positions = app.createVertexBuffer(PicoGL.FLOAT, 2, new Float32Array([
// Triangle positions
-0.15, -0.15,
0.15, -0.15,
0.0, 0.15,
// Square positions
-0.15, 0.15,
-0.15, -0.15,
0.15, -0.15,
-0.15, 0.15,
0.15, -0.15,
0.15, 0.15
]));

// PER-INSTANCE OFFSETS AND COLORS
let verticalOffets = app.createVertexBuffer(PicoGL.FLOAT, 1, new Float32Array([
0.5,
0.0,
-0.5
]));

let colors = app.createVertexBuffer(PicoGL.UNSIGNED_BYTE, 3, new Uint8Array([
255, 0, 0,
0, 255, 0,
0, 0, 255
]));

let triangleArray = app.createVertexArray()
.vertexAttributeBuffer(0, positions)
.instanceAttributeBuffer(1, verticalOffets)
.instanceAttributeBuffer(2, colors, { normalized: true });


// USE PARALLEL SHADER COMPILATION IF AVAILABLE
// https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
app.createPrograms([vsSource, fsSource]).then(([program]) => {
let drawCall = app.createDrawCall(program, triangleArray)
.drawRanges(
[0, 3, 1, 2],
[3, 6, 2, 1],
[3, 6, 2],
[0, 3, 3],
);

app.clear();
drawCall.draw();

// CLEANUP
program.delete();
positions.delete();
verticalOffets.delete();
colors.delete();
triangleArray.delete();
});


</script>
<a href="https://github.com/tsherif/picogl.js" id="github-ribbon"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"></a>
<script src="../site/js/iframe.js"></script>
</body>
</html>
20 changes: 10 additions & 10 deletions examples/multi-draw.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="utf-8">
<script src="utils/compatibility.js"></script>
<script src="utils/utils.js"></script>
<link rel="stylesheet" href="../site/css/picogl-example.css">
<link rel="stylesheet" href="../site/css/picogl-example.css">
</head>
<!--
The MIT License (MIT)
Expand Down Expand Up @@ -40,11 +40,11 @@
<script type="shader/vs" id="vs">
#version 300 es
#extension GL_ANGLE_multi_draw : require

layout(location=0) in vec4 position;
layout(location=1) in float verticalOffset;
layout(location=2) in vec4 color;

out vec4 vColor;
void main() {
vColor = color;
Expand All @@ -63,18 +63,18 @@
fragColor = vColor;
}
</script>

<script type="module">
import { PicoGL } from "../src/picogl.js";

if (!testExtension("WEBGL_multi_draw_instanced")) {
if (!testExtension("WEBGL_multi_draw_instanced") && !testExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")) {
document.body.innerHTML = 'This example requires extension <b>WEBGL_multi_draw_instanced</b> which is not supported on this system. You may need to enable <b>WebGL Draft Extensions</b> in your browser, via <b><code>chrome://flags</code></b> in Google Chrome, or <b><code>about:config</code></b> in Firefox.';
}

let canvas = document.getElementById("gl-canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let app = PicoGL.createApp(canvas)
.clearColor(0.0, 0.0, 0.0, 1.0);

Expand All @@ -85,14 +85,14 @@
// PROGRAM
let vsSource = document.getElementById("vs").text;
let fsSource = document.getElementById("fs").text;

// PER-VERTEX POSITIONS
let positions = app.createVertexBuffer(PicoGL.FLOAT, 2, new Float32Array([
// Triangle positions
-0.15, -0.15,
0.15, -0.15,
0.0, 0.15,
// Square positions
// Square positions
-0.15, 0.15,
-0.15, -0.15,
0.15, -0.15,
Expand All @@ -118,7 +118,7 @@
.vertexAttributeBuffer(0, positions)
.instanceAttributeBuffer(1, verticalOffets)
.instanceAttributeBuffer(2, colors, { normalized: true });


// USE PARALLEL SHADER COMPILATION IF AVAILABLE
// https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
Expand Down
2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,8 @@ export class App {
// Draft extensions
this.gl.getExtension("KHR_parallel_shader_compile");
this.state.extensions.multiDrawInstanced = this.gl.getExtension("WEBGL_multi_draw_instanced");
this.state.extensions.drawInstancedBaseVertexBaseInstance = this.gl.getExtension("WEBGL_draw_instanced_base_vertex_base_instance");
this.state.extensions.multiDrawInstancedBaseVertexBaseInstance = this.gl.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");
}

initContextListeners() {
Expand Down
44 changes: 43 additions & 1 deletion src/draw-call.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export class DrawCall {
this.offsets = new Int32Array(1);
this.numElements = new Int32Array(1);
this.numInstances = new Int32Array(1);
this.baseVertices = new Int32Array(1);
this.baseInstances = new Uint32Array(1);

this.hasBaseInstancesOrBaseVertices = false;

this.numDraws = 1;
this.drawCountsFromVertexArray = true;
Expand Down Expand Up @@ -167,6 +171,8 @@ export class DrawCall {
<li> (Number) Number of elements to skip at the start of the array.
<li> (Number) Number of elements to draw.
<li> (Number - optional) Number of instances to draw of the given range.
<li> (Number - optional) Base instance to begin drawing.
<li> (Number - optional) Base vertex to begin drawing.
</ul>
@return {DrawCall} The DrawCall object.
*/
Expand All @@ -185,12 +191,26 @@ export class DrawCall {
this.numInstances = new Int32Array(this.numDraws);
}

if (this.baseInstances.length < this.numDraws) {
this.baseInstances = new Uint32Array(this.numDraws);
}

if (this.baseVertices.length < this.numDraws) {
this.baseVertices = new Int32Array(this.numDraws);
}

for (let i = 0; i < this.numDraws; ++i) {
let count = counts[i];

this.offsets[i] = count[0];
this.numElements[i] = count[1];
this.numInstances[i] = count[2] || 1;
this.baseInstances[i] = count[3] || 0;
this.baseVertices[i] = count[4] || 0;

this.hasBaseInstancesOrBaseVertices = this.hasBaseInstancesOrBaseVertices
|| this.baseInstances[i]
|| this.baseVertices[i];
}

this.drawCountsFromVertexArray = false;
Expand Down Expand Up @@ -245,7 +265,29 @@ export class DrawCall {
this.appState.transformFeedback = null;
}

if (WEBGL_INFO.MULTI_DRAW_INSTANCED) {
if (this.hasBaseInstancesOrBaseVertices && !(WEBGL_INFO.DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE || WEBGL_INFO.MULTI_DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE)) {
console.warn("DrawCall.draw 'baseInstances' or 'baseVertices' have been set but the required WebGL extensions are not available; 'WEBGL_multidraw_instanced_base_vertex_base_instance' or 'WEBGL_draw_instanced_base_vertex_base_instance' are needed.");
}

if (WEBGL_INFO.MULTI_DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE) {
let ext = this.appState.extensions.multiDrawInstancedBaseVertexBaseInstance;
if (indexed) {
ext.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(this.drawPrimitive, this.numElements, 0, this.currentVertexArray.indexType, this.offsets, 0, this.numInstances, 0, this.baseVertices, 0, this.baseInstances, 0, this.numDraws);
} else {
ext.multiDrawArraysInstancedBaseInstanceWEBGL(this.drawPrimitive, this.offsets, 0, this.numElements, 0, this.numInstances, 0, this.baseInstances, 0, this.numDraws);
}
} else if (this.hasBaseInstancesOrBaseVertices && WEBGL_INFO.DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE) {
let ext = this.appState.extensions.drawInstancedBaseVertexBaseInstance;
if (indexed) {
for (let i = 0; i < this.numDraws; ++i) {
ext.drawElementsInstancedBaseVertexBaseInstanceWEBGL(this.drawPrimitive, this.numElements[i], this.currentVertexArray.indexType, this.offsets[i], this.numInstances[i], this.baseVertices[i], this.baseInstances[i]);
}
} else {
for (let i = 0; i < this.numDraws; ++i) {
ext.drawArraysInstancedBaseInstanceWEBGL(this.drawPrimitive, this.offsets[i], this.numElements[i], this.numInstances[i], this.baseInstances[i]);
}
}
} else if (WEBGL_INFO.MULTI_DRAW_INSTANCED) {
let ext = this.appState.extensions.multiDrawInstanced;
if (indexed) {
ext.multiDrawElementsInstancedWEBGL(this.drawPrimitive, this.numElements, 0, this.currentVertexArray.indexType, this.offsets, 0, this.numInstances, 0, this.numDraws);
Expand Down
2 changes: 2 additions & 0 deletions src/picogl.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export const PicoGL = Object.assign({
// Draft extensions
WEBGL_INFO.PARALLEL_SHADER_COMPILE = Boolean(gl.getExtension("KHR_parallel_shader_compile"));
WEBGL_INFO.MULTI_DRAW_INSTANCED = Boolean(gl.getExtension("WEBGL_multi_draw_instanced"));
WEBGL_INFO.DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE = Boolean(gl.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));
WEBGL_INFO.MULTI_DRAW_INSTANCED_BASE_VERTEX_BASE_INSTANCE = Boolean(gl.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));

webglInfoInitialized = true;
}
Expand Down

0 comments on commit c7a541d

Please sign in to comment.