michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: #include "WebGLElementArrayCache.cpp" michael@0: michael@0: #include michael@0: #include michael@0: #include "nscore.h" michael@0: #include "nsTArray.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: int gTestsPassed = 0; michael@0: michael@0: void VerifyImplFunction(bool condition, const char* file, int line) michael@0: { michael@0: if (condition) { michael@0: gTestsPassed++; michael@0: } else { michael@0: std::cerr << "Test failed at " << file << ":" << line << std::endl; michael@0: abort(); michael@0: } michael@0: } michael@0: michael@0: #define VERIFY(condition) \ michael@0: VerifyImplFunction((condition), __FILE__, __LINE__) michael@0: michael@0: void MakeRandomVector(nsTArray& a, size_t size) { michael@0: a.SetLength(size); michael@0: // only the most-significant bits of rand() are reasonably random. michael@0: // RAND_MAX can be as low as 0x7fff, and we need 8 bits for the result, so we can only michael@0: // ignore the 7 least significant bits. michael@0: for (size_t i = 0; i < size; i++) michael@0: a[i] = static_cast((unsigned int)(rand()) >> 7); michael@0: } michael@0: michael@0: template michael@0: T RandomInteger(T a, T b) michael@0: { michael@0: T result(a + rand() % (b - a + 1)); michael@0: return result; michael@0: } michael@0: michael@0: template michael@0: GLenum GLType() michael@0: { michael@0: switch (sizeof(T)) michael@0: { michael@0: case 4: return LOCAL_GL_UNSIGNED_INT; michael@0: case 2: return LOCAL_GL_UNSIGNED_SHORT; michael@0: case 1: return LOCAL_GL_UNSIGNED_BYTE; michael@0: default: michael@0: VERIFY(false); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: template michael@0: void CheckValidateOneType(WebGLElementArrayCache& c, size_t firstByte, size_t countBytes) michael@0: { michael@0: size_t first = firstByte / sizeof(T); michael@0: size_t count = countBytes / sizeof(T); michael@0: michael@0: GLenum type = GLType(); michael@0: michael@0: T max = 0; michael@0: for (size_t i = 0; i < count; i++) michael@0: if (c.Element(first + i) > max) michael@0: max = c.Element(first + i); michael@0: michael@0: VERIFY(c.Validate(type, max, first, count)); michael@0: VERIFY(c.Validate(type, T(-1), first, count)); michael@0: if (T(max + 1)) VERIFY(c.Validate(type, T(max + 1), first, count)); michael@0: if (max > 0) { michael@0: VERIFY(!c.Validate(type, max - 1, first, count)); michael@0: VERIFY(!c.Validate(type, 0, first, count)); michael@0: } michael@0: } michael@0: michael@0: void CheckValidate(WebGLElementArrayCache& c, size_t firstByte, size_t countBytes) michael@0: { michael@0: CheckValidateOneType(c, firstByte, countBytes); michael@0: CheckValidateOneType(c, firstByte, countBytes); michael@0: CheckValidateOneType(c, firstByte, countBytes); michael@0: } michael@0: michael@0: template michael@0: void CheckSanity() michael@0: { michael@0: const size_t numElems = 64; // should be significantly larger than tree leaf size to michael@0: // ensure we exercise some nontrivial tree-walking michael@0: T data[numElems] = {1,0,3,1,2,6,5,4}; // intentionally specify only 8 elements for now michael@0: size_t numBytes = numElems * sizeof(T); michael@0: MOZ_ASSERT(numBytes == sizeof(data)); michael@0: michael@0: GLenum type = GLType(); michael@0: michael@0: WebGLElementArrayCache c; michael@0: c.BufferData(data, numBytes); michael@0: VERIFY( c.Validate(type, 6, 0, 8)); michael@0: VERIFY(!c.Validate(type, 5, 0, 8)); michael@0: VERIFY( c.Validate(type, 3, 0, 3)); michael@0: VERIFY(!c.Validate(type, 2, 0, 3)); michael@0: VERIFY( c.Validate(type, 6, 2, 4)); michael@0: VERIFY(!c.Validate(type, 5, 2, 4)); michael@0: michael@0: c.BufferSubData(5*sizeof(T), data, sizeof(T)); michael@0: VERIFY( c.Validate(type, 5, 0, 8)); michael@0: VERIFY(!c.Validate(type, 4, 0, 8)); michael@0: michael@0: // now test a somewhat larger size to ensure we exceed the size of a tree leaf michael@0: for(size_t i = 0; i < numElems; i++) michael@0: data[i] = numElems - i; michael@0: c.BufferData(data, numBytes); michael@0: VERIFY( c.Validate(type, numElems, 0, numElems)); michael@0: VERIFY(!c.Validate(type, numElems - 1, 0, numElems)); michael@0: michael@0: MOZ_ASSERT(numElems > 10); michael@0: VERIFY( c.Validate(type, numElems - 10, 10, numElems - 10)); michael@0: VERIFY(!c.Validate(type, numElems - 11, 10, numElems - 10)); michael@0: } michael@0: michael@0: template michael@0: void CheckUintOverflow() michael@0: { michael@0: // This test is only for integer types smaller than uint32_t michael@0: static_assert(sizeof(T) < sizeof(uint32_t), "This test is only for integer types \ michael@0: smaller than uint32_t"); michael@0: michael@0: const size_t numElems = 64; // should be significantly larger than tree leaf size to michael@0: // ensure we exercise some nontrivial tree-walking michael@0: T data[numElems]; michael@0: size_t numBytes = numElems * sizeof(T); michael@0: MOZ_ASSERT(numBytes == sizeof(data)); michael@0: michael@0: GLenum type = GLType(); michael@0: michael@0: WebGLElementArrayCache c; michael@0: michael@0: for(size_t i = 0; i < numElems; i++) michael@0: data[i] = numElems - i; michael@0: c.BufferData(data, numBytes); michael@0: michael@0: // bug 825205 michael@0: uint32_t bigValWrappingToZero = uint32_t(T(-1)) + 1; michael@0: VERIFY( c.Validate(type, bigValWrappingToZero, 0, numElems)); michael@0: VERIFY( c.Validate(type, bigValWrappingToZero - 1, 0, numElems)); michael@0: VERIFY(!c.Validate(type, 0, 0, numElems)); michael@0: } michael@0: michael@0: int main(int argc, char *argv[]) michael@0: { michael@0: srand(0); // do not want a random seed here. michael@0: michael@0: CheckSanity(); michael@0: CheckSanity(); michael@0: CheckSanity(); michael@0: michael@0: CheckUintOverflow(); michael@0: CheckUintOverflow(); michael@0: michael@0: nsTArray v, vsub; michael@0: WebGLElementArrayCache b; michael@0: michael@0: for (int maxBufferSize = 1; maxBufferSize <= 4096; maxBufferSize *= 2) { michael@0: // See bug 800612. We originally had | repeat = min(maxBufferSize, 20) | michael@0: // and a real bug was only caught on Windows and not on Linux due to rand() michael@0: // producing different values. In that case, the minimum value by which to replace michael@0: // this 20 to reproduce the bug on Linux, was 25. Replacing it with 64 should give michael@0: // us some comfort margin. michael@0: int repeat = std::min(maxBufferSize, 64); michael@0: for (int i = 0; i < repeat; i++) { michael@0: size_t size = RandomInteger(1, maxBufferSize); michael@0: MakeRandomVector(v, size); michael@0: b.BufferData(v.Elements(), size); michael@0: CheckValidate(b, 0, size); michael@0: michael@0: for (int j = 0; j < 16; j++) { michael@0: for (int bufferSubDataCalls = 1; bufferSubDataCalls <= 8; bufferSubDataCalls *= 2) { michael@0: for (int validateCalls = 1; validateCalls <= 8; validateCalls *= 2) { michael@0: michael@0: size_t offset = 0, subsize = 0; michael@0: michael@0: for (int k = 0; k < bufferSubDataCalls; k++) { michael@0: offset = RandomInteger(0, size); michael@0: subsize = RandomInteger(0, size - offset); michael@0: MakeRandomVector(vsub, subsize); michael@0: b.BufferSubData(offset, vsub.Elements(), subsize); michael@0: } michael@0: michael@0: for (int k = 0; k < validateCalls; k++) { michael@0: offset = RandomInteger(0, size); michael@0: subsize = RandomInteger(0, size - offset); michael@0: CheckValidate(b, offset, subsize); michael@0: } michael@0: } // validateCalls michael@0: } // bufferSubDataCalls michael@0: } // j michael@0: } // i michael@0: } // maxBufferSize michael@0: michael@0: std::cerr << argv[0] << ": all " << gTestsPassed << " tests passed" << std::endl; michael@0: return 0; michael@0: }