Bug 1250710 - Add a test. - r=ethlin
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 14 Jun 2016 09:49:03 -0700
changeset 388850 c2ee198a1c719a61ed7666a20ab8883d6f7ddaa9
parent 388849 cb9ec5bb8bcc67eaac9aba306347869b9a38972d
child 388851 385d885ca02fbc48c66f1ce0941b176e4d0e28bb
push id23247
push userbmo:jgilbert@mozilla.com
push dateMon, 18 Jul 2016 06:13:58 +0000
reviewersethlin
bugs1250710
milestone50.0a1
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>