From f8393f18c2786a3dd257e1e9e2df5ef119bd786d Mon Sep 17 00:00:00 2001 From: Brandel Zachernuk Date: Mon, 19 Feb 2024 15:04:13 -0800 Subject: [PATCH 1/3] Add webXR capability to MotionMark Update the main harness to pass through a frame object where extant, Update the main harness to use an internally-stored `requestAnimationFrame` to be rerouted in the case of webXR tests, Add the webXR capabilities to the base webGL test --- MotionMark/resources/debug-runner/tests.js | 16 +++ MotionMark/tests/3d/resources/webgl.js | 131 +++++++++++++++++++-- MotionMark/tests/resources/main.js | 12 +- 3 files changed, 143 insertions(+), 16 deletions(-) diff --git a/MotionMark/resources/debug-runner/tests.js b/MotionMark/resources/debug-runner/tests.js index f48d0b1..b914f61 100644 --- a/MotionMark/resources/debug-runner/tests.js +++ b/MotionMark/resources/debug-runner/tests.js @@ -353,10 +353,26 @@ Suites.push(new Suite("Suits suite", Suites.push(new Suite("3D Graphics", [ + { + url: "3d/triangles-webgl.html?triangleSize=1.0", + name: "Triangles (WebGL, large)" + }, + { + url: "3d/triangles-webgl.html?triangleSize=0.01", + name: "Triangles (WebGL, small)" + }, + { + url: "3d/triangles-webgl.html?blended", + name: "Triangles (WebGL, blended)" + }, { url: "3d/triangles-webgl.html", name: "Triangles (WebGL)" }, + { + url: "3d/triangles-webgl.html?webxr", + name: "Triangles (WebXR)" + }, { url: "3d/triangles-webgpu.html", name: "Triangles (WebGPU)" diff --git a/MotionMark/tests/3d/resources/webgl.js b/MotionMark/tests/3d/resources/webgl.js index 33dc0fe..7ac1a83 100644 --- a/MotionMark/tests/3d/resources/webgl.js +++ b/MotionMark/tests/3d/resources/webgl.js @@ -37,8 +37,12 @@ WebGLStage = Utilities.createSubclass(Stage, this._numTriangles = 0; this._bufferSize = 0; - - this._gl = this.element.getContext("webgl"); + this._testOptions = new URLSearchParams(document.location.search); + if(this._testOptions.has("webxr")) { + this._gl = this.element.getContext('webgl2',{antialias:true, xrCompatible: true}); + } else { + this._gl = this.element.getContext("webgl"); + } var gl = this._gl; gl.clearColor(0, 0, 0, 1); @@ -81,6 +85,10 @@ WebGLStage = Utilities.createSubclass(Stage, // Our program has two inputs. We have a single uniform "color", // and one vertex attribute "position". + if(this._testOptions.has("blended")) { + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_COLOR, gl.DST_COLOR); + } gl.useProgram(program); this._uScale = gl.getUniformLocation(program, "scale"); @@ -96,28 +104,89 @@ WebGLStage = Utilities.createSubclass(Stage, this._aColor = gl.getAttribLocation(program, "color"); gl.enableVertexAttribArray(this._aColor); + let s = 0.1; + if(this._testOptions.has("triangleSize")) { + s = parseFloat(this._testOptions.get("triangleSize")); + } this._positionData = new Float32Array([ // x y z 1 - 0, 0.1, 0, 1, - -0.1, -0.1, 0, 1, - 0.1, -0.1, 0, 1 + 0, s, 0, 1, + -s, -s, 0, 1, + s, -s, 0, 1 ]); this._positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._positionData, gl.STATIC_DRAW); + const brightness = 0.1; this._colorData = new Float32Array([ - 1, 0, 0, 1, - 0, 1, 0, 1, - 0, 0, 1, 1 + brightness, 0, 0, brightness, + 0, brightness, 0, brightness, + 0, 0, brightness, brightness ]); this._colorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._colorData, gl.STATIC_DRAW); + if(this._testOptions.has("webxr")) { + this._benchmark._requestAnimationFrame = ()=>{}; + var startButton = this._makeVRButton(); + } + this._resetIfNecessary(); }, + _makeVRButton: function() + { + var button = document.createElement('div'); + + Object.assign(button.style, { + position:'fixed', + top:0, + left:0, + width:'300px', + height:'30px', + fontSize:'1.5rem', + border:'thin solid white', + color:'white', + backgroundColor:'black', + margin:'20px', + textAlign:'center', + borderRadius:'20px' + }); + + if(navigator.xr!=null) { + button.innerHTML = "Open webXR view"; + button.addEventListener('click', clickEvent=>{ + this._launchXR(); + }); + } else button.innerHTML = "WebXR Not supported"; + + document.body.appendChild(button); + }, + + _launchXR: function() + { + navigator.xr.requestSession('immersive-vr', {optionalFeatures: []}) + .then(session=>{ + var gl = this._gl; + session.addEventListener('end', e=>{ + this._requestAnimationFrame = (rafFunction,frame)=> + window.requestAnimationFrame(rafFunction ,frame); + }); + const baseLayer = new XRWebGLLayer(session, gl); + session.updateRenderState({ baseLayer }); + session.requestReferenceSpace('local').then(refSpace=>{ + this.xrRefSpace = refSpace; + this._benchmark._requestAnimationFrame = (rafFunction)=>{ + session.requestAnimationFrame((t,frame)=>rafFunction(t,frame)); + }; + this._benchmark._requestAnimationFrame(this._benchmark._animateLoop); + }); + }); + }, + + _getFunctionSource: function(id) { return document.getElementById(id).text; @@ -156,16 +225,56 @@ WebGLStage = Utilities.createSubclass(Stage, this._resetIfNecessary(); }, - animate: function(timeDelta) + animate: function(timeDelta, xrFrame) + { + if(xrFrame) { + this.animateXR(timeDelta, xrFrame); + } else { + this.animate2D(timeDelta); + } + }, + + animate2D: function(timeDelta) { var gl = this._gl; - gl.clear(gl.COLOR_BUFFER_BIT); + + if (!this._startTime) + this._startTime = Stage.dateCounterValue(1000); + var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + this._animateInternal(elapsedTime); + + }, + + animateXR: function (t,frame) { + var gl = this._gl; if (!this._startTime) - this._startTime = Stage.dateCounterValue(1000); + this._startTime = Stage.dateCounterValue(1000); var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + + let pose = frame.getViewerPose(this.xrRefSpace); + let glLayer = frame.session.renderState.baseLayer; + + if(pose) { + gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer); + + for (let view of pose.views) { + let viewport = glLayer.getViewport(view); + gl.viewport(viewport.x, viewport.y, + viewport.width, viewport.height); + this._animateInternal(elapsedTime); + } + } + }, + _animateInternal: function (elapsedTime) { + let gl = this._gl; + for (var i = 0; i < this._numTriangles; ++i) { this._uniformData[i * 6 + 1] = elapsedTime; diff --git a/MotionMark/tests/resources/main.js b/MotionMark/tests/resources/main.js index ca7f2a9..58f5438 100644 --- a/MotionMark/tests/resources/main.js +++ b/MotionMark/tests/resources/main.js @@ -891,6 +891,8 @@ Benchmark = Utilities.createClass( this._firstFrameMinimumLength = options["first-frame-minimum-length"]; this._stage = stage; + this._requestAnimationFrame = rafFunction=> window.requestAnimationFrame(rafFunction) + this._stage.initialize(this, options); switch (options["time-measurement"]) @@ -960,7 +962,7 @@ Benchmark = Utilities.createClass( return promise; }, - _animateLoop: function(timestamp) + _animateLoop: function(timestamp,frame) { timestamp = (this._getTimestamp && this._getTimestamp()) || timestamp; this._currentTimestamp = timestamp; @@ -984,15 +986,15 @@ Benchmark = Utilities.createClass( } } - this._stage.animate(0); + this._stage.animate(0,frame); ++this._frameCount; - requestAnimationFrame(this._animateLoop); + this._requestAnimationFrame(this._animateLoop); return; } this._controller.update(timestamp, this._stage); - this._stage.animate(timestamp - this._previousTimestamp); + this._stage.animate(timestamp - this._previousTimestamp,frame); this._previousTimestamp = timestamp; - requestAnimationFrame(this._animateLoop); + this._requestAnimationFrame(this._animateLoop); } }); From 7bbf28f9d489f10502064cdbd09b9e0590ed53a6 Mon Sep 17 00:00:00 2001 From: Brandel Zachernuk Date: Fri, 23 Feb 2024 16:07:32 -0800 Subject: [PATCH 2/3] Revert "Add webXR capability to MotionMark" This reverts commit f8393f18c2786a3dd257e1e9e2df5ef119bd786d. --- MotionMark/resources/debug-runner/tests.js | 16 --- MotionMark/tests/3d/resources/webgl.js | 131 ++------------------- MotionMark/tests/resources/main.js | 12 +- 3 files changed, 16 insertions(+), 143 deletions(-) diff --git a/MotionMark/resources/debug-runner/tests.js b/MotionMark/resources/debug-runner/tests.js index b914f61..f48d0b1 100644 --- a/MotionMark/resources/debug-runner/tests.js +++ b/MotionMark/resources/debug-runner/tests.js @@ -353,26 +353,10 @@ Suites.push(new Suite("Suits suite", Suites.push(new Suite("3D Graphics", [ - { - url: "3d/triangles-webgl.html?triangleSize=1.0", - name: "Triangles (WebGL, large)" - }, - { - url: "3d/triangles-webgl.html?triangleSize=0.01", - name: "Triangles (WebGL, small)" - }, - { - url: "3d/triangles-webgl.html?blended", - name: "Triangles (WebGL, blended)" - }, { url: "3d/triangles-webgl.html", name: "Triangles (WebGL)" }, - { - url: "3d/triangles-webgl.html?webxr", - name: "Triangles (WebXR)" - }, { url: "3d/triangles-webgpu.html", name: "Triangles (WebGPU)" diff --git a/MotionMark/tests/3d/resources/webgl.js b/MotionMark/tests/3d/resources/webgl.js index 7ac1a83..33dc0fe 100644 --- a/MotionMark/tests/3d/resources/webgl.js +++ b/MotionMark/tests/3d/resources/webgl.js @@ -37,12 +37,8 @@ WebGLStage = Utilities.createSubclass(Stage, this._numTriangles = 0; this._bufferSize = 0; - this._testOptions = new URLSearchParams(document.location.search); - if(this._testOptions.has("webxr")) { - this._gl = this.element.getContext('webgl2',{antialias:true, xrCompatible: true}); - } else { - this._gl = this.element.getContext("webgl"); - } + + this._gl = this.element.getContext("webgl"); var gl = this._gl; gl.clearColor(0, 0, 0, 1); @@ -85,10 +81,6 @@ WebGLStage = Utilities.createSubclass(Stage, // Our program has two inputs. We have a single uniform "color", // and one vertex attribute "position". - if(this._testOptions.has("blended")) { - gl.enable(gl.BLEND); - gl.blendFunc(gl.SRC_COLOR, gl.DST_COLOR); - } gl.useProgram(program); this._uScale = gl.getUniformLocation(program, "scale"); @@ -104,89 +96,28 @@ WebGLStage = Utilities.createSubclass(Stage, this._aColor = gl.getAttribLocation(program, "color"); gl.enableVertexAttribArray(this._aColor); - let s = 0.1; - if(this._testOptions.has("triangleSize")) { - s = parseFloat(this._testOptions.get("triangleSize")); - } this._positionData = new Float32Array([ // x y z 1 - 0, s, 0, 1, - -s, -s, 0, 1, - s, -s, 0, 1 + 0, 0.1, 0, 1, + -0.1, -0.1, 0, 1, + 0.1, -0.1, 0, 1 ]); this._positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._positionData, gl.STATIC_DRAW); - const brightness = 0.1; this._colorData = new Float32Array([ - brightness, 0, 0, brightness, - 0, brightness, 0, brightness, - 0, 0, brightness, brightness + 1, 0, 0, 1, + 0, 1, 0, 1, + 0, 0, 1, 1 ]); this._colorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._colorData, gl.STATIC_DRAW); - if(this._testOptions.has("webxr")) { - this._benchmark._requestAnimationFrame = ()=>{}; - var startButton = this._makeVRButton(); - } - this._resetIfNecessary(); }, - _makeVRButton: function() - { - var button = document.createElement('div'); - - Object.assign(button.style, { - position:'fixed', - top:0, - left:0, - width:'300px', - height:'30px', - fontSize:'1.5rem', - border:'thin solid white', - color:'white', - backgroundColor:'black', - margin:'20px', - textAlign:'center', - borderRadius:'20px' - }); - - if(navigator.xr!=null) { - button.innerHTML = "Open webXR view"; - button.addEventListener('click', clickEvent=>{ - this._launchXR(); - }); - } else button.innerHTML = "WebXR Not supported"; - - document.body.appendChild(button); - }, - - _launchXR: function() - { - navigator.xr.requestSession('immersive-vr', {optionalFeatures: []}) - .then(session=>{ - var gl = this._gl; - session.addEventListener('end', e=>{ - this._requestAnimationFrame = (rafFunction,frame)=> - window.requestAnimationFrame(rafFunction ,frame); - }); - const baseLayer = new XRWebGLLayer(session, gl); - session.updateRenderState({ baseLayer }); - session.requestReferenceSpace('local').then(refSpace=>{ - this.xrRefSpace = refSpace; - this._benchmark._requestAnimationFrame = (rafFunction)=>{ - session.requestAnimationFrame((t,frame)=>rafFunction(t,frame)); - }; - this._benchmark._requestAnimationFrame(this._benchmark._animateLoop); - }); - }); - }, - - _getFunctionSource: function(id) { return document.getElementById(id).text; @@ -225,56 +156,16 @@ WebGLStage = Utilities.createSubclass(Stage, this._resetIfNecessary(); }, - animate: function(timeDelta, xrFrame) - { - if(xrFrame) { - this.animateXR(timeDelta, xrFrame); - } else { - this.animate2D(timeDelta); - } - }, - - animate2D: function(timeDelta) + animate: function(timeDelta) { var gl = this._gl; - - if (!this._startTime) - this._startTime = Stage.dateCounterValue(1000); - var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - this._animateInternal(elapsedTime); - - }, - - animateXR: function (t,frame) { - var gl = this._gl; + gl.clear(gl.COLOR_BUFFER_BIT); if (!this._startTime) - this._startTime = Stage.dateCounterValue(1000); + this._startTime = Stage.dateCounterValue(1000); var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - - let pose = frame.getViewerPose(this.xrRefSpace); - let glLayer = frame.session.renderState.baseLayer; - - if(pose) { - gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer); - - for (let view of pose.views) { - let viewport = glLayer.getViewport(view); - gl.viewport(viewport.x, viewport.y, - viewport.width, viewport.height); - this._animateInternal(elapsedTime); - } - } - }, - _animateInternal: function (elapsedTime) { - let gl = this._gl; - for (var i = 0; i < this._numTriangles; ++i) { this._uniformData[i * 6 + 1] = elapsedTime; diff --git a/MotionMark/tests/resources/main.js b/MotionMark/tests/resources/main.js index 58f5438..ca7f2a9 100644 --- a/MotionMark/tests/resources/main.js +++ b/MotionMark/tests/resources/main.js @@ -891,8 +891,6 @@ Benchmark = Utilities.createClass( this._firstFrameMinimumLength = options["first-frame-minimum-length"]; this._stage = stage; - this._requestAnimationFrame = rafFunction=> window.requestAnimationFrame(rafFunction) - this._stage.initialize(this, options); switch (options["time-measurement"]) @@ -962,7 +960,7 @@ Benchmark = Utilities.createClass( return promise; }, - _animateLoop: function(timestamp,frame) + _animateLoop: function(timestamp) { timestamp = (this._getTimestamp && this._getTimestamp()) || timestamp; this._currentTimestamp = timestamp; @@ -986,15 +984,15 @@ Benchmark = Utilities.createClass( } } - this._stage.animate(0,frame); + this._stage.animate(0); ++this._frameCount; - this._requestAnimationFrame(this._animateLoop); + requestAnimationFrame(this._animateLoop); return; } this._controller.update(timestamp, this._stage); - this._stage.animate(timestamp - this._previousTimestamp,frame); + this._stage.animate(timestamp - this._previousTimestamp); this._previousTimestamp = timestamp; - this._requestAnimationFrame(this._animateLoop); + requestAnimationFrame(this._animateLoop); } }); From 509c6980dd93d8f41e39a4856c281b3421697287 Mon Sep 17 00:00:00 2001 From: Brandel Zachernuk Date: Fri, 23 Feb 2024 16:17:15 -0800 Subject: [PATCH 3/3] Enable webXR without changes to the Benchmark runner files Use the test itself to change the containing Benchmark's functionality to use the XRSession's requestAnimationFrame and to shuttle through the frame information. --- MotionMark/resources/debug-runner/tests.js | 4 + MotionMark/tests/3d/resources/webgl.js | 171 +++++++++++++++++++-- 2 files changed, 164 insertions(+), 11 deletions(-) diff --git a/MotionMark/resources/debug-runner/tests.js b/MotionMark/resources/debug-runner/tests.js index f48d0b1..11d7bea 100644 --- a/MotionMark/resources/debug-runner/tests.js +++ b/MotionMark/resources/debug-runner/tests.js @@ -357,6 +357,10 @@ Suites.push(new Suite("3D Graphics", url: "3d/triangles-webgl.html", name: "Triangles (WebGL)" }, + { + url: "3d/triangles-webgl.html?webxr=true", + name: "Triangles (WebXR)" + }, { url: "3d/triangles-webgpu.html", name: "Triangles (WebGPU)" diff --git a/MotionMark/tests/3d/resources/webgl.js b/MotionMark/tests/3d/resources/webgl.js index 33dc0fe..aa89715 100644 --- a/MotionMark/tests/3d/resources/webgl.js +++ b/MotionMark/tests/3d/resources/webgl.js @@ -37,12 +37,17 @@ WebGLStage = Utilities.createSubclass(Stage, this._numTriangles = 0; this._bufferSize = 0; - - this._gl = this.element.getContext("webgl"); + this._testOptions = new URLSearchParams(document.location.search); + if(this._testOptions.has("webxr")) { + this._overrideAnimationLoop(benchmark); + this._gl = this.element.getContext('webgl2',{antialias:true, xrCompatible: true}); + } else { + this._gl = this.element.getContext("webgl"); + } var gl = this._gl; gl.clearColor(0, 0, 0, 1); - + // Create the vertex shader object. var vertexShader = gl.createShader(gl.VERTEX_SHADER); @@ -81,6 +86,10 @@ WebGLStage = Utilities.createSubclass(Stage, // Our program has two inputs. We have a single uniform "color", // and one vertex attribute "position". + if(this._testOptions.has("blended")) { + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_COLOR, gl.DST_COLOR); + } gl.useProgram(program); this._uScale = gl.getUniformLocation(program, "scale"); @@ -96,28 +105,128 @@ WebGLStage = Utilities.createSubclass(Stage, this._aColor = gl.getAttribLocation(program, "color"); gl.enableVertexAttribArray(this._aColor); + let s = 0.1; + if(this._testOptions.has("triangleSize")) { + s = parseFloat(this._testOptions.get("triangleSize")); + } this._positionData = new Float32Array([ // x y z 1 - 0, 0.1, 0, 1, - -0.1, -0.1, 0, 1, - 0.1, -0.1, 0, 1 + 0, s, 0, 1, + -s, -s, 0, 1, + s, -s, 0, 1 ]); this._positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._positionData, gl.STATIC_DRAW); + const brightness = 0.1; this._colorData = new Float32Array([ - 1, 0, 0, 1, - 0, 1, 0, 1, - 0, 0, 1, 1 + brightness, 0, 0, brightness, + 0, brightness, 0, brightness, + 0, 0, brightness, brightness ]); this._colorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this._colorData, gl.STATIC_DRAW); + if(this._testOptions.has("webxr")) { + this._benchmark._requestAnimationFrame = ()=>{}; + var startButton = this._makeVRButton(); + } + this._resetIfNecessary(); }, + _overrideAnimationLoop: function(benchmark) { + + benchmark._oldAnimateLoop = benchmark._animateLoop; + benchmark._animateLoop = function(timestamp, xrFrame) { + timestamp = (this._getTimestamp && this._getTimestamp()) || timestamp; + this._currentTimestamp = timestamp; + + if (this._controller.shouldStop(timestamp)) { + this._finishPromise.resolve(this._controller.results()); + return; + } + + if (!this._didWarmUp) { + if (!this._previousTimestamp) { + this._previousTimestamp = timestamp; + this._benchmarkStartTimestamp = timestamp; + } else if (timestamp - this._previousTimestamp >= this._warmupLength && this._frameCount >= this._warmupFrameCount) { + this._didWarmUp = true; + this._benchmarkStartTimestamp = timestamp; + this._controller.start(timestamp, this._stage); + this._previousTimestamp = timestamp; + + while (this._getTimestamp && this._getTimestamp() - timestamp < this._firstFrameMinimumLength) { + } + } + + this._stage.animate(0,xrFrame); + ++this._frameCount; + if(xrFrame) { xrFrame.session.requestAnimationFrame(this._animateLoop); } + return; + } + + this._controller.update(timestamp, this._stage); + this._stage.animate(timestamp - this._previousTimestamp,xrFrame); + this._previousTimestamp = timestamp; + xrFrame.session.requestAnimationFrame(this._animateLoop); + }.bind(benchmark); + }, + + _makeVRButton: function() + { + var button = document.createElement('div'); + + Object.assign(button.style, { + position:'fixed', + top:0, + left:0, + width:'300px', + height:'30px', + fontSize:'1.5rem', + border:'thin solid white', + color:'white', + backgroundColor:'black', + margin:'20px', + textAlign:'center', + borderRadius:'20px' + }); + + if(navigator.xr!=null) { + button.innerHTML = "Open webXR view"; + button.addEventListener('click', clickEvent=>{ + this._launchXR(); + }); + } else button.innerHTML = "WebXR Not supported"; + + document.body.appendChild(button); + }, + + _launchXR: function() + { + navigator.xr.requestSession('immersive-vr', {optionalFeatures: []}) + .then(session=>{ + var gl = this._gl; + session.addEventListener('end', e=>{ + this._requestAnimationFrame = (rafFunction,frame)=> + window.requestAnimationFrame(rafFunction ,frame); + }); + const baseLayer = new XRWebGLLayer(session, gl); + session.updateRenderState({ baseLayer }); + session.requestReferenceSpace('local').then(refSpace=>{ + this.xrRefSpace = refSpace; + this._benchmark._requestAnimationFrame = (rafFunction)=>{ + session.requestAnimationFrame((t,frame)=>rafFunction(t,frame)); + }; + this._benchmark._requestAnimationFrame(this._benchmark._animateLoop); + }); + }); + }, + + _getFunctionSource: function(id) { return document.getElementById(id).text; @@ -156,16 +265,56 @@ WebGLStage = Utilities.createSubclass(Stage, this._resetIfNecessary(); }, - animate: function(timeDelta) + animate: function(timeDelta, xrFrame) + { + if(xrFrame) { + this.animateXR(timeDelta, xrFrame); + } else { + this.animate2D(timeDelta); + } + }, + + animate2D: function(timeDelta) { var gl = this._gl; - gl.clear(gl.COLOR_BUFFER_BIT); + + if (!this._startTime) + this._startTime = Stage.dateCounterValue(1000); + var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + this._animateInternal(elapsedTime); + + }, + + animateXR: function (t,frame) { + var gl = this._gl; if (!this._startTime) this._startTime = Stage.dateCounterValue(1000); var elapsedTime = Stage.dateCounterValue(1000) - this._startTime; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + + let pose = frame.getViewerPose(this.xrRefSpace); + let glLayer = frame.session.renderState.baseLayer; + + if(pose) { + gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer); + + for (let view of pose.views) { + let viewport = glLayer.getViewport(view); + gl.viewport(viewport.x, viewport.y, + viewport.width, viewport.height); + this._animateInternal(elapsedTime); + } + } + }, + _animateInternal: function (elapsedTime) { + let gl = this._gl; + for (var i = 0; i < this._numTriangles; ++i) { this._uniformData[i * 6 + 1] = elapsedTime;