1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/compiledtest/TestWebGLElementArrayCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,208 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/Assertions.h" 1.10 + 1.11 +#include "WebGLElementArrayCache.cpp" 1.12 + 1.13 +#include <cstdlib> 1.14 +#include <iostream> 1.15 +#include "nscore.h" 1.16 +#include "nsTArray.h" 1.17 + 1.18 +using namespace mozilla; 1.19 + 1.20 +int gTestsPassed = 0; 1.21 + 1.22 +void VerifyImplFunction(bool condition, const char* file, int line) 1.23 +{ 1.24 + if (condition) { 1.25 + gTestsPassed++; 1.26 + } else { 1.27 + std::cerr << "Test failed at " << file << ":" << line << std::endl; 1.28 + abort(); 1.29 + } 1.30 +} 1.31 + 1.32 +#define VERIFY(condition) \ 1.33 + VerifyImplFunction((condition), __FILE__, __LINE__) 1.34 + 1.35 +void MakeRandomVector(nsTArray<uint8_t>& a, size_t size) { 1.36 + a.SetLength(size); 1.37 + // only the most-significant bits of rand() are reasonably random. 1.38 + // RAND_MAX can be as low as 0x7fff, and we need 8 bits for the result, so we can only 1.39 + // ignore the 7 least significant bits. 1.40 + for (size_t i = 0; i < size; i++) 1.41 + a[i] = static_cast<uint8_t>((unsigned int)(rand()) >> 7); 1.42 +} 1.43 + 1.44 +template<typename T> 1.45 +T RandomInteger(T a, T b) 1.46 +{ 1.47 + T result(a + rand() % (b - a + 1)); 1.48 + return result; 1.49 +} 1.50 + 1.51 +template<typename T> 1.52 +GLenum GLType() 1.53 +{ 1.54 + switch (sizeof(T)) 1.55 + { 1.56 + case 4: return LOCAL_GL_UNSIGNED_INT; 1.57 + case 2: return LOCAL_GL_UNSIGNED_SHORT; 1.58 + case 1: return LOCAL_GL_UNSIGNED_BYTE; 1.59 + default: 1.60 + VERIFY(false); 1.61 + return 0; 1.62 + } 1.63 +} 1.64 + 1.65 +template<typename T> 1.66 +void CheckValidateOneType(WebGLElementArrayCache& c, size_t firstByte, size_t countBytes) 1.67 +{ 1.68 + size_t first = firstByte / sizeof(T); 1.69 + size_t count = countBytes / sizeof(T); 1.70 + 1.71 + GLenum type = GLType<T>(); 1.72 + 1.73 + T max = 0; 1.74 + for (size_t i = 0; i < count; i++) 1.75 + if (c.Element<T>(first + i) > max) 1.76 + max = c.Element<T>(first + i); 1.77 + 1.78 + VERIFY(c.Validate(type, max, first, count)); 1.79 + VERIFY(c.Validate(type, T(-1), first, count)); 1.80 + if (T(max + 1)) VERIFY(c.Validate(type, T(max + 1), first, count)); 1.81 + if (max > 0) { 1.82 + VERIFY(!c.Validate(type, max - 1, first, count)); 1.83 + VERIFY(!c.Validate(type, 0, first, count)); 1.84 + } 1.85 +} 1.86 + 1.87 +void CheckValidate(WebGLElementArrayCache& c, size_t firstByte, size_t countBytes) 1.88 +{ 1.89 + CheckValidateOneType<uint8_t>(c, firstByte, countBytes); 1.90 + CheckValidateOneType<uint16_t>(c, firstByte, countBytes); 1.91 + CheckValidateOneType<uint32_t>(c, firstByte, countBytes); 1.92 +} 1.93 + 1.94 +template<typename T> 1.95 +void CheckSanity() 1.96 +{ 1.97 + const size_t numElems = 64; // should be significantly larger than tree leaf size to 1.98 + // ensure we exercise some nontrivial tree-walking 1.99 + T data[numElems] = {1,0,3,1,2,6,5,4}; // intentionally specify only 8 elements for now 1.100 + size_t numBytes = numElems * sizeof(T); 1.101 + MOZ_ASSERT(numBytes == sizeof(data)); 1.102 + 1.103 + GLenum type = GLType<T>(); 1.104 + 1.105 + WebGLElementArrayCache c; 1.106 + c.BufferData(data, numBytes); 1.107 + VERIFY( c.Validate(type, 6, 0, 8)); 1.108 + VERIFY(!c.Validate(type, 5, 0, 8)); 1.109 + VERIFY( c.Validate(type, 3, 0, 3)); 1.110 + VERIFY(!c.Validate(type, 2, 0, 3)); 1.111 + VERIFY( c.Validate(type, 6, 2, 4)); 1.112 + VERIFY(!c.Validate(type, 5, 2, 4)); 1.113 + 1.114 + c.BufferSubData(5*sizeof(T), data, sizeof(T)); 1.115 + VERIFY( c.Validate(type, 5, 0, 8)); 1.116 + VERIFY(!c.Validate(type, 4, 0, 8)); 1.117 + 1.118 + // now test a somewhat larger size to ensure we exceed the size of a tree leaf 1.119 + for(size_t i = 0; i < numElems; i++) 1.120 + data[i] = numElems - i; 1.121 + c.BufferData(data, numBytes); 1.122 + VERIFY( c.Validate(type, numElems, 0, numElems)); 1.123 + VERIFY(!c.Validate(type, numElems - 1, 0, numElems)); 1.124 + 1.125 + MOZ_ASSERT(numElems > 10); 1.126 + VERIFY( c.Validate(type, numElems - 10, 10, numElems - 10)); 1.127 + VERIFY(!c.Validate(type, numElems - 11, 10, numElems - 10)); 1.128 +} 1.129 + 1.130 +template<typename T> 1.131 +void CheckUintOverflow() 1.132 +{ 1.133 + // This test is only for integer types smaller than uint32_t 1.134 + static_assert(sizeof(T) < sizeof(uint32_t), "This test is only for integer types \ 1.135 + smaller than uint32_t"); 1.136 + 1.137 + const size_t numElems = 64; // should be significantly larger than tree leaf size to 1.138 + // ensure we exercise some nontrivial tree-walking 1.139 + T data[numElems]; 1.140 + size_t numBytes = numElems * sizeof(T); 1.141 + MOZ_ASSERT(numBytes == sizeof(data)); 1.142 + 1.143 + GLenum type = GLType<T>(); 1.144 + 1.145 + WebGLElementArrayCache c; 1.146 + 1.147 + for(size_t i = 0; i < numElems; i++) 1.148 + data[i] = numElems - i; 1.149 + c.BufferData(data, numBytes); 1.150 + 1.151 + // bug 825205 1.152 + uint32_t bigValWrappingToZero = uint32_t(T(-1)) + 1; 1.153 + VERIFY( c.Validate(type, bigValWrappingToZero, 0, numElems)); 1.154 + VERIFY( c.Validate(type, bigValWrappingToZero - 1, 0, numElems)); 1.155 + VERIFY(!c.Validate(type, 0, 0, numElems)); 1.156 +} 1.157 + 1.158 +int main(int argc, char *argv[]) 1.159 +{ 1.160 + srand(0); // do not want a random seed here. 1.161 + 1.162 + CheckSanity<uint8_t>(); 1.163 + CheckSanity<uint16_t>(); 1.164 + CheckSanity<uint32_t>(); 1.165 + 1.166 + CheckUintOverflow<uint8_t>(); 1.167 + CheckUintOverflow<uint16_t>(); 1.168 + 1.169 + nsTArray<uint8_t> v, vsub; 1.170 + WebGLElementArrayCache b; 1.171 + 1.172 + for (int maxBufferSize = 1; maxBufferSize <= 4096; maxBufferSize *= 2) { 1.173 + // See bug 800612. We originally had | repeat = min(maxBufferSize, 20) | 1.174 + // and a real bug was only caught on Windows and not on Linux due to rand() 1.175 + // producing different values. In that case, the minimum value by which to replace 1.176 + // this 20 to reproduce the bug on Linux, was 25. Replacing it with 64 should give 1.177 + // us some comfort margin. 1.178 + int repeat = std::min(maxBufferSize, 64); 1.179 + for (int i = 0; i < repeat; i++) { 1.180 + size_t size = RandomInteger<size_t>(1, maxBufferSize); 1.181 + MakeRandomVector(v, size); 1.182 + b.BufferData(v.Elements(), size); 1.183 + CheckValidate(b, 0, size); 1.184 + 1.185 + for (int j = 0; j < 16; j++) { 1.186 + for (int bufferSubDataCalls = 1; bufferSubDataCalls <= 8; bufferSubDataCalls *= 2) { 1.187 + for (int validateCalls = 1; validateCalls <= 8; validateCalls *= 2) { 1.188 + 1.189 + size_t offset = 0, subsize = 0; 1.190 + 1.191 + for (int k = 0; k < bufferSubDataCalls; k++) { 1.192 + offset = RandomInteger<size_t>(0, size); 1.193 + subsize = RandomInteger<size_t>(0, size - offset); 1.194 + MakeRandomVector(vsub, subsize); 1.195 + b.BufferSubData(offset, vsub.Elements(), subsize); 1.196 + } 1.197 + 1.198 + for (int k = 0; k < validateCalls; k++) { 1.199 + offset = RandomInteger<size_t>(0, size); 1.200 + subsize = RandomInteger<size_t>(0, size - offset); 1.201 + CheckValidate(b, offset, subsize); 1.202 + } 1.203 + } // validateCalls 1.204 + } // bufferSubDataCalls 1.205 + } // j 1.206 + } // i 1.207 + } // maxBufferSize 1.208 + 1.209 + std::cerr << argv[0] << ": all " << gTestsPassed << " tests passed" << std::endl; 1.210 + return 0; 1.211 +}