summaryrefslogtreecommitdiffstats
path: root/dom/canvas/gtest/TestWebGLElementArrayCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/gtest/TestWebGLElementArrayCache.cpp')
-rw-r--r--dom/canvas/gtest/TestWebGLElementArrayCache.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/dom/canvas/gtest/TestWebGLElementArrayCache.cpp b/dom/canvas/gtest/TestWebGLElementArrayCache.cpp
new file mode 100644
index 000000000..c8ffc8701
--- /dev/null
+++ b/dom/canvas/gtest/TestWebGLElementArrayCache.cpp
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/Assertions.h"
+
+#include "WebGLElementArrayCache.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include "nscore.h"
+#include "nsTArray.h"
+
+void
+MakeRandomVector(nsTArray<uint8_t>& a, size_t size)
+{
+ a.SetLength(size);
+ // only the most-significant bits of rand() are reasonably random.
+ // RAND_MAX can be as low as 0x7fff, and we need 8 bits for the result, so we can only
+ // ignore the 7 least significant bits.
+ for (size_t i = 0; i < size; i++)
+ a[i] = static_cast<uint8_t>((unsigned int)(rand()) >> 7);
+}
+
+template<typename T>
+T
+RandomInteger(T a, T b)
+{
+ T result(a + rand() % (b - a + 1));
+ return result;
+}
+
+template<typename T>
+GLenum
+GLType()
+{
+ switch (sizeof(T)) {
+ case 4: return LOCAL_GL_UNSIGNED_INT;
+ case 2: return LOCAL_GL_UNSIGNED_SHORT;
+ case 1: return LOCAL_GL_UNSIGNED_BYTE;
+ default:
+ MOZ_RELEASE_ASSERT(false);
+ return 0;
+ }
+}
+
+void
+CheckValidate(bool expectSuccess, mozilla::WebGLElementArrayCache& c, GLenum type,
+ uint32_t maxAllowed, size_t first, size_t count)
+{
+ const bool success = c.Validate(type, maxAllowed, first, count);
+ ASSERT_TRUE(success == expectSuccess);
+}
+
+template<typename T>
+void
+CheckValidateOneTypeVariousBounds(mozilla::WebGLElementArrayCache& c, size_t firstByte,
+ size_t countBytes)
+{
+ size_t first = firstByte / sizeof(T);
+ size_t count = countBytes / sizeof(T);
+
+ GLenum type = GLType<T>();
+
+ T max = 0;
+ for (size_t i = 0; i < count; i++)
+ if (c.Element<T>(first + i) > max)
+ max = c.Element<T>(first + i);
+
+ CheckValidate(true, c, type, max, first, count);
+ CheckValidate(true, c, type, T(-1), first, count);
+ if (T(max + 1)) CheckValidate(true, c, type, T(max + 1), first, count);
+ if (max > 0) {
+ CheckValidate(false, c, type, max - 1, first, count);
+ CheckValidate(false, c, type, 0, first, count);
+ }
+}
+
+void CheckValidateAllTypes(mozilla::WebGLElementArrayCache& c, size_t firstByte,
+ size_t countBytes)
+{
+ CheckValidateOneTypeVariousBounds<uint8_t>(c, firstByte, countBytes);
+ CheckValidateOneTypeVariousBounds<uint16_t>(c, firstByte, countBytes);
+ CheckValidateOneTypeVariousBounds<uint32_t>(c, firstByte, countBytes);
+}
+
+template<typename T>
+void
+CheckSanity()
+{
+ const size_t numElems = 64; // should be significantly larger than tree leaf size to
+ // ensure we exercise some nontrivial tree-walking
+ T data[numElems] = {1,0,3,1,2,6,5,4}; // intentionally specify only 8 elements for now
+ size_t numBytes = numElems * sizeof(T);
+ ASSERT_TRUE(numBytes == sizeof(data));
+
+ GLenum type = GLType<T>();
+
+ mozilla::WebGLElementArrayCache c;
+ c.BufferData(data, numBytes);
+ CheckValidate(true, c, type, 6, 0, 8);
+ CheckValidate(false, c, type, 5, 0, 8);
+ CheckValidate(true, c, type, 3, 0, 3);
+ CheckValidate(false, c, type, 2, 0, 3);
+ CheckValidate(true, c, type, 6, 2, 4);
+ CheckValidate(false, c, type, 5, 2, 4);
+
+ c.BufferSubData(5*sizeof(T), data, sizeof(T));
+ CheckValidate(true, c, type, 5, 0, 8);
+ CheckValidate(false, c, type, 4, 0, 8);
+
+ // now test a somewhat larger size to ensure we exceed the size of a tree leaf
+ for(size_t i = 0; i < numElems; i++)
+ data[i] = numElems - i;
+ c.BufferData(data, numBytes);
+ CheckValidate(true, c, type, numElems, 0, numElems);
+ CheckValidate(false, c, type, numElems - 1, 0, numElems);
+
+ ASSERT_TRUE(numElems > 10);
+ CheckValidate(true, c, type, numElems - 10, 10, numElems - 10);
+ CheckValidate(false, c, type, numElems - 11, 10, numElems - 10);
+}
+
+template<typename T>
+void
+CheckUintOverflow()
+{
+ // This test is only for integer types smaller than uint32_t
+ static_assert(sizeof(T) < sizeof(uint32_t), "This test is only for integer types \
+ smaller than uint32_t");
+
+ const size_t numElems = 64; // should be significantly larger than tree leaf size to
+ // ensure we exercise some nontrivial tree-walking
+ T data[numElems];
+ size_t numBytes = numElems * sizeof(T);
+ ASSERT_TRUE(numBytes == sizeof(data));
+
+ GLenum type = GLType<T>();
+
+ mozilla::WebGLElementArrayCache c;
+
+ for(size_t i = 0; i < numElems; i++)
+ data[i] = numElems - i;
+ c.BufferData(data, numBytes);
+
+ // bug 825205
+ uint32_t bigValWrappingToZero = uint32_t(T(-1)) + 1;
+ CheckValidate(true, c, type, bigValWrappingToZero, 0, numElems);
+ CheckValidate(true, c, type, bigValWrappingToZero - 1, 0, numElems);
+ CheckValidate(false, c, type, 0, 0, numElems);
+}
+
+TEST(WebGLElementArrayCache, Test)
+{
+ srand(0); // do not want a random seed here.
+
+ CheckSanity<uint8_t>();
+ CheckSanity<uint16_t>();
+ CheckSanity<uint32_t>();
+
+ CheckUintOverflow<uint8_t>();
+ CheckUintOverflow<uint16_t>();
+
+ nsTArray<uint8_t> v, vsub;
+ mozilla::WebGLElementArrayCache b;
+
+ for (int maxBufferSize = 1; maxBufferSize <= 4096; maxBufferSize *= 2) {
+ // See bug 800612. We originally had | repeat = min(maxBufferSize, 20) |
+ // and a real bug was only caught on Windows and not on Linux due to rand()
+ // producing different values. In that case, the minimum value by which to replace
+ // this 20 to reproduce the bug on Linux, was 25. Replacing it with 64 should give
+ // us some comfort margin.
+ int repeat = std::min(maxBufferSize, 64);
+ for (int i = 0; i < repeat; i++) {
+ size_t size = RandomInteger<size_t>(0, maxBufferSize);
+ MakeRandomVector(v, size);
+ b.BufferData(v.Elements(), size);
+ CheckValidateAllTypes(b, 0, size);
+
+ for (int j = 0; j < 16; j++) {
+ for (int bufferSubDataCalls = 1; bufferSubDataCalls <= 8; bufferSubDataCalls *= 2) {
+ for (int validateCalls = 1; validateCalls <= 8; validateCalls *= 2) {
+
+ size_t offset = 0, subsize = 0;
+
+ for (int k = 0; k < bufferSubDataCalls; k++) {
+ offset = RandomInteger<size_t>(0, size);
+ subsize = RandomInteger<size_t>(0, size - offset);
+ MakeRandomVector(vsub, subsize);
+ b.BufferSubData(offset, vsub.Elements(), subsize);
+ }
+
+ for (int k = 0; k < validateCalls; k++) {
+ offset = RandomInteger<size_t>(0, size);
+ subsize = RandomInteger<size_t>(0, size - offset);
+ CheckValidateAllTypes(b, offset, subsize);
+ }
+ } // validateCalls
+ } // bufferSubDataCalls
+ } // j
+ } // i
+ } // maxBufferSize
+}
+