Bug 1229481 - Part 2: Add draw rect reftest for WebVR; r=kip
authorDaosheng Mu <daoshengmu@gmail.com>
Fri, 05 May 2017 19:00:25 +0800
changeset 410172 bce41e33bffd069768eba7acb4cb121f1613307a
parent 410171 7c13bf6be43e4af673ad9a53838233db45cd8fc2
child 410173 6fc608d6f3fdf0c8e8fa8301f01846a07b39d2c9
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip
bugs1229481
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1229481 - Part 2: Add draw rect reftest for WebVR; r=kip MozReview-Commit-ID: CnSYFFZS8lP
dom/vr/moz.build
dom/vr/test/reftest/VRSimulationDriver.js
dom/vr/test/reftest/draw_rect.html
dom/vr/test/reftest/draw_rect.png
dom/vr/test/reftest/reftest.list
dom/vr/test/reftest/webgl-util.js
dom/vr/test/reftest/wrapper.html
layout/reftests/reftest.list
--- a/dom/vr/moz.build
+++ b/dom/vr/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
-    BUG_COMPONENT = ("Core", "DOM")
+    BUG_COMPONENT = ("Core", "WebVR")
 
 EXPORTS.mozilla.dom += [
     'VRDisplay.h',
     'VRDisplayEvent.h',
     'VREventObserver.h',
     'VRServiceTest.h'
     ]
 
@@ -23,9 +23,10 @@ UNIFIED_SOURCES = [
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/dom/base'
 ]
 
-MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
\ No newline at end of file
+MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
+REFTEST_MANIFESTS += ['test/reftest/reftest.list']
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/reftest/VRSimulationDriver.js
@@ -0,0 +1,56 @@
+
+var VRServiceTest;
+var vrMockDisplay;
+
+var VRSimulationDriver = (function() {
+"use strict";
+
+var AttachWebVRDisplay = function() {
+  var promise = VRServiceTest.attachVRDisplay("VRDisplayTest");
+  promise.then(function (display) {
+    vrMockDisplay = display;
+  });
+
+  return promise;
+};
+
+var SetVRDisplayPose = function(position,
+                                linearVelocity, linearAcceleration,
+                                orientation, angularVelocity,
+                                angularAcceleration) {
+  vrMockDisplay.setPose(position, linearVelocity, linearAcceleration,
+                        orientation, angularVelocity, angularAcceleration);
+};
+
+var SetEyeResolution = function(width, height) {
+  vrMockDisplay.setEyeResolution(width, height);
+}
+
+var SetEyeParameter = function(eye, offsetX, offsetY, offsetZ,
+                               upDegree, rightDegree, downDegree, leftDegree) {
+  vrMockDisplay.setEyeParameter(eye, offsetX, offsetY, offsetZ, upDegree, rightDegree,
+                                downDegree, leftDegree);
+}
+
+var SetMountState = function(isMounted) {
+  vrMockDisplay.setMountState(isMounted);
+}
+
+var UpdateVRDisplay = function() {
+  vrMockDisplay.update();
+}
+
+var API = {
+  AttachWebVRDisplay: AttachWebVRDisplay,
+  SetVRDisplayPose: SetVRDisplayPose,
+  SetEyeResolution: SetEyeResolution,
+  SetEyeParameter: SetEyeParameter,
+  SetMountState: SetMountState,
+  UpdateVRDisplay: UpdateVRDisplay,
+
+  none: false
+};
+
+return API;
+
+}());
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/reftest/draw_rect.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!-- Draw rect in WebGL and submit it to the VR device as a base64 image.
+If this fails, something is seriously wrong. -->
+<html class="reftest-wait">
+<head>
+  <script type='text/javascript' src='webgl-util.js'></script>
+  <script type='text/javascript' src="VRSimulationDriver.js"></script>
+  <script id="vs" type="x-shader/x-vertex">
+    attribute vec2 aVertCoord;
+
+    void main(void) {
+      gl_Position = vec4(aVertCoord, 0.0, 1.0);
+    }
+  </script>
+  <script id="fs" type="x-shader/x-fragment">
+    precision mediump float;
+
+    void main(void) {
+      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+    }
+  </script>
+  <script type='text/javascript'>
+    'use strict';
+
+    var submitResult = null;
+    var vrDisplay = null;
+    var webglCanvas = null;
+    var gl = null;
+    var prog = null;
+    var img = null;
+
+    function setStatus(text) {
+      var elem = document.getElementById('status');
+      elem.innerHTML = text;
+    }
+
+    function initVRMock() {
+      VRServiceTest = navigator.requestVRServiceTest();
+      if (!VRServiceTest) {
+        setStatus('VRServiceTest get failed.');
+        return;
+      }
+
+      VRSimulationDriver.AttachWebVRDisplay().then(() => {
+        // Looking for VR displays
+        if (navigator.getVRDisplays) {
+          submitResult = new VRSubmitFrameResult();
+          navigator.getVRDisplays().then(function (displays) {
+            if (displays.length > 0) {
+              vrDisplay = displays[0];
+              vrDisplay.requestPresent([{ source: webglCanvas }]);
+              vrDisplay.requestAnimationFrame(onAnimationFrame);
+            }
+          });
+        }
+      });
+    }
+
+    function onAnimationFrame() {
+      if (!vrDisplay.isPresenting) {
+        return;
+      }
+
+      vrDisplay.requestAnimationFrame(onAnimationFrame);
+      gl.clearColor(0.0, 1.0, 0.0, 1.0);
+      gl.clear(gl.COLOR_BUFFER_BIT);
+
+      // Presenting render a stereo view.
+      gl.viewport(0, 0, webglCanvas.width * 0.5, webglCanvas.height);
+      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+      gl.viewport(webglCanvas.width * 0.5, 0, webglCanvas.width * 0.5, webglCanvas.height);
+      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+      // Indicate VRDisplay we're done rendering.
+      vrDisplay.submitFrame();
+      if (vrDisplay.getSubmitFrameResult(submitResult)) {
+        if (!img) {
+          img = document.createElement("img");
+          img.onload = function(){
+            webglCanvas.style.display = 'none';
+            vrDisplay.exitPresent();
+            setTimeout(testComplete, 0);
+          };
+          img.src = submitResult.base64Image;
+          document.body.appendChild(img);
+        } else {
+          img.src = submitResult.base64Image;
+        }
+      }
+    }
+
+    function runTest() {
+      webglCanvas = document.getElementById('canvas');
+      gl = WebGLUtil.getWebGL('canvas');
+      if (!gl) {
+        setStatus('WebGL context creation failed.');
+        return;
+      }
+      gl.disable(gl.DEPTH_TEST);
+      prog = WebGLUtil.createProgramByIds(gl, 'vs', 'fs');
+      if (!prog) {
+        setStatus('Program linking failed.');
+        return;
+      }
+      prog.aVertCoord = gl.getAttribLocation(prog, "aVertCoord");
+
+      var vertCoordArr = new Float32Array([
+        -0.5, -0.5,
+        0.5, -0.5,
+        -0.5, 0.5,
+        0.5, 0.5,
+      ]);
+      var vertCoordBuff = gl.createBuffer();
+      gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff);
+      gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW);
+      gl.useProgram(prog);
+      gl.enableVertexAttribArray(prog.aVertCoord);
+      gl.vertexAttribPointer(prog.aVertCoord, 2, gl.FLOAT, false, 0, 0);
+
+      initVRMock();
+    }
+
+    function testComplete() {
+      document.documentElement.removeAttribute("class");
+    }
+  </script>
+</head>
+
+<body onload='runTest();'>
+  <canvas id='canvas' width='256' height='256'></canvas>
+  <div id='status'></div>
+</body>
+
+</html>
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0f4d24a0d19ea26224adb3d90dab146f5a4c7a95
GIT binary patch
literal 1747
zc%17D@N?(olHy`uVBq!ia0y~yU}OMc4mKbaQ?w$Dfq`w7r;B4q#hkYnH}WzV@EqRo
z=YL5x8#{MPnextR&$N$>o-%d{orl>~3V$@H@X1d&@{oCwMU8_{JHN-H55q&!oxfuH
zU8~x9+2!mn*k4?G`TMnnt%JS8cE9`a$6qr3V%$~w>z|b${{{XFYcGGlURc#o*N``N
z-~PVK%wL#GUVr&pI!A7S{DSD^@7F*6!tj@2)TmLTMvWRZie^R)e2GaH$wWJisj`nh
THge7eR#pt2u6{1-oD!M<+goFD
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/reftest/reftest.list
@@ -0,0 +1,7 @@
+# WebVR Reftests
+default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1)
+
+# VR SubmitFrame is only implemented for D3D11 now.
+# We need to continue to investigate why these reftests can be run well in local,
+# but will be suspended until terminating on reftest debug build.
+skip-if(!winWidget||!layersGPUAccelerated||isDebugBuild) == draw_rect.html wrapper.html?draw_rect.png
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/reftest/webgl-util.js
@@ -0,0 +1,170 @@
+WebGLUtil = (function() {
+  // ---------------------------------------------------------------------------
+  // Error handling (for obvious failures, such as invalid element ids)
+
+  function defaultErrorFunc(str) {
+    console.log('Error: ' + str);
+  }
+
+  var gErrorFunc = defaultErrorFunc;
+  function setErrorFunc(func) {
+    gErrorFunc = func;
+  }
+
+  function error(str) {
+    gErrorFunc(str);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Warning handling (for failures that may be intentional)
+
+  function defaultWarningFunc(str) {
+    console.log('Warning: ' + str);
+  }
+
+  var gWarningFunc = defaultWarningFunc;
+  function setWarningFunc(func) {
+    gWarningFunc = func;
+  }
+
+  function warning(str) {
+    gWarningFunc(str);
+  }
+
+  // ---------------------------------------------------------------------------
+  // WebGL helpers
+
+  function getWebGL(canvasId, requireConformant, attributes) {
+    // `requireConformant` will default to falsey if it is not supplied.
+
+    var canvas = document.getElementById(canvasId);
+
+    var gl = null;
+    try {
+      gl = canvas.getContext('webgl', attributes);
+    } catch(e) {}
+
+    if (!gl && !requireConformant) {
+      try {
+        gl = canvas.getContext('experimental-webgl', attributes);
+      } catch(e) {}
+    }
+
+    if (!gl) {
+      error('WebGL context could not be retrieved from \'' + canvasId + '\'.');
+      return null;
+    }
+
+    return gl;
+  }
+
+  function withWebGL2(canvasId, callback, onFinished) {
+    var run = function() {
+      var canvas = document.getElementById(canvasId);
+
+      var gl = null;
+      try {
+        gl = canvas.getContext('webgl2');
+      } catch(e) {}
+
+      if (!gl) {
+        todo(false, 'WebGL2 is not supported');
+        onFinished();
+        return;
+      }
+
+      function errorFunc(str) {
+        ok(false, 'Error: ' + str);
+      }
+      setErrorFunc(errorFunc);
+      setWarningFunc(errorFunc);
+
+      callback(gl);
+      onFinished();
+    };
+
+    try {
+      var prefArrArr = [
+        ['webgl.force-enabled', true],
+        ['webgl.enable-webgl2', true],
+      ];
+      var prefEnv = {'set': prefArrArr};
+      SpecialPowers.pushPrefEnv(prefEnv, run);
+    } catch (e) {
+      warning('No SpecialPowers, but trying WebGL2 anyway...');
+      run();
+    }
+  }
+
+  function getContentFromElem(elem) {
+    var str = "";
+    var k = elem.firstChild;
+    while (k) {
+      if (k.nodeType == 3)
+        str += k.textContent;
+
+      k = k.nextSibling;
+    }
+
+    return str;
+  }
+
+  // Returns a valid shader, or null on errors.
+  function createShaderById(gl, id) {
+    var elem = document.getElementById(id);
+    if (!elem) {
+      error('Failed to create shader from non-existent id \'' + id + '\'.');
+      return null;
+    }
+
+    var src = getContentFromElem(elem);
+
+    var shader;
+    if (elem.type == "x-shader/x-fragment") {
+      shader = gl.createShader(gl.FRAGMENT_SHADER);
+    } else if (elem.type == "x-shader/x-vertex") {
+      shader = gl.createShader(gl.VERTEX_SHADER);
+    } else {
+      error('Bad MIME type for shader \'' + id + '\': ' + elem.type + '.');
+      return null;
+    }
+
+    gl.shaderSource(shader, src);
+    gl.compileShader(shader);
+
+    return shader;
+  }
+
+  function createProgramByIds(gl, vsId, fsId) {
+    var vs = createShaderById(gl, vsId);
+    var fs = createShaderById(gl, fsId);
+    if (!vs || !fs)
+      return null;
+
+    var prog = gl.createProgram();
+    gl.attachShader(prog, vs);
+    gl.attachShader(prog, fs);
+    gl.linkProgram(prog);
+
+    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
+      var str = "Shader program linking failed:";
+      str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
+      str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
+      str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
+      warning(str);
+      return null;
+    }
+
+    return prog;
+  }
+
+  return {
+    setErrorFunc: setErrorFunc,
+    setWarningFunc: setWarningFunc,
+
+    getWebGL: getWebGL,
+    withWebGL2: withWebGL2,
+    createShaderById: createShaderById,
+    createProgramByIds: createProgramByIds,
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/reftest/wrapper.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+<title>Image reftest wrapper</title>
+<style type="text/css">
+  #image1 { background-color: rgb(10, 100, 250); }
+</style>
+<script>
+  // The image is loaded async after the page loads
+  // wait for it to finish loading
+  function onImageLoad() {
+    document.documentElement.removeAttribute("class");
+  };
+</script>
+</head>
+<body>
+<img id="image1">
+<script>
+  // Use as "wrapper.html?image.png"
+  var imgURL = document.location.search.substr(1);
+  document.images[0].onload = onImageLoad;
+  document.images[0].onerror = onImageLoad;
+  document.images[0].src = imgURL;
+</script>
+</body>
+</html>
+
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -371,16 +371,19 @@ include transform-3d/reftest.list
 # unicode/ (verify that we don't do expend effort doing unicode-aware case checks)
 include unicode/reftest.list
 
 # usercss
 include usercss/reftest.list
 
 include view-source/reftest.list
 
+# vr
+include ../../dom/vr/test/reftest/reftest.list
+
 # web-animations
 include web-animations/reftest.list
 
 # webcomponents/
 include webcomponents/reftest.list
 
 # widget/
 include ../../widget/reftests/reftest.list