Bug 1250710 - Add a test. - r=ethlin
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 14 Jun 2016 09:49:03 -0700
changeset 305344 c2ee198a1c719a61ed7666a20ab8883d6f7ddaa9
parent 305343 cb9ec5bb8bcc67eaac9aba306347869b9a38972d
child 305345 385d885ca02fbc48c66f1ce0941b176e4d0e28bb
push id30460
push usercbook@mozilla.com
push dateMon, 18 Jul 2016 15:08:19 +0000
treeherdermozilla-central@cde56ead650f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersethlin
bugs1250710
milestone50.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 1250710 - Add a test. - r=ethlin MozReview-Commit-ID: I6I7lKcjmMp
dom/canvas/WebGL2ContextBuffers.cpp
dom/canvas/moz.build
dom/canvas/test/webgl-mochitest/mochitest.ini
dom/canvas/test/webgl-mochitest/test_pixel_pack_buffer.html
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -228,16 +228,18 @@ WebGL2Context::GetBufferSubDataT(GLenum 
      */
 
     void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
                                     LOCAL_GL_MAP_READ_BIT);
     // Warning: Possibly shared memory.  See bug 1225033.
     memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
     gl->fUnmapBuffer(target);
 
+    ////
+
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
         BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
     }
 }
 
 void
 WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
                                 const dom::Nullable<dom::ArrayBuffer>& maybeData)
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -1,21 +1,21 @@
 # -*- Mode: python; c-basic-offset: 4; 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/.
 
 TEST_DIRS += [
-    'compiledtest', 
+    'compiledtest',
     'gtest'
 ]
 
 # Change the following line(s) to avoid bug 1081323 (clobber after changing a manifest):
-# * Add a regression test for triangle-then-point rendering.
+# * Implement ReadPixel with PBOs.
 
 MOCHITEST_MANIFESTS += [
     'test/crash/mochitest.ini',
     'test/crossorigin/mochitest.ini',
     'test/mochitest.ini',
     'test/webgl-conf/generated-mochitest.ini',
     'test/webgl-mochitest/mochitest.ini',
 ]
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -66,16 +66,17 @@ support-files = ../captureStream_common.
 skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in libLLVM-3.0.so)
 [test_hidden_depth_stencil.html]
 fail-if = (os == 'win' && os_version == '5.1')
 [test_implicit_color_buffer_float.html]
 [test_highp_fs.html]
 [test_no_arr_points.html]
 skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
 [test_noprog_draw.html]
+[test_pixel_pack_buffer.html]
 [test_privileged_exts.html]
 [test_renderer_strings.html]
 [test_sab_with_webgl.html]
 [test_texsubimage_float.html]
 [test_uninit_data.html]
 [test_webgl_available.html]
 #[test_webgl_color_buffer_float.html]
 # We haven't cleaned up the Try results yet, but let's get this on the books first.
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_pixel_pack_buffer.html
@@ -0,0 +1,285 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <script src='/tests/SimpleTest/SimpleTest.js'></script>
+    <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+  </head>
+  <body>
+    <script>
+
+var RED   = [1, 0, 0, 1];
+var GREEN = [0, 1, 0, 1];
+var BLUE  = [0, 0, 1, 1];
+var WHITE = [1, 1, 1, 1];
+var ZERO  = [0, 0, 0, 0];
+
+function DrawColors(gl) {
+  var fnClearToColor = function(color) {
+    gl.clearColor(color[0], color[1], color[2], color[3]);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+  };
+
+  gl.enable(gl.SCISSOR_TEST);
+
+  // +---+
+  // |G W|
+  // |R B|
+  // +---+
+
+  gl.scissor(0, 0, 1, 1);
+  fnClearToColor(RED);
+
+  gl.scissor(1, 0, 1, 1);
+  fnClearToColor(BLUE);
+
+  gl.scissor(0, 1, 1, 1);
+  fnClearToColor(GREEN);
+
+  gl.scissor(1, 1, 1, 1);
+  fnClearToColor(WHITE);
+}
+
+function ClearBufferPair(gl, byteCount) {
+  // Using `null` here clears to zero according to WebGL.
+  gl.bufferData(gl.PIXEL_PACK_BUFFER, byteCount, gl.STREAM_READ);
+
+  var arr = new Uint8Array(byteCount);
+  return arr;
+}
+
+function ColorToString(color, offset=0) {
+  var arr = [ color[offset+0],
+              color[offset+1],
+              color[offset+2],
+              color[offset+3] ];
+  return '[' + arr.join(', ') + ']';
+}
+
+function TestIsUNormColor(refColor, testData, offset) {
+  if (testData.length < offset + 4) {
+    ok(false, 'testData not long enough.');
+  }
+
+  var refUNormColor = [
+    (refColor[0] * 255) | 0,
+    (refColor[1] * 255) | 0,
+    (refColor[2] * 255) | 0,
+    (refColor[3] * 255) | 0,
+  ];
+
+  var refStr = ColorToString(refUNormColor);
+  var testStr = ColorToString(testData, offset);
+  ok(testStr == refStr, 'Expected ' + refStr + ', was ' + testStr + '.');
+}
+
+function section(text) {
+  ok(true, '');
+  ok(true, 'Section: ' + text);
+}
+
+function EnsureNoError(gl) {
+  var glErr = gl.getError();
+  while (gl.getError()) {}
+
+  if (!glErr)
+    return;
+
+  var extraInfo = '';
+
+  var err = new Error();
+  var stackStr = err.stack;
+  if (stackStr !== undefined) {
+    var stackArr = stackStr.split('\n');
+    stackStr = stackArr[1]; // First one after present scope.
+    extraInfo = ': ' + stackStr;
+  }
+
+  ok(false, 'Unexpected GL error: 0x' + glErr.toString(16) + extraInfo);
+}
+
+function TestError(gl, refErrVal, str='') {
+  if (str == '') {
+    str = 'gl.getError()';
+  } else {
+    str = str + ': gl.getError()';
+  }
+
+  var err = gl.getError();
+  while (gl.getError()) {}
+
+  ShouldBe(err.toString(16), refErrVal.toString(16), str);
+}
+
+function ShouldBe(val, ref, str='') {
+  if (str != '') {
+    str += ': ';
+  }
+
+  ok(val == ref, str + 'Should be `' + ref + '`, was `' + val + '`.');
+}
+
+var gl;
+
+function Test() {
+  var canvas = document.createElement('canvas');
+  canvas.width = 2;
+  canvas.height = 2;
+  canvas.style = 'width: 256px; height: 256px; border: 1px solid black;';
+  document.body.appendChild(canvas);
+
+  var attribs = {
+    antialias: false,
+    alpha: false,
+  };
+  gl = canvas.getContext('webgl2', attribs);
+  if (!gl) {
+    todo(false, 'WebGL 2 not present, skipping.');
+    return;
+  }
+
+  ////////
+
+  TestIsUNormColor(RED, new Uint8Array([255, 0, 0, 255]), 0);
+
+  ////////
+
+  gl.clearColor(RED[0], RED[1], RED[2], RED[3]);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  var data = new Uint8Array(16);
+  gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
+  console.log(JSON.stringify(data));
+  TestIsUNormColor(RED, data, 0);
+
+  ////////
+
+  DrawColors(gl);
+
+  ////////
+
+  EnsureNoError(gl);
+  gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+  TestError(gl, gl.INVALID_OPERATION);
+
+  var data = new Uint8Array(16);
+  gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
+  EnsureNoError(gl);
+  TestIsUNormColor(RED, data, 0);
+  TestIsUNormColor(BLUE, data, 4);
+  TestIsUNormColor(GREEN, data, 8);
+  TestIsUNormColor(WHITE, data, 12);
+
+  ////////
+
+  var a = gl.createBuffer();
+  gl.bindBuffer(gl.PIXEL_PACK_BUFFER, a);
+  EnsureNoError(gl);
+
+  gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
+  TestError(gl, gl.INVALID_OPERATION);
+
+  ////////
+
+  // Basic
+  section('Basic readback');
+  data = ClearBufferPair(gl, 16);
+  EnsureNoError(gl);
+  gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+  EnsureNoError(gl);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  EnsureNoError(gl);
+  TestIsUNormColor(RED, data, 0);
+  TestIsUNormColor(BLUE, data, 4);
+  TestIsUNormColor(GREEN, data, 8);
+  TestIsUNormColor(WHITE, data, 12);
+
+  section('Subrect readback');
+  data = ClearBufferPair(gl, 8);
+  gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  EnsureNoError(gl);
+  TestIsUNormColor(WHITE, data, 0);
+  TestIsUNormColor(ZERO, data, 4);
+
+  section('ReadPixels offset:4');
+  data = ClearBufferPair(gl, 16);
+  gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 4);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  EnsureNoError(gl);
+  TestIsUNormColor(ZERO, data, 0);
+  TestIsUNormColor(WHITE, data, 4);
+  TestIsUNormColor(ZERO, data, 8);
+  TestIsUNormColor(ZERO, data, 12);
+
+  section('ReadPixels offset:5');
+  gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 5);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
+  EnsureNoError(gl);
+  TestIsUNormColor(ZERO, data, 0);
+  TestIsUNormColor(WHITE, data, 4); // Should remain from previous read.
+  TestIsUNormColor(WHITE, data, 5);
+  TestIsUNormColor(ZERO, data, 9);
+  TestIsUNormColor(ZERO, data, 12);
+
+  section('GetBufferSubData src too small');
+  data = ClearBufferPair(gl, 16);
+  EnsureNoError(gl);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
+  TestError(gl, gl.INVALID_VALUE);
+  TestIsUNormColor(ZERO, data, 0);
+  TestIsUNormColor(ZERO, data, 4);
+  TestIsUNormColor(ZERO, data, 8);
+  TestIsUNormColor(ZERO, data, 12);
+
+  section('GetBufferSubData offset:1');
+  data = new Uint8Array(15);
+  gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 8);
+  gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
+  EnsureNoError(gl);
+  TestIsUNormColor(ZERO, data, 0);
+  TestIsUNormColor(ZERO, data, 3);
+  TestIsUNormColor(WHITE, data, 7);
+  TestIsUNormColor(ZERO, data, 11);
+
+  //////////////////////////////////////
+
+  section('Test packing state');
+  EnsureNoError(gl);
+
+  function TestPackState(enumStr, initialVal, changedVal) {
+    var enumVal = gl[enumStr];
+
+    ShouldBe(gl.getParameter(enumVal), initialVal, 'Initial ' + enumStr);
+    gl.pixelStorei(enumVal, changedVal);
+    ShouldBe(gl.getParameter(enumVal), changedVal, 'Changed ' + enumStr);
+    gl.pixelStorei(enumVal, initialVal);
+    ShouldBe(gl.getParameter(enumVal), initialVal, 'Reverted ' + enumStr);
+    EnsureNoError(gl);
+  }
+
+  TestPackState('PACK_ALIGNMENT', 4, 1);
+  TestPackState('PACK_ROW_LENGTH', 0, 16);
+  TestPackState('PACK_SKIP_PIXELS', 0, 3);
+  TestPackState('PACK_SKIP_ROWS', 0, 3);
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+try {
+  var prefArrArr = [
+    ['webgl.force-enabled', true],
+    ['webgl.disable-angle', true],
+  ];
+  var prefEnv = {'set': prefArrArr};
+  SpecialPowers.pushPrefEnv(prefEnv, Test);
+} catch (e) {
+  todo(false, 'No SpecialPowers, but trying anyway...');
+  Test();
+}
+
+    </script>
+  </body>
+</html>