summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-02-25 19:23:56 -0500
committerAlon Zakai <alonzakai@gmail.com>2013-02-25 19:23:56 -0500
commit230c0e80dfcd44870bec3254c399db430f6e1d98 (patch)
tree745ec3b082adc222050b4d48a416d7a969dd148d
parent5a99d2567e76f257309cfd225876f3a5402e5f46 (diff)
parent9d4ef477a511ae4136c2d63e0150a4768cbd53ea (diff)
Merge branch 'incoming'
Conflicts: AUTHORS
-rw-r--r--AUTHORS2
-rwxr-xr-xemcc121
-rwxr-xr-xemscripten.py5
-rw-r--r--src/analyzer.js7
-rw-r--r--src/compiler.js8
-rw-r--r--src/corruptionCheck.js98
-rw-r--r--src/jsifier.js26
-rw-r--r--src/library.js225
-rw-r--r--src/library_browser.js19
-rw-r--r--src/library_egl.js41
-rw-r--r--src/library_gl.js311
-rw-r--r--src/library_glut.js6
-rw-r--r--src/library_sdl.js14
-rw-r--r--src/parseTools.js63
-rw-r--r--src/preamble.js170
-rw-r--r--src/runtime.js31
-rw-r--r--src/settings.js40
-rw-r--r--system/lib/libc.symbols5
-rw-r--r--system/lib/libcxx/symbols9
-rw-r--r--system/lib/libcxxabi/symbols7
-rw-r--r--tests/aniso.pngbin35041 -> 26812 bytes
-rw-r--r--tests/cubegeom.c14
-rw-r--r--tests/cubegeom_pre2_vao.c380
-rw-r--r--tests/cubegeom_pre2_vao2.c381
-rw-r--r--tests/cubegeom_pre_vao.c333
-rw-r--r--tests/float_tex.pngbin19944 -> 18869 bytes
-rw-r--r--tests/fuzz/1.c117
-rw-r--r--tests/fuzz/1.c.txt1
-rwxr-xr-xtests/fuzz/creduce_tester.py53
-rw-r--r--tests/fuzz/csmith.h130
-rwxr-xr-xtests/fuzz/csmith_driver.py100
-rw-r--r--tests/fuzz/platform_generic.h132
-rw-r--r--tests/fuzz/random_inc.h129
-rw-r--r--tests/fuzz/safe_math.h947
-rw-r--r--tests/gears.pngbin7832 -> 6407 bytes
-rw-r--r--tests/gl_ps.c3
-rw-r--r--tests/gl_ps.pngbin203535 -> 202598 bytes
-rw-r--r--tests/gl_ps_packed.c230
-rw-r--r--tests/gl_ps_workaround.c230
-rw-r--r--tests/gl_ps_workaround2.c230
-rw-r--r--tests/glbook/CH13_ParticleSystem.pngbin5106 -> 4921 bytes
-rw-r--r--tests/perspective.c408
-rw-r--r--tests/perspective.pngbin0 -> 2477 bytes
-rwxr-xr-xtests/runner.py499
-rw-r--r--tests/s3tc_crunch.pngbin353677 -> 271258 bytes
-rw-r--r--tests/screenshot-fog-density.pngbin154012 -> 157048 bytes
-rw-r--r--tests/screenshot-fog-exp2.pngbin119847 -> 122164 bytes
-rw-r--r--tests/screenshot-fog-linear.pngbin247928 -> 250343 bytes
-rw-r--r--tests/screenshot-fog-negative.pngbin79537 -> 80704 bytes
-rw-r--r--tests/screenshot-fog-simple.pngbin36557 -> 37940 bytes
-rw-r--r--tests/screenshot-gray-purple.pngbin242425 -> 241235 bytes
-rw-r--r--tests/screenshot-gray.pngbin203336 -> 202044 bytes
-rw-r--r--tests/sdl_gl_read.c9
-rw-r--r--tests/sdl_image_jpeg.c45
-rw-r--r--tests/websockets.c2
-rw-r--r--tools/file_packager.py2
-rw-r--r--tools/js-optimizer.js2
-rw-r--r--tools/js_optimizer.py3
-rw-r--r--tools/shared.py61
-rw-r--r--tools/test-js-optimizer-regs-output.js4
-rw-r--r--tools/test-js-optimizer-regs.js6
61 files changed, 5074 insertions, 585 deletions
diff --git a/AUTHORS b/AUTHORS
index b1003dbd..3a7ceb32 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -48,4 +48,6 @@ a license to everyone to use it as detailed in LICENSE.)
* Jasper St. Pierre <jstpierre@mecheye.net>
* Manuel Schölling <manuel.schoelling@gmx.de>
* Bruce Mitchener, Jr. <bruce.mitchener@gmail.com>
+* Michael Bishop <mbtyke@gmail.com>
+* Roger Braun <roger@rogerbraun.net>
diff --git a/emcc b/emcc
index ffce7363..2f4bad2b 100755
--- a/emcc
+++ b/emcc
@@ -119,11 +119,20 @@ if len(sys.argv) == 1:
exit(1)
if sys.argv[1] == '--version':
- print '''emcc (Emscripten GCC-like replacement) 2.0
-Copyright (C) 2012 the Emscripten authors.
+ revision = '(unknown revision)'
+ here = os.getcwd()
+ os.chdir(shared.path_from_root())
+ try:
+ revision = execute(['git', 'show'], stdout=PIPE, stderr=PIPE)[0].split('\n')[0]
+ except:
+ pass
+ finally:
+ os.chdir(here)
+ print '''emcc (Emscripten GCC-like replacement) %s (%s)
+Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- '''
+ ''' % (shared.EMSCRIPTEN_VERSION, revision)
exit(0)
elif sys.argv[1] == '--help':
this = os.path.basename('em++' if os.environ.get('EMMAKEN_CXX') else 'emcc')
@@ -148,14 +157,19 @@ Options that are modified or new in %s include:
compiling to JavaScript, not to intermediate
bitcode.
-O2 As -O1, plus the relooper (loop recreation),
- plus closure compiler advanced opts, plus
- LLVM -O2 optimizations
- Warning: Compiling with this takes a long time!
+ plus LLVM -O2 optimizations
-O3 As -O2, plus dangerous optimizations that may
- break the generated code! This is not
- recommended at all, see the wiki for more
- details (you can try -O2 and then add
- dangerous optimizations one by one).
+ break the generated code! This adds
+
+ -s INLINING_LIMIT=0
+ -s DOUBLE_MODE=0
+ -s PRECISE_I64_MATH=0
+ --closure 1
+
+ This is not recommended at all. A better idea
+ is to try each of these separately on top of
+ -O2 to see what works. See the wiki for more
+ information.
-s OPTION=VALUE JavaScript code generation option passed
into the emscripten compiler. For the
@@ -177,6 +191,12 @@ Options that are modified or new in %s include:
the last compilation phase from bitcode to
JavaScript, or else we will remove it by
default in -O1 and above.
+ In -O0, line numbers wil be shown in the
+ generated code. In -O1 and above, the optimizer
+ removes those comments. This flag does however
+ have the effect of disabling anything that
+ causes name mangling or minification (closure
+ or the registerize pass).
--typed-arrays <mode> 0: No typed arrays
1: Parallel typed arrays
@@ -193,8 +213,17 @@ Options that are modified or new in %s include:
(see --llvm-opts), setting this to 1 has no
effect.
- --closure <on> 0: No closure compiler (default in -O0, -O1)
- 1: Run closure compiler (default in -O2, -O3)
+ --closure <on> 0: No closure compiler (default in -O2 and below)
+ 1: Run closure compiler. This greatly reduces
+ code size and may in some cases increase
+ runtime speed (although the opposite can also
+ occur). Note that it takes time to run, and
+ may require some changes to the code. This
+ is run by default in -O3.
+
+ Note: If closure compiler hits an out-of-memory,
+ try adjusting JAVA_HEAP_SIZE in the environment
+ (for example, to 4096m for 4GB).
--js-transform <cmd> <cmd> will be called on the generated code
before it is optimized. This lets you modify
@@ -600,7 +629,8 @@ try:
ignore_dynamic_linking = False
shell_path = shared.path_from_root('src', 'shell.html')
js_libraries = []
- keep_debug = False
+ keep_llvm_debug = False
+ keep_js_debug = False
bind = False
jcache = False
if use_cxx:
@@ -616,7 +646,8 @@ try:
for i in range(len(newargs)):
newargs[i] = newargs[i].strip() # On Windows Vista (and possibly others), excessive spaces in the command line leak into the items in this array, so trim e.g. 'foo.cpp ' -> 'foo.cpp'
if newargs[i].startswith('-O'):
- requested_level = newargs[i][2]
+ # Let -O default to -O2, which is what gcc does.
+ requested_level = newargs[i][2:] or '2'
if requested_level == 's':
print >> sys.stderr, 'emcc: warning: -Os is ignored (use -O0, -O1, -O2)'
else:
@@ -667,7 +698,8 @@ try:
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i] == '-g':
- keep_debug = True
+ keep_llvm_debug = True
+ keep_js_debug = True
elif newargs[i] == '--bind':
bind = True
newargs[i] = ''
@@ -738,8 +770,9 @@ try:
if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level]
if llvm_lto is None: llvm_lto = llvm_opts > 0
- if closure is None: closure = 1 if opt_level >= 2 else 0
- if opt_level <= 0: keep_debug = True # always keep debug in -O0
+ if opt_level <= 0: keep_llvm_debug = keep_js_debug = True # always keep debug in -O0
+ if opt_level > 0: keep_llvm_debug = False # JS optimizer wipes out llvm debug info from being visible
+ if closure is None and opt_level == 3: closure = True
if DEBUG: start_time = time.time() # done after parsing arguments, which might affect debug state
@@ -879,7 +912,11 @@ try:
shared.Settings.CORRECT_OVERFLOWS = 1
if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2:
- keep_debug = True # must keep debug info to do line-by-line operations
+ keep_llvm_debug = True # must keep debug info to do line-by-line operations
+
+ if (keep_llvm_debug or keep_js_debug) and closure:
+ print >> sys.stderr, 'emcc: warning: disabling closure because debug info was requested'
+ closure = False
if minify_whitespace is None:
minify_whitespace = closure # if closure is run, minify whitespace
@@ -984,7 +1021,7 @@ try:
def create_libcxx():
if DEBUG: print >> sys.stderr, 'emcc: building libcxx for cache'
os = []
- for src in ['algorithm.cpp', 'condition_variable.cpp', 'future.cpp', 'iostream.cpp', 'memory.cpp', 'random.cpp', 'stdexcept.cpp', 'system_error.cpp', 'utility.cpp', 'bind.cpp', 'debug.cpp', 'hash.cpp', 'mutex.cpp', 'string.cpp', 'thread.cpp', 'valarray.cpp', 'chrono.cpp', 'exception.cpp', 'ios.cpp', 'locale.cpp', 'regex.cpp', 'strstream.cpp', 'typeinfo.cpp']:
+ for src in ['algorithm.cpp', 'condition_variable.cpp', 'future.cpp', 'iostream.cpp', 'memory.cpp', 'random.cpp', 'stdexcept.cpp', 'system_error.cpp', 'utility.cpp', 'bind.cpp', 'debug.cpp', 'hash.cpp', 'mutex.cpp', 'string.cpp', 'thread.cpp', 'valarray.cpp', 'chrono.cpp', 'exception.cpp', 'ios.cpp', 'locale.cpp', 'regex.cpp', 'strstream.cpp']:
o = in_temp(src + '.o')
execute([shared.PYTHON, shared.EMXX, shared.path_from_root('system', 'lib', 'libcxx', src), '-o', o], stdout=stdout, stderr=stderr)
os.append(o)
@@ -1003,7 +1040,7 @@ try:
def create_libcxxabi():
if DEBUG: print >> sys.stderr, 'emcc: building libcxxabi for cache'
os = []
- for src in ['private_typeinfo.cpp']:
+ for src in ['private_typeinfo.cpp', 'typeinfo.cpp']:
o = in_temp(src + '.o')
execute([shared.PYTHON, shared.EMXX, shared.path_from_root('system', 'lib', 'libcxxabi', 'src', src), '-o', o], stdout=stdout, stderr=stderr)
os.append(o)
@@ -1017,29 +1054,32 @@ try:
libcxxabi_symbols = filter(lambda symbol: symbol not in libc_symbols, libcxxabi_symbols)
libcxxabi_symbols = set(libcxxabi_symbols)
- force = False # If we have libcxx, we must force inclusion of libc, since libcxx uses new internally. Note: this is kind of hacky
-
+ # If we have libcxx, we must force inclusion of libc, since libcxx uses new internally. Note: this is kind of hacky
+ # Settings this in the environment will avoid checking dependencies and make building big projects a little faster
+ force = os.environ.get('EMCC_FORCE_STDLIBS')
+ has = need = None
for name, create, fix, library_symbols in [('libcxx', create_libcxx, fix_libcxx, libcxx_symbols),
('libcxxabi', create_libcxxabi, fix_libcxxabi, libcxxabi_symbols),
('libc', create_libc, fix_libc, libc_symbols)]:
- need = set()
- has = set()
- for temp_file in temp_files:
- symbols = shared.Building.llvm_nm(temp_file)
- for library_symbol in library_symbols:
- if library_symbol in symbols.undefs:
- need.add(library_symbol)
- if library_symbol in symbols.defs:
- has.add(library_symbol)
- for haz in has: # remove symbols that are supplied by another of the inputs
- if haz in need:
- need.remove(haz)
- if DEBUG: print >> sys.stderr, 'emcc: considering including %s: we need %s and have %s' % (name, str(need), str(has))
+ if not force:
+ need = set()
+ has = set()
+ for temp_file in temp_files:
+ symbols = shared.Building.llvm_nm(temp_file)
+ for library_symbol in library_symbols:
+ if library_symbol in symbols.undefs:
+ need.add(library_symbol)
+ if library_symbol in symbols.defs:
+ has.add(library_symbol)
+ for haz in has: # remove symbols that are supplied by another of the inputs
+ if haz in need:
+ need.remove(haz)
+ if DEBUG: print >> sys.stderr, 'emcc: considering including %s: we need %s and have %s' % (name, str(need), str(has))
if force or len(need) > 0:
# We need to build and link the library in
if DEBUG: print >> sys.stderr, 'emcc: including %s' % name
libfile = shared.Cache.get(name, create)
- if len(has) > 0:
+ if has and len(has) > 0:
# remove the symbols we do not need
fixed = in_temp(uniquename(libfile)) + '.bc'
shutil.copyfile(libfile, fixed)
@@ -1049,7 +1089,7 @@ try:
libfile = fixed
extra_files_to_link.append(libfile)
force = True
- if fix:
+ if fix and need:
fix(need)
# First, combine the bitcode files if there are several. We must also link if we have a singleton .a
@@ -1084,7 +1124,7 @@ try:
# Optimize, if asked to
if not LEAVE_INPUTS_RAW:
- link_opts = [] if keep_debug else ['-strip-debug']
+ link_opts = [] if keep_llvm_debug else ['-strip-debug'] # remove LLVM debug info in -O1+, since the optimizer removes it anyhow
if llvm_opts > 0:
shared.Building.llvm_opt(in_temp(target_basename + '.bc'), llvm_opts)
if DEBUG: save_intermediate('opt', 'bc')
@@ -1216,8 +1256,9 @@ try:
if DEBUG: print >> sys.stderr, 'emcc: running closure'
final = shared.Building.closure_compiler(final)
if DEBUG: save_intermediate('closure')
- elif shared.Settings.ASM_JS and shared.Settings.RELOOP:
- js_optimizer_queue += ['registerize'] # we can't use closure in asm, but this does much of the same
+ elif shared.Settings.RELOOP and not closure and not keep_js_debug:
+ # do this if closure is not enabled (it gives similar speedups), and we do not need to keep debug info around
+ js_optimizer_queue += ['registerize']
if opt_level >= 1:
if DEBUG: print >> sys.stderr, 'emcc: running post-closure post-opts'
diff --git a/emscripten.py b/emscripten.py
index af762a21..b3e153c1 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -322,10 +322,7 @@ def emscript(infile, settings, outfile, libraries=[]):
function_tables_defs = '\n'.join([info[0] for info in infos] + [info[1] for info in infos])
asm_setup = ''
- maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil']]
- if settings['USE_MATH_IMUL']:
- maths += ['Math.imul']
- asm_setup += 'if (!Math.imul) Math.imul = function(x, y) { return (x*y)|0 }; // # not a real polyfill since semantics not identical, but close and fairly fast\n'
+ maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil', 'imul']]
fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array']
math_envs = ['Runtime.bitshift64', 'Math.min'] # TODO: move min to maths
asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs])
diff --git a/src/analyzer.js b/src/analyzer.js
index 1c53b76c..c930231f 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -223,6 +223,9 @@ function analyzer(data, sidePass) {
for (var i = 0; i < item.params.length; i++) {
if (item.params[i].type == 'i64') item.params[i].type = 'i32';
}
+ } else if (item.intertype == 'inttoptr') {
+ var input = item.params[0];
+ if (input.type == 'i64') input.type = 'i32'; // inttoptr can only care about 32 bits anyhow since pointers are 32-bit
}
if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
isIllegal = true;
@@ -681,9 +684,9 @@ function analyzer(data, sidePass) {
params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null],
type: 'i32',
};
- if (j == 0 && isUnsignedOp(value.op) && sourceBits < 32) {
+ if (j == 0 && sourceBits < 32) {
// zext sign correction
- result.ident = makeSignOp(result.ident, 'i' + sourceBits, 'un', 1, 1);
+ result.ident = makeSignOp(result.ident, 'i' + sourceBits, isUnsignedOp(value.op) ? 'un' : 're', 1, 1);
}
if (fraction != 0) {
var other = {
diff --git a/src/compiler.js b/src/compiler.js
index 25c306cf..0b43842e 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -160,12 +160,6 @@ if (SAFE_HEAP >= 2) {
SAFE_HEAP_LINES = set(SAFE_HEAP_LINES); // for fast checking
}
-if (PGO) { // by default, correct everything during PGO
- CORRECT_SIGNS = CORRECT_SIGNS || 1;
- CORRECT_OVERFLOWS = CORRECT_OVERFLOWS || 1;
- CORRECT_ROUNDINGS = CORRECT_ROUNDINGS || 1;
-}
-
EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST);
@@ -185,7 +179,7 @@ assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB)); // shared libraries must have
if (phase == 'pre') {
if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP ||
- !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) {
+ !SKIP_STACK_IN_SMALL || SAFE_HEAP || !DISABLE_EXCEPTION_CATCHING) {
print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.');
} else {
print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code');
diff --git a/src/corruptionCheck.js b/src/corruptionCheck.js
new file mode 100644
index 00000000..315f5cf0
--- /dev/null
+++ b/src/corruptionCheck.js
@@ -0,0 +1,98 @@
+
+// See settings.js, CORRUPTION_CHECK
+
+var CorruptionChecker = {
+ BUFFER_FACTOR: Math.round({{{ CORRUPTION_CHECK }}}),
+
+ ptrs: {},
+ checks: 0,
+ checkFrequency: 1,
+
+ init: function() {
+ this.realMalloc = _malloc;
+ _malloc = Module['_malloc'] = this.malloc;
+
+ this.realFree = _free;
+ _free = Module['_free'] = this.free;
+
+ if (typeof _realloc != 'undefined') {
+ this.realRealloc = _realloc;
+ _realloc = Module['_realloc'] = this.realloc;
+ }
+
+ __ATEXIT__.push({ func: function() {
+ Module.printErr('No corruption detected, ran ' + CorruptionChecker.checks + ' checks.');
+ } });
+ },
+ malloc: function(size) {
+ if (size <= 0) size = 1; // malloc(0) sometimes happens - just allocate a larger area, no harm
+ CorruptionChecker.checkAll();
+ size = (size+7)&(~7);
+ var allocation = CorruptionChecker.realMalloc(size*(1+2*CorruptionChecker.BUFFER_FACTOR));
+ var ptr = allocation + size*CorruptionChecker.BUFFER_FACTOR;
+ assert(!CorruptionChecker.ptrs[ptr]);
+ CorruptionChecker.ptrs[ptr] = size;
+ CorruptionChecker.fillBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR);
+ CorruptionChecker.fillBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR);
+ //Module.printErr('malloc ' + size + ' ==> ' + [ptr, allocation]);
+ return ptr;
+ },
+ free: function(ptr) {
+ if (!ptr) return; // ok to free(NULL), does nothing
+ CorruptionChecker.checkAll();
+ var size = CorruptionChecker.ptrs[ptr];
+ //Module.printErr('free ' + ptr + ' of size ' + size);
+ assert(size);
+ var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
+ //Module.printErr('free ' + ptr + ' of size ' + size + ' and allocation ' + allocation);
+ delete CorruptionChecker.ptrs[ptr];
+ CorruptionChecker.realFree(allocation);
+ },
+ realloc: function(ptr, newSize) {
+ //Module.printErr('realloc ' + ptr + ' to size ' + newSize);
+ if (newSize <= 0) newSize = 1; // like in malloc
+ if (!ptr) return CorruptionChecker.malloc(newSize); // realloc(NULL, size) forwards to malloc according to the spec
+ var size = CorruptionChecker.ptrs[ptr];
+ assert(size);
+ var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
+ var newPtr = CorruptionChecker.malloc(newSize);
+ //Module.printErr('realloc ' + ptr + ' to size ' + newSize + ' is now ' + newPtr);
+ var newAllocation = newPtr + newSize*CorruptionChecker.BUFFER_FACTOR;
+ HEAPU8.set(HEAPU8.subarray(ptr, ptr + Math.min(size, newSize)), newPtr);
+ CorruptionChecker.free(ptr);
+ return newPtr;
+ },
+ canary: function(x) {
+ return (x&127) + 10;
+ },
+ fillBuffer: function(buffer, size) {
+ for (var x = buffer; x < buffer + size; x++) {
+ {{{ makeSetValue('x', 0, 'CorruptionChecker.canary(x)', 'i8') }}};
+ }
+ },
+ checkBuffer: function(buffer, size) {
+ for (var x = buffer; x < buffer + size; x++) {
+ if (({{{ makeGetValue('x', 0, 'i8') }}}&255) != CorruptionChecker.canary(x)) {
+ assert(0, 'Heap corruption detected!' + [x, buffer, size, {{{ makeGetValue('x', 0, 'i8') }}}&255, CorruptionChecker.canary(x)]);
+ }
+ }
+ },
+ checkPtr: function(ptr) {
+ var size = CorruptionChecker.ptrs[ptr];
+ assert(size);
+ var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
+ CorruptionChecker.checkBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR);
+ CorruptionChecker.checkBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR);
+ },
+ checkAll: function(force) {
+ CorruptionChecker.checks++;
+ if (!force && CorruptionChecker.checks % CorruptionChecker.checkFrequency != 0) return;
+ //Module.printErr('checking for corruption ' + (CorruptionChecker.checks/CorruptionChecker.checkFrequency));
+ for (var ptr in CorruptionChecker.ptrs) {
+ CorruptionChecker.checkPtr(ptr, false);
+ }
+ },
+};
+
+CorruptionChecker.init();
+
diff --git a/src/jsifier.js b/src/jsifier.js
index 761a5fec..4af522b4 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -478,8 +478,7 @@ function JSify(data, functionsOnly, givenFunctions) {
ident = '_' + ident;
}
var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : '');
- // redirected idents just need a var, but no value assigned to them - it would be unused
- var contentText = isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';');
+ var contentText = isFunction ? snippet : ('var ' + ident + '=' + snippet + ';');
if (ASM_JS) {
var sig = LibraryManager.library[ident.substr(1) + '__sig'];
if (isFunction && sig && LibraryManager.library[ident.substr(1) + '__asm']) {
@@ -508,7 +507,7 @@ function JSify(data, functionsOnly, givenFunctions) {
item.JS = addFromLibrary(shortident);
} else {
item.JS = 'var ' + item.ident + '; // stub for ' + item.ident;
- if (WARN_ON_UNDEFINED_SYMBOLS) {
+ if (WARN_ON_UNDEFINED_SYMBOLS || ASM_JS) { // always warn on undefs in asm, since it breaks validation
warn('Unresolved symbol: ' + item.ident);
}
}
@@ -631,15 +630,6 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
- if (PROFILE) {
- func.JS += ' if (PROFILING) { '
- + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
- + 'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
- + 'PROFILING_NODE.calls++; '
- + 'var __profilingStartTime__ = Date.now() '
- + '}\n';
- }
-
if (true) { // TODO: optimize away when not needed
if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
func.JS += ' var label = 0;\n';
@@ -1145,12 +1135,6 @@ function JSify(data, functionsOnly, givenFunctions) {
});
makeFuncLineActor('return', function(item) {
var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations) + ';\n';
- if (PROFILE) {
- ret += 'if (PROFILING) { '
- + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
- + 'PROFILING_NODE = __parentProfilingNode__ '
- + '}\n';
- }
if (LABEL_DEBUG && functionNameFilterTest(item.funcData.ident)) {
ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');\n"
+ "INDENT = INDENT.substr(0, INDENT.length-2);\n";
@@ -1527,7 +1511,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('// ASM_LIBRARY FUNCTIONS');
function fix(f) { // fix indenting to not confuse js optimizer
f = f.substr(f.indexOf('f')); // remove initial spaces before 'function'
- f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last }
+ f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last } XXX assumes function has multiple lines
return f + '}'; // add unindented } to match function
}
print(asmLibraryFunctions.map(fix).join('\n'));
@@ -1547,6 +1531,10 @@ function JSify(data, functionsOnly, givenFunctions) {
// This is the main 'post' pass. Print out the generated code that we have here, together with the
// rest of the output that we started to print out earlier (see comment on the
// "Final shape that will be created").
+ if (CORRUPTION_CHECK) {
+ assert(!ASM_JS); // cannot monkeypatch asm!
+ print(processMacros(read('corruptionCheck.js')));
+ }
if (PRECISE_I64_MATH && Types.preciseI64MathUsed) {
print(read('long.js'));
} else {
diff --git a/src/library.js b/src/library.js
index 1e026937..d0f73fdd 100644
--- a/src/library.js
+++ b/src/library.js
@@ -624,7 +624,12 @@ LibraryManager.library = {
// dirent.h
// ==========================================================================
- __dirent_struct_layout: Runtime.generateStructInfo(['d_ino', 'd_name', 'd_off', 'd_reclen', 'd_type'], '%struct.dirent'),
+ __dirent_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'd_ino'],
+ ['b1024', 'd_name'],
+ ['i32', 'd_off'],
+ ['i32', 'd_reclen'],
+ ['i32', 'd_type']]),
opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
opendir: function(dirname) {
// DIR *opendir(const char *dirname);
@@ -786,7 +791,9 @@ LibraryManager.library = {
// utime.h
// ==========================================================================
- __utimbuf_struct_layout: Runtime.generateStructInfo(['actime', 'modtime'], '%struct.utimbuf'),
+ __utimbuf_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'actime'],
+ ['i32', 'modtime']]),
utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'],
utime: function(path, times) {
// int utime(const char *path, const struct utimbuf *times);
@@ -877,23 +884,23 @@ LibraryManager.library = {
// ==========================================================================
__stat_struct_layout: Runtime.generateStructInfo([
- 'st_dev',
- 'st_ino',
- 'st_mode',
- 'st_nlink',
- 'st_uid',
- 'st_gid',
- 'st_rdev',
- 'st_size',
- 'st_atime',
- 'st_spare1',
- 'st_mtime',
- 'st_spare2',
- 'st_ctime',
- 'st_spare3',
- 'st_blksize',
- 'st_blocks',
- 'st_spare4'], '%struct.stat'),
+ ['i32', 'st_dev'],
+ ['i32', 'st_ino'],
+ ['i32', 'st_mode'],
+ ['i32', 'st_nlink'],
+ ['i32', 'st_uid'],
+ ['i32', 'st_gid'],
+ ['i32', 'st_rdev'],
+ ['i32', 'st_size'],
+ ['i32', 'st_atime'],
+ ['i32', 'st_spare1'],
+ ['i32', 'st_mtime'],
+ ['i32', 'st_spare2'],
+ ['i32', 'st_ctime'],
+ ['i32', 'st_spare3'],
+ ['i32', 'st_blksize'],
+ ['i32', 'st_blocks'],
+ ['i32', 'st_spare4']]),
stat__deps: ['$FS', '__stat_struct_layout'],
stat: function(path, buf, dontResolveLastLink) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -1065,17 +1072,17 @@ LibraryManager.library = {
// ==========================================================================
__statvfs_struct_layout: Runtime.generateStructInfo([
- 'f_bsize',
- 'f_frsize',
- 'f_blocks',
- 'f_bfree',
- 'f_bavail',
- 'f_files',
- 'f_ffree',
- 'f_favail',
- 'f_fsid',
- 'f_flag',
- 'f_namemax'], '%struct.statvfs'),
+ ['i32', 'f_bsize'],
+ ['i32', 'f_frsize'],
+ ['i32', 'f_blocks'],
+ ['i32', 'f_bfree'],
+ ['i32', 'f_bavail'],
+ ['i32', 'f_files'],
+ ['i32', 'f_ffree'],
+ ['i32', 'f_favail'],
+ ['i32', 'f_fsid'],
+ ['i32', 'f_flag'],
+ ['i32', 'f_namemax']]),
statvfs__deps: ['$FS', '__statvfs_struct_layout'],
statvfs: function(path, buf) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -1110,12 +1117,12 @@ LibraryManager.library = {
// ==========================================================================
__flock_struct_layout: Runtime.generateStructInfo([
- 'l_type',
- 'l_whence',
- 'l_start',
- 'l_len',
- 'l_pid',
- 'l_xxx'], '%struct.flock'),
+ ['i16', 'l_type'],
+ ['i16', 'l_whence'],
+ ['i32', 'l_start'],
+ ['i32', 'l_len'],
+ ['i16', 'l_pid'],
+ ['i16', 'l_xxx']]),
open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
open: function(path, oflag, varargs) {
// int open(const char *path, int oflag, ...);
@@ -1336,7 +1343,10 @@ LibraryManager.library = {
// poll.h
// ==========================================================================
- __pollfd_struct_layout: Runtime.generateStructInfo(['fd', 'events', 'revents'], '%struct.pollfd'),
+ __pollfd_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'fd'],
+ ['i16', 'events'],
+ ['i16', 'revents']]),
poll__deps: ['$FS', '__pollfd_struct_layout'],
poll: function(fds, nfds, timeout) {
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
@@ -2481,6 +2491,17 @@ LibraryManager.library = {
continue;
}
+ // TODO: Support strings like "%5c" etc.
+ if (format[formatIndex] === '%' && format[formatIndex+1] == 'c') {
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getNativeFieldSize('void*');
+ fields++;
+ next = get();
+ {{{ makeSetValue('argPtr', 0, 'next', 'i8') }}}
+ formatIndex += 2;
+ continue;
+ }
+
// remove whitespace
while (1) {
next = get();
@@ -4202,6 +4223,8 @@ LibraryManager.library = {
return 1;
},
+ arc4random: 'rand',
+
// ==========================================================================
// string.h
// ==========================================================================
@@ -4502,11 +4525,16 @@ LibraryManager.library = {
return 0;
},
+ memcmp__asm: 'true',
+ memcmp__sig: 'iiii',
memcmp: function(p1, p2, num) {
- for (var i = 0; i < num; i++) {
- var v1 = {{{ makeGetValue('p1', 'i', 'i8', 0, 1) }}};
- var v2 = {{{ makeGetValue('p2', 'i', 'i8', 0, 1) }}};
- if (v1 != v2) return v1 > v2 ? 1 : -1;
+ p1 = p1|0; p2 = p2|0; num = num|0;
+ var i = 0, v1 = 0, v2 = 0;
+ while ((i|0) < (num|0)) {
+ var v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}};
+ var v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}};
+ if ((v1|0) != (v2|0)) return ((v1|0) > (v2|0) ? 1 : -1)|0;
+ i = (i+1)|0;
}
return 0;
},
@@ -4607,10 +4635,8 @@ LibraryManager.library = {
__strtok_state: 0,
strtok__deps: ['__strtok_state', 'strtok_r'],
+ strtok__postset: '___strtok_state = Runtime.staticAlloc(4);',
strtok: function(s, delim) {
- if (!___strtok_state) {
- ___strtok_state = _malloc(4);
- }
return _strtok_r(s, delim, ___strtok_state);
},
@@ -5070,6 +5096,7 @@ LibraryManager.library = {
},
__cxa_call_unexpected: function(exception) {
+ Module.printErr('Unexpected exception thrown, this is not properly supported - aborting');
ABORT = true;
throw exception;
},
@@ -5619,11 +5646,11 @@ LibraryManager.library = {
// ==========================================================================
__utsname_struct_layout: Runtime.generateStructInfo([
- 'sysname',
- 'nodename',
- 'release',
- 'version',
- 'machine'], '%struct.utsname'),
+ ['b32', 'sysname'],
+ ['b32', 'nodename'],
+ ['b32', 'release'],
+ ['b32', 'version'],
+ ['b32', 'machine']]),
uname__deps: ['__utsname_struct_layout'],
uname: function(name) {
// int uname(struct utsname *name);
@@ -5823,17 +5850,17 @@ LibraryManager.library = {
},
__tm_struct_layout: Runtime.generateStructInfo([
- 'tm_sec',
- 'tm_min',
- 'tm_hour',
- 'tm_mday',
- 'tm_mon',
- 'tm_year',
- 'tm_wday',
- 'tm_yday',
- 'tm_isdst',
- 'tm_gmtoff',
- 'tm_zone'], '%struct.tm'),
+ ['i32', 'tm_sec'],
+ ['i32', 'tm_min'],
+ ['i32', 'tm_hour'],
+ ['i32', 'tm_mday'],
+ ['i32', 'tm_mon'],
+ ['i32', 'tm_year'],
+ ['i32', 'tm_wday'],
+ ['i32', 'tm_yday'],
+ ['i32', 'tm_isdst'],
+ ['i32', 'tm_gmtoff'],
+ ['i32', 'tm_zone']]),
// Statically allocated time struct.
__tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
// Statically allocated timezone strings.
@@ -6032,7 +6059,9 @@ LibraryManager.library = {
// sys/time.h
// ==========================================================================
- __timespec_struct_layout: Runtime.generateStructInfo(['tv_sec', 'tv_nsec'], '%struct.timespec'),
+ __timespec_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'tv_sec'],
+ ['i32', 'tv_nsec']]),
// TODO: Implement these for real.
clock_gettime__deps: ['__timespec_struct_layout'],
clock_gettime: function(clk_id, tp) {
@@ -6089,10 +6118,10 @@ LibraryManager.library = {
// ==========================================================================
__tms_struct_layout: Runtime.generateStructInfo([
- 'tms_utime',
- 'tms_stime',
- 'tms_cutime',
- 'tms_cstime'], '%struct.tms'),
+ ['i32', 'tms_utime'],
+ ['i32', 'tms_stime'],
+ ['i32', 'tms_cutime'],
+ ['i32', 'tms_cstime']]),
times__deps: ['__tms_struct_layout', 'memset'],
times: function(buffer) {
// clock_t times(struct tms *buffer);
@@ -6614,7 +6643,9 @@ LibraryManager.library = {
// ==========================================================================
// TODO: Implement for real.
- __rlimit_struct_layout: Runtime.generateStructInfo(['rlim_cur', 'rlim_max'], '%struct.rlimit'),
+ __rlimit_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'rlim_cur'],
+ ['i32', 'rlim_max']]),
getrlimit__deps: ['__rlimit_struct_layout'],
getrlimit: function(resource, rlp) {
// int getrlimit(int resource, struct rlimit *rlp);
@@ -6630,22 +6661,22 @@ LibraryManager.library = {
// TODO: Implement for real. We just do time used, and no useful data
__rusage_struct_layout: Runtime.generateStructInfo([
- 'ru_utime',
- 'ru_stime',
- 'ru_maxrss',
- 'ru_ixrss',
- 'ru_idrss',
- 'ru_isrss',
- 'ru_minflt',
- 'ru_majflt',
- 'ru_nswap',
- 'ru_inblock',
- 'ru_oublock',
- 'ru_msgsnd',
- 'ru_msgrcv',
- 'ru_nsignals',
- 'ru_nvcsw',
- 'ru_nivcsw'], '%struct.rusage'),
+ ['i64', 'ru_utime'],
+ ['i64', 'ru_stime'],
+ ['i32', 'ru_maxrss'],
+ ['i32', 'ru_ixrss'],
+ ['i32', 'ru_idrss'],
+ ['i32', 'ru_isrss'],
+ ['i32', 'ru_minflt'],
+ ['i32', 'ru_majflt'],
+ ['i32', 'ru_nswap'],
+ ['i32', 'ru_inblock'],
+ ['i32', 'ru_oublock'],
+ ['i32', 'ru_msgsnd'],
+ ['i32', 'ru_msgrcv'],
+ ['i32', 'ru_nsignals'],
+ ['i32', 'ru_nvcsw'],
+ ['i32', 'ru_nivcsw']]),
getrusage__deps: ['__rusage_struct_layout'],
getrusage: function(resource, rlp) {
// %struct.timeval = type { i32, i32 }
@@ -7289,36 +7320,6 @@ LibraryManager.library = {
emscripten_random: function() {
return Math.random();
},
-
- $Profiling: {
- max_: 0,
- times: null,
- invalid: 0,
- dump: function() {
- if (Profiling.invalid) {
- Module.printErr('Invalid # of calls to Profiling begin and end!');
- return;
- }
- Module.printErr('Profiling data:')
- for (var i = 0; i < Profiling.max_; i++) {
- Module.printErr('Block ' + i + ': ' + Profiling.times[i]);
- }
- }
- },
- EMSCRIPTEN_PROFILE_INIT__deps: ['$Profiling'],
- EMSCRIPTEN_PROFILE_INIT: function(max_) {
- Profiling.max_ = max_;
- Profiling.times = new Array(max_);
- for (var i = 0; i < max_; i++) Profiling.times[i] = 0;
- },
- EMSCRIPTEN_PROFILE_BEGIN__inline: function(id) {
- return 'Profiling.times[' + id + '] -= Date.now();'
- + 'Profiling.invalid++;'
- },
- EMSCRIPTEN_PROFILE_END__inline: function(id) {
- return 'Profiling.times[' + id + '] += Date.now();'
- + 'Profiling.invalid--;'
- }
};
function autoAddDeps(object, name) {
diff --git a/src/library_browser.js b/src/library_browser.js
index d16fbc0b..5b19a360 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -68,6 +68,7 @@ mergeInto(LibraryManager.library, {
function getMimetype(name) {
return {
'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
'png': 'image/png',
'bmp': 'image/bmp',
'ogg': 'audio/ogg',
@@ -81,7 +82,7 @@ mergeInto(LibraryManager.library, {
var imagePlugin = {};
imagePlugin['canHandle'] = function(name) {
- return name.substr(-4) in { '.jpg': 1, '.png': 1, '.bmp': 1 };
+ return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/.exec(name);
};
imagePlugin['handle'] = function(byteArray, name, onload, onerror) {
var b = null;
@@ -123,7 +124,7 @@ mergeInto(LibraryManager.library, {
var audioPlugin = {};
audioPlugin['canHandle'] = function(name) {
- return name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+ return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
};
audioPlugin['handle'] = function(byteArray, name, onload, onerror) {
var done = false;
@@ -200,8 +201,18 @@ mergeInto(LibraryManager.library, {
return null;
}
#endif
+ var ctx;
try {
- var ctx = canvas.getContext(useWebGL ? 'experimental-webgl' : '2d');
+ if (useWebGL) {
+ ctx = canvas.getContext('experimental-webgl', {
+ alpha: false,
+#if GL_TESTING
+ preserveDrawingBuffer: true
+#endif
+ });
+ } else {
+ ctx = canvas.getContext('2d');
+ }
if (!ctx) throw ':(';
} catch (e) {
Module.print('Could not create canvas - ' + e);
@@ -262,7 +273,7 @@ mergeInto(LibraryManager.library, {
}
return ctx;
},
-
+ destroyContext: function(canvas, useWebGL, setInModule) {},
requestFullScreen: function() {
var canvas = Module['canvas'];
function fullScreenChange() {
diff --git a/src/library_egl.js b/src/library_egl.js
index a9eb37dd..271ea29e 100644
--- a/src/library_egl.js
+++ b/src/library_egl.js
@@ -83,6 +83,17 @@ var LibraryEGL = {
return 1;
},
+// EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+ eglTerminate: function(display) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ // TODO: Tear down EGL here. Currently a no-op since we don't need to actually do anything here for the browser.
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1;
+ },
+
// EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
eglGetConfigs: function(display, configs, config_size, numConfigs) {
return EGL.chooseConfig(display, 0, configs, config_size, numConfigs);
@@ -225,6 +236,20 @@ var LibraryEGL = {
return 62006; /* Magic ID for Emscripten 'default surface' */
},
+ // EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay display, EGLSurface surface);
+ eglDestroySurface: function(display, surface) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+ if (surface != 62006 /* Magic ID for the only EGLSurface supported by Emscripten */) {
+ EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */);
+ return 1;
+ }
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 1; /* Magic ID for Emscripten 'default surface' */
+ },
+
eglCreateContext__deps: ['glutCreateWindow', '$GL'],
// EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
@@ -234,7 +259,21 @@ var LibraryEGL = {
return 0;
}
- _glutCreateWindow();
+ EGL.windowID = _glutCreateWindow();
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 62004; // Magic ID for Emscripten EGLContext
+ },
+
+ eglDestroyContext__deps: ['glutDestroyWindow', '$GL'],
+
+ // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext context);
+ eglDestroyContext: function(display, context) {
+ if (display != 62000 /* Magic ID for Emscripten 'default display' */) {
+ EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */);
+ return 0;
+ }
+
+ _glutDestroyWindow(EGL.windowID);
EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
return 62004; // Magic ID for Emscripten EGLContext
},
diff --git a/src/library_gl.js b/src/library_gl.js
index f7966dab..027b2841 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -408,7 +408,19 @@ var LibraryGL = {
},
glReadPixels: function(x, y, width, height, format, type, pixels) {
- Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels));
+ assert(type == 0x1401 /* GL_UNSIGNED_BYTE */);
+ var sizePerPixel;
+ switch (format) {
+ case 0x1907 /* GL_RGB */:
+ sizePerPixel = 3;
+ break;
+ case 0x1908 /* GL_RGBA */:
+ sizePerPixel = 4;
+ break;
+ default: throw 'unsupported glReadPixels format';
+ }
+ var totalSize = width*height*sizePerPixel;
+ Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize));
},
glBindTexture: function(target, texture) {
@@ -908,11 +920,9 @@ var LibraryGL = {
},
glIsProgram: function(program) {
- var fb = GL.programs[program];
- if (typeof(fb) == 'undefined') {
- return 0;
- }
- return Module.ctx.isProgram(fb);
+ var program = GL.programs[program];
+ if (!program) return 0;
+ return Module.ctx.isProgram(program);
},
glBindAttribLocation__sig: 'viii',
@@ -983,6 +993,11 @@ var LibraryGL = {
fogMode: 0x0800, // GL_EXP
fogEnabled: false,
+ // VAO support
+ vaos: [],
+ currentVao: null,
+ enabledVertexAttribArrays: {}, // helps with vao cleanups
+
init: function() {
GLEmulation.fogColor = new Float32Array(4);
@@ -1008,6 +1023,11 @@ var LibraryGL = {
if (cap == 0x0B60 /* GL_FOG */) {
GLEmulation.fogEnabled = true;
return;
+ } else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
+ // XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
+ // it by forwarding to glEnableClientState
+ _glEnableClientState(cap);
+ return;
} else if (!(cap in validCapabilities)) {
return;
}
@@ -1018,6 +1038,11 @@ var LibraryGL = {
if (cap == 0x0B60 /* GL_FOG */) {
GLEmulation.fogEnabled = false;
return;
+ } else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
+ // XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
+ // it by forwarding to glDisableClientState
+ _glDisableClientState(cap);
+ return;
} else if (!(cap in validCapabilities)) {
return;
}
@@ -1052,6 +1077,51 @@ var LibraryGL = {
return;
}
case 0x8871: pname = Module.ctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS /* close enough */; break; // GL_MAX_TEXTURE_COORDS
+ case 0x807A: { // GL_VERTEX_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x807B: { // GL_VERTEX_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x807C: { // GL_VERTEX_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
+ case 0x8081: { // GL_COLOR_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x8082: { // GL_COLOR_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x8083: { // GL_COLOR_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.COLOR];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
+ case 0x8088: { // GL_TEXTURE_COORD_ARRAY_SIZE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
+ return;
+ }
+ case 0x8089: { // GL_TEXTURE_COORD_ARRAY_TYPE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
+ return;
+ }
+ case 0x808A: { // GL_TEXTURE_COORD_ARRAY_STRIDE
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
+ {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
+ return;
+ }
}
glGetIntegerv(pname, params);
};
@@ -1267,8 +1337,13 @@ var LibraryGL = {
glBindBuffer(target, buffer);
if (target == Module.ctx.ARRAY_BUFFER) {
GL.currArrayBuffer = buffer;
+ if (GLEmulation.currentVao) {
+ assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
+ GLEmulation.currentVao.arrayBuffer = buffer;
+ }
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
GL.currElementArrayBuffer = buffer;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.elementArrayBuffer = buffer;
}
};
@@ -1312,6 +1387,28 @@ var LibraryGL = {
}
glHint(target, mode);
};
+
+ var glEnableVertexAttribArray = _glEnableVertexAttribArray;
+ _glEnableVertexAttribArray = function(index) {
+ glEnableVertexAttribArray(index);
+ GLEmulation.enabledVertexAttribArrays[index] = 1;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.enabledVertexAttribArrays[index] = 1;
+ };
+
+ var glDisableVertexAttribArray = _glDisableVertexAttribArray;
+ _glDisableVertexAttribArray = function(index) {
+ glDisableVertexAttribArray(index);
+ delete GLEmulation.enabledVertexAttribArrays[index];
+ if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledVertexAttribArrays[index];
+ };
+
+ var glVertexAttribPointer = _glVertexAttribPointer;
+ _glVertexAttribPointer = function(index, size, type, normalized, stride, pointer) {
+ glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ if (GLEmulation.currentVao) { // TODO: avoid object creation here? likely not hot though
+ GLEmulation.currentVao.vertexAttribPointers[index] = [index, size, type, normalized, stride, pointer];
+ }
+ };
},
getProcAddress: function(name) {
@@ -1375,6 +1472,9 @@ var LibraryGL = {
case 'glIsFramebuffer': ret = {{{ Functions.getIndex('_glIsFramebuffer', true) }}}; break;
case 'glCheckFramebufferStatus': ret = {{{ Functions.getIndex('_glCheckFramebufferStatus', true) }}}; break;
case 'glRenderbufferStorage': ret = {{{ Functions.getIndex('_glRenderbufferStorage', true) }}}; break;
+ case 'glGenVertexArrays': ret = {{{ Functions.getIndex('_glGenVertexArrays', true) }}}; break;
+ case 'glDeleteVertexArrays': ret = {{{ Functions.getIndex('_glDeleteVertexArrays', true) }}}; break;
+ case 'glBindVertexArray': ret = {{{ Functions.getIndex('_glBindVertexArray', true) }}}; break;
}
if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
return ret;
@@ -1427,6 +1527,20 @@ var LibraryGL = {
assert(id == 0);
},
+ glGetPointerv: function(name, p) {
+ var attribute;
+ switch(name) {
+ case 0x808E: // GL_VERTEX_ARRAY_POINTER
+ attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX]; break;
+ case 0x8090: // GL_COLOR_ARRAY_POINTER
+ attribute = GLImmediate.clientAttributes[GLImmediate.COLOR]; break;
+ case 0x8092: // GL_TEXTURE_COORD_ARRAY_POINTER
+ attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; break;
+ default: throw 'TODO: glGetPointerv for ' + name;
+ }
+ {{{ makeSetValue('p', '0', 'attribute ? attribute.pointer : 0', 'i32') }}};
+ },
+
// GL Immediate mode
$GLImmediate__postset: 'GL.immediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GL.immediate.init() });',
@@ -1501,7 +1615,7 @@ var LibraryGL = {
},
// Temporary buffers
- MAX_TEMP_BUFFER_SIZE: 2*1024*1024,
+ MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}},
tempBufferIndexLookup: null,
tempVertexBuffers: null,
tempIndexBuffers: null,
@@ -1784,27 +1898,35 @@ var LibraryGL = {
}
// If the array buffer is unchanged and the renderer as well, then we can avoid all the work here
- // XXX We use some heuristics here, and this may not work in all cases. Try disabling this if you
- // have odd glitches (by setting canSkip always to 0, or even cleaning up the renderer right
- // after rendering)
+ // XXX We use some heuristics here, and this may not work in all cases. Try disabling GL_UNSAFE_OPTS if you
+ // have odd glitches
+#if GL_UNSAFE_OPTS
var lastRenderer = GL.immediate.lastRenderer;
var canSkip = this == lastRenderer &&
arrayBuffer == GL.immediate.lastArrayBuffer &&
(GL.currProgram || this.program) == GL.immediate.lastProgram &&
!GL.immediate.matricesModified;
if (!canSkip && lastRenderer) lastRenderer.cleanup();
+#endif
if (!GL.currArrayBuffer) {
// Bind the array buffer and upload data after cleaning up the previous renderer
+#if GL_UNSAFE_OPTS
+ // Potentially unsafe, since lastArrayBuffer might not reflect the true array buffer in code that mixes immediate/non-immediate
if (arrayBuffer != GL.immediate.lastArrayBuffer) {
+#endif
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, arrayBuffer);
+#if GL_UNSAFE_OPTS
}
+#endif
Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, start, GL.immediate.vertexData.subarray(start >> 2, end >> 2));
}
+#if GL_UNSAFE_OPTS
if (canSkip) return;
GL.immediate.lastRenderer = this;
GL.immediate.lastArrayBuffer = arrayBuffer;
GL.immediate.lastProgram = GL.currProgram || this.program;
GL.immediate.matricesModified = false;
+#endif
if (!GL.currProgram) {
Module.ctx.useProgram(this.program);
@@ -1880,9 +2002,11 @@ var LibraryGL = {
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
}
+#if GL_UNSAFE_OPTS
GL.immediate.lastRenderer = null;
GL.immediate.lastArrayBuffer = null;
GL.immediate.lastProgram = null;
+#endif
GL.immediate.matricesModified = true;
}
};
@@ -1997,22 +2121,61 @@ var LibraryGL = {
#endif
if (attribute.stride) stride = attribute.stride;
}
-
- var bytes = 0;
- for (var i = 0; i < attributes.length; i++) {
- var attribute = attributes[i];
- if (!attribute) break;
- attribute.offset = attribute.pointer - start;
- if (attribute.offset > bytes) { // ensure we start where we should
- assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
- bytes += attribute.offset - bytes;
+ var bytes = 0; // total size in bytes
+ if (!stride && !beginEnd) {
+ // beginEnd can not have stride in the attributes, that is fine. otherwise,
+ // no stride means that all attributes are in fact packed. to keep the rest of
+ // our emulation code simple, we perform unpacking/restriding here. this adds overhead, so
+ // it is a good idea to not hit this!
+#if ASSERTIONS
+ Runtime.warnOnce('Unpacking/restriding attributes, this is not fast');
+#endif
+ if (!GL.immediate.restrideBuffer) GL.immediate.restrideBuffer = _malloc(GL.immediate.MAX_TEMP_BUFFER_SIZE);
+ start = GL.immediate.restrideBuffer;
+#if ASSERTIONS
+ assert(start % 4 == 0);
+#endif
+ // calculate restrided offsets and total size
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ if (!attribute) break;
+ var size = attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot];
+ if (size % 4 != 0) size += 4 - (size % 4); // align everything
+ attribute.offset = bytes;
+ bytes += size;
+ }
+#if ASSERTIONS
+ assert(count*bytes <= GL.immediate.MAX_TEMP_BUFFER_SIZE);
+#endif
+ // copy out the data (we need to know the stride for that, and define attribute.pointer
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ if (!attribute) break;
+ var size4 = Math.floor((attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot])/4);
+ for (var j = 0; j < count; j++) {
+ for (var k = 0; k < size4; k++) { // copy in chunks of 4 bytes, our alignment makes this possible
+ HEAP32[((start + attribute.offset + bytes*j)>>2) + k] = HEAP32[(attribute.pointer>>2) + j*size4 + k];
+ }
+ }
+ attribute.pointer = start + attribute.offset;
+ }
+ } else {
+ // normal situation, everything is strided and in the same buffer
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ if (!attribute) break;
+ attribute.offset = attribute.pointer - start;
+ if (attribute.offset > bytes) { // ensure we start where we should
+ assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
+ bytes += attribute.offset - bytes;
+ }
+ bytes += attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot];
+ if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
+ }
+ assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
+ if (bytes < stride) { // ensure the size is that of the stride
+ bytes = stride;
}
- bytes += attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot];
- if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
- }
- assert(stride == 0 || bytes <= stride);
- if (bytes < stride) { // ensure the size is that of the stride
- bytes = stride;
}
GL.immediate.stride = bytes;
@@ -2026,6 +2189,9 @@ var LibraryGL = {
},
flush: function(numProvidedIndexes, startIndex, ptr) {
+#if ASSERTIONS
+ assert(numProvidedIndexes >= 0 || !numProvidedIndexes);
+#endif
startIndex = startIndex || 0;
ptr = ptr || 0;
@@ -2085,6 +2251,10 @@ var LibraryGL = {
if (emulatedElementArrayBuffer) {
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
}
+
+#if GL_UNSAFE_OPTS == 0
+ renderer.cleanup();
+#endif
}
},
@@ -2302,6 +2472,7 @@ var LibraryGL = {
var attrib;
switch(cap) {
case 0x8078: // GL_TEXTURE_COORD_ARRAY
+ case 0x0de1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it
attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
case 0x8074: // GL_VERTEX_ARRAY
attrib = GL.immediate.VERTEX; break;
@@ -2310,14 +2481,19 @@ var LibraryGL = {
case 0x8076: // GL_COLOR_ARRAY
attrib = GL.immediate.COLOR; break;
default:
- throw 'unhandled clientstate: ' + cap;
+#if ASSERTIONS
+ Module.printErr('WARNING: unhandled clientstate: ' + cap);
+#endif
+ return;
}
if (disable && GL.immediate.enabledClientAttributes[attrib]) {
GL.immediate.enabledClientAttributes[attrib] = false;
GL.immediate.totalEnabledClientAttributes--;
+ if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
} else if (!disable && !GL.immediate.enabledClientAttributes[attrib]) {
GL.immediate.enabledClientAttributes[attrib] = true;
GL.immediate.totalEnabledClientAttributes++;
+ if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1;
}
GL.immediate.modifiedClientAttributes = true;
},
@@ -2344,6 +2520,63 @@ var LibraryGL = {
GL.immediate.clientActiveTexture = texture - 0x84C0; // GL_TEXTURE0
},
+ // Vertex array object (VAO) support. TODO: when the WebGL extension is popular, use that and remove this code and GL.vaos
+ glGenVertexArrays__deps: ['$GLEMulation'],
+ glGenVertexArrays__sig: ['vii'],
+ glGenVertexArrays: function(n, vaos) {
+ for (var i = 0; i < n; i++) {
+ var id = GL.getNewId(GLEmulation.vaos);
+ GLEmulation.vaos[id] = {
+ id: id,
+ arrayBuffer: 0,
+ elementArrayBuffer: 0,
+ enabledVertexAttribArrays: {},
+ vertexAttribPointers: {},
+ enabledClientStates: {},
+ };
+ {{{ makeSetValue('vaos', 'i*4', 'id', 'i32') }}};
+ }
+ },
+ glDeleteVertexArrays__sig: ['vii'],
+ glDeleteVertexArrays: function(n, vaos) {
+ for (var i = 0; i < n; i++) {
+ var id = {{{ makeGetValue('vaos', 'i*4', 'i32') }}};
+ GLEmulation.vaos[id] = null;
+ if (GLEmulation.currentVao && GLEmulation.currentVao.id == id) GLEmulation.currentVao = null;
+ }
+ },
+ glBindVertexArray__sig: ['vi'],
+ glBindVertexArray: function(vao) {
+ // undo vao-related things, wipe the slate clean, both for vao of 0 or an actual vao
+ GLEmulation.currentVao = null; // make sure the commands we run here are not recorded
+ if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
+ _glBindBuffer(Module.ctx.ARRAY_BUFFER, 0); // XXX if one was there before we were bound?
+ _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, 0);
+ for (var vaa in GLEmulation.enabledVertexAttribArrays) {
+ Module.ctx.disableVertexAttribArray(vaa);
+ }
+ GLEmulation.enabledVertexAttribArrays = {};
+ GL.immediate.enabledClientAttributes = [0, 0];
+ GL.immediate.totalEnabledClientAttributes = 0;
+ GL.immediate.modifiedClientAttributes = true;
+ if (vao) {
+ // replay vao
+ var info = GLEmulation.vaos[vao];
+ _glBindBuffer(Module.ctx.ARRAY_BUFFER, info.arrayBuffer); // XXX overwrite current binding?
+ _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, info.elementArrayBuffer);
+ for (var vaa in info.enabledVertexAttribArrays) {
+ _glEnableVertexAttribArray(vaa);
+ }
+ for (var vaa in info.vertexAttribPointers) {
+ _glVertexAttribPointer.apply(null, info.vertexAttribPointers[vaa]);
+ }
+ for (var attrib in info.enabledClientStates) {
+ _glEnableClientState(attrib|0);
+ }
+ GLEmulation.currentVao = info; // set currentVao last, so the commands we ran here were not recorded
+ }
+ },
+
// OpenGL Immediate Mode matrix routines.
// Note that in the future we might make these available only in certain modes.
glMatrixMode__deps: ['$GL', '$GLImmediateSetup', '$GLEmulation'], // emulation is not strictly needed, this is a workaround
@@ -2434,6 +2667,7 @@ var LibraryGL = {
GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
GL.immediate.matrix.lib.mat4.frustum(left, right, bottom, top_, nearVal, farVal));
},
+ glFrustumf: 'glFrustum',
glOrtho: function(left, right, bottom, top_, nearVal, farVal) {
GL.immediate.matricesModified = true;
@@ -2464,8 +2698,9 @@ var LibraryGL = {
gluPerspective: function(fov, aspect, near, far) {
GL.immediate.matricesModified = true;
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
- GL.immediate.matrix.lib.mat4.perspective(fov, aspect, near, far, GL.immediate.currentMatrix));
+ GL.immediate.matrix[GL.immediate.currentMatrix] =
+ GL.immediate.matrix.lib.mat4.perspective(fov, aspect, near, far,
+ GL.immediate.matrix[GL.immediate.currentMatrix]);
},
gluLookAt: function(ex, ey, ez, cx, cy, cz, ux, uy, uz) {
@@ -2534,8 +2769,8 @@ var LibraryGL = {
glTexGeni: function() { throw 'glTexGeni: TODO' },
glTexGenfv: function() { throw 'glTexGenfv: TODO' },
- glTexEnvi: function() { throw 'glTexEnvi: TODO' },
- glTexEnvfv: function() { throw 'glTexEnvfv: TODO' },
+ glTexEnvi: function() { Runtime.warnOnce('glTexEnvi: TODO') },
+ glTexEnvfv: function() { Runtime.warnOnce('glTexEnvfv: TODO') },
glTexImage1D: function() { throw 'glTexImage1D: TODO' },
glTexCoord3f: function() { throw 'glTexCoord3f: TODO' },
@@ -2548,6 +2783,22 @@ var LibraryGL = {
glVertexAttribPointer__sig: 'viiiiii',
glCheckFramebufferStatus__sig: 'ii',
glRenderbufferStorage__sig: 'viiii',
+
+ // Open GLES1.1 compatibility
+ glGenFramebuffersOES : 'glGenFramebuffers',
+ glGenRenderbuffersOES : 'glGenRenderbuffers',
+ glBindFramebufferOES : 'glBindFramebuffer',
+ glBindRenderbufferOES : 'glBindRenderbuffer',
+ glGetRenderbufferParameterivOES : 'glGetRenderbufferParameteriv',
+ glFramebufferRenderbufferOES : 'glFramebufferRenderbuffer',
+ glRenderbufferStorageOES : 'glRenderbufferStorage',
+ glCheckFramebufferStatusOES : 'glCheckFramebufferStatus',
+ glDeleteFramebuffersOES : 'glDeleteFramebuffers',
+ glDeleteRenderbuffersOES : 'glDeleteRenderbuffers',
+ glGenVertexArraysOES: 'glGenVertexArrays',
+ glDeleteVertexArraysOES: 'glDeleteVertexArrays',
+ glBindVertexArrayOES: 'glBindVertexArray',
+ glFramebufferTexture2DOES: 'glFramebufferTexture2D'
};
// Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name
diff --git a/src/library_glut.js b/src/library_glut.js
index 2e662698..bb4dfefa 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -381,6 +381,12 @@ var LibraryGLUT = {
return 1;
},
+ glutDestroyWindow__deps: ['$Browser'],
+ glutDestroyWindow: function(name) {
+ Module.ctx = Browser.destroyContext(Module['canvas'], true, true);
+ return 1;
+ },
+
glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'],
glutReshapeWindow: function(width, height) {
GLUT.cancelFullScreen();
diff --git a/src/library_sdl.js b/src/library_sdl.js
index cfab6410..e02e1e62 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -607,9 +607,11 @@ var LibrarySDL = {
SDL_Init: function(what) {
SDL.startTime = Date.now();
// capture all key events. we just keep down and up, but also capture press to prevent default actions
- document.onkeydown = SDL.receiveEvent;
- document.onkeyup = SDL.receiveEvent;
- document.onkeypress = SDL.receiveEvent;
+ if (!Module['doNotCaptureKeyboard']) {
+ document.onkeydown = SDL.receiveEvent;
+ document.onkeyup = SDL.receiveEvent;
+ document.onkeypress = SDL.receiveEvent;
+ }
window.onunload = SDL.receiveEvent;
SDL.keyboardState = _malloc(0x10000);
_memset(SDL.keyboardState, 0, 0x10000);
@@ -1077,7 +1079,9 @@ var LibrarySDL = {
}
var surf = SDL.makeSurface(raw.width, raw.height, 0, false, 'load:' + filename);
var surfData = SDL.surfaces[surf];
+ surfData.ctx.globalCompositeOperation = "copy";
surfData.ctx.drawImage(raw, 0, 0, raw.width, raw.height, 0, 0, raw.width, raw.height);
+ surfData.ctx.globalCompositeOperation = "source-over";
// XXX SDL does not specify that loaded images must have available pixel data, in fact
// there are cases where you just want to blit them, so you just need the hardware
// accelerated version. However, code everywhere seems to assume that the pixels
@@ -1176,6 +1180,10 @@ var LibrarySDL = {
// SDL Mixer
+ Mix_Init: function(flags) {
+ return 8; /* MIX_INIT_OGG */
+ },
+
Mix_OpenAudio: function(frequency, format, channels, chunksize) {
SDL.allocateChannels(32);
// Just record the values for a later call to Mix_QuickLoad_RAW
diff --git a/src/parseTools.js b/src/parseTools.js
index e081d0de..357d33a1 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -103,6 +103,11 @@ function isNiceIdent(ident, loose) {
}
}
+function isJSVar(ident) {
+ return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident);
+
+}
+
function isStructPointerType(type) {
// This test is necessary for clang - in llvm-gcc, we
// could check for %struct. The downside is that %1 can
@@ -976,12 +981,6 @@ function checkSafeHeap() {
return SAFE_HEAP === 1 || checkSpecificSafeHeap();
}
-if (ASM_JS) {
- var hexMemoryMask = '0x' + (TOTAL_MEMORY-1).toString(16);
- var decMemoryMask = (TOTAL_MEMORY-1).toString();
- var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask;
-}
-
function getHeapOffset(offset, type, forceAsm) {
if (USE_TYPED_ARRAYS !== 2) {
return offset;
@@ -991,11 +990,11 @@ function getHeapOffset(offset, type, forceAsm) {
}
var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2;
offset = '(' + offset + ')';
- if (ASM_JS && (phase == 'funcs' || forceAsm)) offset = '(' + offset + '&' + memoryMask + ')';
if (shifts != 0) {
return '(' + offset + '>>' + shifts + ')';
} else {
- return offset;
+ // we need to guard against overflows here, HEAP[U]8 expects a guaranteed int
+ return isJSVar(offset) ? offset : '(' + offset + '|0)';
}
}
}
@@ -1045,20 +1044,6 @@ function asmCoercion(value, type, signedness) {
}
}
-var TWO_TWENTY = Math.pow(2, 20);
-
-function asmMultiplyI32(a, b) {
- // special-case: there is no integer multiply in asm, because there is no true integer
- // multiply in JS. While we wait for Math.imul, do double multiply
- if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY)) {
- return '(((' + a + ')*(' + b + '))&-1)'; // small enough to emit directly as a multiply
- }
- if (USE_MATH_IMUL) {
- return 'Math.imul(' + a + ',' + b + ')';
- }
- return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))';
-}
-
function asmFloatToInt(x) {
return '(~~(' + x + '))';
}
@@ -1070,7 +1055,6 @@ function makeGetTempDouble(i, type, forSet) { // get an aliased part of the temp
var ptr = getFastValue('tempDoublePtr', '+', Runtime.getNativeTypeSize(type)*i);
var offset;
if (type == 'double') {
- if (ASM_JS) ptr = '(' + ptr + ')&' + memoryMask;
offset = '(' + ptr + ')>>3';
} else {
offset = getHeapOffset(ptr, type);
@@ -1153,8 +1137,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
}
-function makeGetValueAsm(ptr, pos, type) {
- return makeGetValue(ptr, pos, type, null, null, null, null, null, true);
+function makeGetValueAsm(ptr, pos, type, unsigned) {
+ return makeGetValue(ptr, pos, type, null, unsigned, null, null, null, true);
}
function indexizeFunctions(value, type) {
@@ -1372,9 +1356,11 @@ function makeHEAPView(which, start, end) {
var PLUS_MUL = set('+', '*');
var MUL_DIV = set('*', '/');
var PLUS_MINUS = set('+', '-');
+var TWO_TWENTY = Math.pow(2, 20);
// Given two values and an operation, returns the result of that operation.
// Tries to do as much as possible at compile time.
+// Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul
function getFastValue(a, op, b, type) {
a = a.toString();
b = b.toString();
@@ -1410,8 +1396,14 @@ function getFastValue(a, op, b, type) {
return '(' + a + '<<' + shifts + ')';
}
}
- if (ASM_JS && !(type in Runtime.FLOAT_TYPES)) {
- return asmMultiplyI32(a, b); // unoptimized multiply, do it using asm.js's special multiply operation
+ if (!(type in Runtime.FLOAT_TYPES)) {
+ // if guaranteed small enough to not overflow into a double, do a normal multiply
+ var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
+ // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there
+ if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
+ return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
+ }
+ return 'Math.imul(' + a + ',' + b + ')';
}
} else {
if (a == '0') {
@@ -1717,9 +1709,7 @@ function handleOverflow(text, bits) {
if (!bits) return text;
var correct = correctOverflows();
warnOnce(!correct || bits <= 32, 'Cannot correct overflows of this many bits: ' + bits);
- if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow() && !PGO) + (
- PGO ? ', "' + Debugging.getIdentifier() + '"' : ''
- ) + ')';
+ if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow()) + ')';
if (!correct) return text;
if (bits == 32) {
return '((' + text + ')|0)';
@@ -1827,9 +1817,7 @@ function makeSignOp(value, type, op, force, ignore) {
var bits, full;
if (type in Runtime.INT_TYPES) {
bits = parseInt(type.substr(1));
- full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign() && !PGO)) + (
- PGO ? ', "' + (ignore ? '' : Debugging.getIdentifier()) + '"' : ''
- ) + ')';
+ full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')';
// Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
if (isNumber(value)) {
return eval(full).toString();
@@ -2142,14 +2130,7 @@ function processMathop(item) {
case 'add': return handleOverflow(getFastValue(idents[0], '+', idents[1], item.type), bits);
case 'sub': return handleOverflow(getFastValue(idents[0], '-', idents[1], item.type), bits);
case 'sdiv': case 'udiv': return makeRounding(getFastValue(idents[0], '/', idents[1], item.type), bits, op[0] === 's');
- case 'mul': {
- if (bits == 32 && PRECISE_I32_MUL) {
- Types.preciseI64MathUsed = true;
- return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + asmCoercion(idents[0], 'i32') + ',0,' + asmCoercion(idents[1], 'i32') + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')';
- } else {
- return '((' +getFastValue(idents[0], '*', idents[1], item.type) + ')&-1)'; // force a non-eliminatable coercion here, to prevent a double result from leaking
- }
- }
+ case 'mul': return getFastValue(idents[0], '*', idents[1], item.type); // overflow handling is already done in getFastValue for '*'
case 'urem': case 'srem': return getFastValue(idents[0], '%', idents[1], item.type);
case 'or': {
if (bits > 32) {
diff --git a/src/preamble.js b/src/preamble.js
index aab50e9a..a7731e7f 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -150,52 +150,6 @@ function SAFE_HEAP_COPY_HISTORY(dest, src) {
//==========================================
#endif
-var CorrectionsMonitor = {
-#if PGO
- MAX_ALLOWED: Infinity,
-#else
- MAX_ALLOWED: 0, // XXX
-#endif
- corrections: 0,
- sigs: {},
-
- note: function(type, succeed, sig) {
- if (!succeed) {
- this.corrections++;
- if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!');
- }
-#if PGO
- if (!sig)
- sig = (new Error().stack).toString().split('\n')[2].split(':').slice(-1)[0]; // Spidermonkey-specific FIXME
- sig = type + '|' + sig;
- if (!this.sigs[sig]) {
- //Module.print('Correction: ' + sig);
- this.sigs[sig] = [0, 0]; // fail, succeed
- }
- this.sigs[sig][succeed ? 1 : 0]++;
-#endif
- },
-
- print: function() {
-#if PGO
- var items = [];
- for (var sig in this.sigs) {
- items.push({
- sig: sig,
- fails: this.sigs[sig][0],
- succeeds: this.sigs[sig][1],
- total: this.sigs[sig][0] + this.sigs[sig][1]
- });
- }
- items.sort(function(x, y) { return y.total - x.total; });
- for (var i = 0; i < items.length; i++) {
- var item = items[i];
- Module.print(item.sig + ' : ' + item.total + ' hits, %' + (Math.ceil(100*item.fails/item.total)) + ' failures');
- }
-#endif
- }
-};
-
#if CHECK_OVERFLOWS
//========================================
// Debugging tools - Mathop overflows
@@ -207,24 +161,20 @@ function CHECK_OVERFLOW(value, bits, ignore, sig) {
// For signedness issue here, see settings.js, CHECK_SIGNED_OVERFLOWS
#if CHECK_SIGNED_OVERFLOWS
if (value === Infinity || value === -Infinity || value >= twopbits1 || value < -twopbits1) {
- CorrectionsMonitor.note('SignedOverflow', 0, sig);
- if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) CorrectionsMonitor.note('Overflow');
+ throw 'SignedOverflow';
+ if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) throw 'Overflow';
+ }
#else
if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) {
- CorrectionsMonitor.note('Overflow', 0, sig);
+ throw 'Overflow';
+ }
#endif
#if CORRECT_OVERFLOWS
- // Fail on >32 bits - we warned at compile time
- if (bits <= 32) {
- value = value & (twopbits - 1);
- }
-#endif
- } else {
-#if CHECK_SIGNED_OVERFLOWS
- CorrectionsMonitor.note('SignedOverflow', 1, sig);
-#endif
- CorrectionsMonitor.note('Overflow', 1, sig);
+ // Fail on >32 bits - we warned at compile time
+ if (bits <= 32) {
+ value = value & (twopbits - 1);
}
+#endif
return value;
}
#endif
@@ -243,39 +193,6 @@ var INDENT = '';
var START_TIME = Date.now();
#endif
-#if PROFILE
-var PROFILING = 0;
-var PROFILING_ROOT = { time: 0, children: {}, calls: 0 };
-var PROFILING_NODE;
-
-function startProfiling() {
- PROFILING_NODE = PROFILING_ROOT;
- PROFILING = 1;
-}
-Module['startProfiling'] = startProfiling;
-
-function stopProfiling() {
- PROFILING = 0;
- assert(PROFILING_NODE === PROFILING_ROOT, 'Must have popped all the profiling call stack');
-}
-Module['stopProfiling'] = stopProfiling;
-
-function printProfiling() {
- function dumpData(name_, node, indent) {
- Module.print(indent + ('________' + node.time).substr(-8) + ': ' + name_ + ' (' + node.calls + ')');
- var children = [];
- for (var child in node.children) {
- children.push(node.children[child]);
- children[children.length-1].name_ = child;
- }
- children.sort(function(x, y) { return y.time - x.time });
- children.forEach(function(child) { dumpData(child.name_, child, indent + ' ') });
- }
- dumpData('root', PROFILING_ROOT, ' ');
-}
-Module['printProfiling'] = printProfiling;
-#endif
-
//========================================
// Runtime essentials
//========================================
@@ -655,47 +572,43 @@ function enlargeMemory() {
#endif
var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}};
-#if ASM_JS == 0
var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}};
-#else
-var TOTAL_MEMORY = {{{ TOTAL_MEMORY }}}; // in asm, we hardcode the mask, so cannot adjust memory at runtime
-#endif
var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
// Initialize the runtime's memory
#if USE_TYPED_ARRAYS
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
- assert(!!Int32Array && !!Float64Array && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
- 'Cannot fallback to non-typed array case: Code is too specialized');
+assert(!!Int32Array && !!Float64Array && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+ 'Cannot fallback to non-typed array case: Code is too specialized');
#if USE_TYPED_ARRAYS == 1
- HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
- IHEAPU = new Uint32Array(IHEAP.buffer);
+HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
+IHEAPU = new Uint32Array(IHEAP.buffer);
#if USE_FHEAP
- FHEAP = new Float64Array(TOTAL_MEMORY);
+FHEAP = new Float64Array(TOTAL_MEMORY);
#endif
#endif
#if USE_TYPED_ARRAYS == 2
- var buffer = new ArrayBuffer(TOTAL_MEMORY);
- HEAP8 = new Int8Array(buffer);
- HEAP16 = new Int16Array(buffer);
- HEAP32 = new Int32Array(buffer);
- HEAPU8 = new Uint8Array(buffer);
- HEAPU16 = new Uint16Array(buffer);
- HEAPU32 = new Uint32Array(buffer);
- HEAPF32 = new Float32Array(buffer);
- HEAPF64 = new Float64Array(buffer);
-
- // Endianness check (note: assumes compiler arch was little-endian)
- HEAP32[0] = 255;
- assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
#endif
#else
- // Make sure that our HEAP is implemented as a flat array.
- HEAP = []; // Hinting at the size with |new Array(TOTAL_MEMORY)| should help in theory but makes v8 much slower
- for (var i = 0; i < FAST_MEMORY; i++) {
- HEAP[i] = 0; // XXX We do *not* use {{| makeSetValue(0, 'i', 0, 'null') |}} here, since this is done just to optimize runtime speed
- }
+// Make sure that our HEAP is implemented as a flat array.
+HEAP = []; // Hinting at the size with |new Array(TOTAL_MEMORY)| should help in theory but makes v8 much slower
+for (var i = 0; i < FAST_MEMORY; i++) {
+ HEAP[i] = 0; // XXX We do *not* use {{| makeSetValue(0, 'i', 0, 'null') |}} here, since this is done just to optimize runtime speed
+}
#endif
Module['HEAP'] = HEAP;
@@ -722,7 +635,7 @@ STACK_MAX = TOTAL_STACK; // we lose a little stack here, but TOTAL_STACK is nice
#if USE_TYPED_ARRAYS == 2
var tempDoublePtr = Runtime.alignMemory(allocate(12, 'i8', ALLOC_STACK), 8);
assert(tempDoublePtr % 8 == 0);
-function copyTempFloat(ptr) { // functions, because inlining this code is increases code size too much
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
HEAP8[tempDoublePtr] = HEAP8[ptr];
HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
@@ -773,9 +686,6 @@ function preMain() {
}
function exitRuntime() {
callRuntimeCallbacks(__ATEXIT__);
-
- // Print summary of correction activity
- CorrectionsMonitor.print();
}
// Tools
@@ -832,6 +742,20 @@ Module['writeArrayToMemory'] = writeArrayToMemory;
{{{ unSign }}}
{{{ reSign }}}
+#if PRECISE_I32_MUL
+if (!Math.imul) Math.imul = function(a, b) {
+ var ah = a >>> 16;
+ var al = a & 0xffff;
+ var bh = b >>> 16;
+ var bl = b & 0xffff;
+ return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+#else
+Math.imul = function(a, b) {
+ return (a*b)|0; // fast but imprecise
+};
+#endif
+
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
diff --git a/src/runtime.js b/src/runtime.js
index e5b86065..e902d27b 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -242,6 +242,10 @@ var Runtime = {
} else if (Runtime.isStructType(field)) {
size = Types.types[field].flatSize;
alignSize = Types.types[field].alignSize;
+ } else if (field[0] == 'b') {
+ // bN, large number field, like a [N x i8]
+ size = field.substr(1)|0;
+ alignSize = 1;
} else {
throw 'Unclear type in struct: ' + field + ', in ' + type.name_ + ' :: ' + dump(Types.types[type.name_]);
}
@@ -353,7 +357,7 @@ var Runtime = {
},
addFunction: function(func, sig) {
- assert(sig);
+ //assert(sig); // TODO: support asm
var table = FUNCTION_TABLE; // TODO: support asm
var ret = table.length;
table.push(func);
@@ -505,26 +509,19 @@ function getRuntime() {
// example, -1 in int32 would be a very large number as unsigned.
function unSign(value, bits, ignore, sig) {
if (value >= 0) {
-#if CHECK_SIGNS
- if (!ignore) CorrectionsMonitor.note('UnSign', 1, sig);
-#endif
return value;
}
#if CHECK_SIGNS
- if (!ignore) CorrectionsMonitor.note('UnSign', 0, sig);
+ if (!ignore) throw 'UnSign';
#endif
return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
: Math.pow(2, bits) + value;
- // TODO: clean up previous line
}
// Converts a value we have as unsigned, into a signed value. For
// example, 200 in a uint8 would be a negative number.
function reSign(value, bits, ignore, sig) {
if (value <= 0) {
-#if CHECK_SIGNS
- if (!ignore) CorrectionsMonitor.note('ReSign', 1, sig);
-#endif
return value;
}
var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
@@ -536,10 +533,7 @@ function reSign(value, bits, ignore, sig) {
// but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
// TODO: In i64 mode 1, resign the two parts separately and safely
#if CHECK_SIGNS
- if (!ignore) {
- CorrectionsMonitor.note('ReSign', 0, sig);
- noted = true;
- }
+ if (!ignore) throw 'ReSign';
#endif
value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
}
@@ -548,18 +542,9 @@ function reSign(value, bits, ignore, sig) {
// without CHECK_SIGNS, we would just do the |0 shortcut, so check that that
// would indeed give the exact same result.
if (bits === 32 && (value|0) !== value && typeof value !== 'boolean') {
- if (!ignore) {
- CorrectionsMonitor.note('ReSign', 0, sig);
- noted = true;
- }
+ if (!ignore) throw 'ReSign';
}
- if (!noted) CorrectionsMonitor.note('ReSign', 1, sig);
#endif
return value;
}
-// Just a stub. We don't care about noting compile-time corrections. But they are called.
-var CorrectionsMonitor = {
- note: function(){}
-};
-
diff --git a/src/settings.js b/src/settings.js
index 0234d0ca..7caa5b92 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -92,13 +92,9 @@ var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which i
// that we can't know at compile time that 64-bit math is needed. For example, if you
// print 64-bit values with printf, but never add them, we can't know at compile time
// and you need to set this to 2.
-var PRECISE_I32_MUL = 0; // If enabled, i64 math is done in i32 multiplication. This is necessary if the values
- // exceed the JS double-integer limit of ~52 bits. This option can normally be disabled
- // because generally i32 multiplication works ok without it, and enabling it has a big
- // impact on performance.
- // Note that you can hand-optimize your code to avoid the need for this: If you do
- // multiplications that actually need 64-bit precision inside 64-bit values, things
- // will work properly. (Unless the LLVM optimizer turns them into 32-bit values?)
+var PRECISE_I32_MUL = 1; // If enabled, i32 multiplication is done with full precision, which means it is
+ // correct even if the value exceeds the JS double-integer limit of ~52 bits (otherwise,
+ // rounding will occur above that range).
var CLOSURE_ANNOTATIONS = 0; // If set, the generated code will be annotated for the closure
// compiler. This potentially lets closure optimize the code better.
@@ -134,6 +130,16 @@ var SAFE_HEAP_LOG = 0; // Log out all SAFE_HEAP operations
var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js
+var CORRUPTION_CHECK = 0; // When enabled, will emit a buffer area at the beginning and
+ // end of each allocation on the heap, filled with canary
+ // values that can be checked later. Corruption is checked for
+ // at the end of each at each free() (see jsifier to add more, and you
+ // can add more manual checks by calling CorruptionChecker.checkAll).
+ // 0 means not enabled, higher values mean the size of the
+ // buffer areas as a multiple of the allocated area (so
+ // 1 means 100%, or buffer areas equal to allocated area,
+ // both before and after). This must be an integer.
+
var LABEL_DEBUG = 0; // 1: Print out functions as we enter them
// 2: Also print out each label as we enter it
var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug.
@@ -148,11 +154,13 @@ var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js).
// Runtime.debug at runtime for logging to cease, and can set it when you
// want it back. A simple way to set it in C++ is
// emscripten_run_script("Runtime.debug = ...;");
-var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you can set a runtime
- // option, in this case GL.debug.
var SOCKET_DEBUG = 0; // Log out socket/network data transfer.
-var PROFILE_MAIN_LOOP = 0; // Profile the function called in set_main_loop
+var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you can set a runtime
+ // option, in this case GL.debug.
+var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, to allow tests to work (but adds overhead)
+var GL_MAX_TEMP_BUFFER_SIZE = 2097152; // How large GL emulation temp buffers are
+var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL emulation code
var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catch exceptions. If the code you
// are compiling does not actually rely on catching exceptions (but the
@@ -203,21 +211,10 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
-var PGO = 0; // Profile-guided optimization.
- // When run with the CHECK_* options, will not fail on errors. Instead, will
- // keep a record of which checks succeeded and which failed. On shutdown, will
- // print out that information. This is useful for knowing which lines need
- // checking enabled and which do not, that is, this is a way to automate the
- // generation of line data for CORRECT_*_LINES options.
- // All CORRECT_* options default to 1 with PGO builds.
- // See https://github.com/kripken/emscripten/wiki/Optimizing-Code for more info
-
var NAMED_GLOBALS = 0; // If 1, we use global variables for globals. Otherwise
// they are referred to by a base plus an offset (called an indexed global),
// saving global variables but adding runtime overhead.
-var PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example.
-
var EXPORT_ALL = 0; // If true, we export all the symbols
var EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported. These functions are kept alive
// through LLVM dead code elimination, and also made accessible outside of
@@ -325,7 +322,6 @@ var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and
var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly experimental,
// and will not work on most codebases yet. It is NOT recommended that you
// try this yet.
-var USE_MATH_IMUL = 0; // If 1, use Math.imul when useful
var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?:
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index b98a79e4..d41f4140 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -48,8 +48,3 @@ _ZNSt20bad_array_new_lengthC2Ev
_ZNSt20bad_array_new_lengthD0Ev
_ZNSt20bad_array_new_lengthD1Ev
_ZNSt20bad_array_new_lengthD2Ev
-memcpy
-llvm.memcpy.i32
-llvm.memcpy.i64
-llvm.memcpy.p0i8.p0i8.i32
-llvm.memcpy.p0i8.p0i8.i64
diff --git a/system/lib/libcxx/symbols b/system/lib/libcxx/symbols
index 23d4a7a4..0d412de7 100644
--- a/system/lib/libcxx/symbols
+++ b/system/lib/libcxx/symbols
@@ -767,7 +767,6 @@
W _ZNKSt3__19money_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE3putES4_bRNS_8ios_baseEwe
W _ZNKSt3__19money_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_bRNS_8ios_baseEwRKNS_12basic_stringIwS3_NS_9allocatorIwEEEE
W _ZNKSt3__19money_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEE6do_putES4_bRNS_8ios_baseEwe
- T _ZNKSt8bad_cast4whatEv
T _ZNKSt9exception4whatEv
T _ZNSt10bad_typeidC1Ev
T _ZNSt10bad_typeidC2Ev
@@ -2561,11 +2560,6 @@
d _ZNSt3__1L7__wcoutE
d _ZNSt3__1L8__rs_mutE
W _ZNSt3__1plIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_12basic_stringIT_T0_T1_EEPKS6_RKS9_
- T _ZNSt8bad_castC1Ev
- T _ZNSt8bad_castC2Ev
- T _ZNSt8bad_castD0Ev
- T _ZNSt8bad_castD1Ev
- T _ZNSt8bad_castD2Ev
T _ZNSt9exceptionD0Ev
T _ZNSt9exceptionD1Ev
T _ZNSt9exceptionD2Ev
@@ -2719,7 +2713,6 @@
D _ZTISt15underflow_error
D _ZTISt16invalid_argument
D _ZTISt16nested_exception
- D _ZTISt8bad_cast
D _ZTISt9exception
C _ZTSNSt3__110__stdinbufIcEE
C _ZTSNSt3__110__stdinbufIwEE
@@ -2855,7 +2848,6 @@
D _ZTSSt15underflow_error
D _ZTSSt16invalid_argument
D _ZTSSt16nested_exception
- D _ZTSSt8bad_cast
D _ZTSSt9exception
D _ZTTNSt3__110istrstreamE
D _ZTTNSt3__110ostrstreamE
@@ -2980,7 +2972,6 @@
D _ZTVSt15underflow_error
D _ZTVSt16invalid_argument
D _ZTVSt16nested_exception
- D _ZTVSt8bad_cast
D _ZTVSt9exception
W _ZThn8_NKSt3__115time_get_bynameIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEE3__XEv
W _ZThn8_NKSt3__115time_get_bynameIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEE3__cEv
diff --git a/system/lib/libcxxabi/symbols b/system/lib/libcxxabi/symbols
index 8ef205ba..b63f2f82 100644
--- a/system/lib/libcxxabi/symbols
+++ b/system/lib/libcxxabi/symbols
@@ -10,3 +10,10 @@
D _ZTVN10__cxxabiv121__vmi_class_type_infoE
D _ZTVN10__cxxabiv123__fundamental_type_infoE
D _ZTVN10__cxxabiv129__pointer_to_member_type_infoE
+ D _ZTSSt9type_info
+ T _ZNKSt8bad_cast4whatEv
+ T _ZNSt8bad_castC1Ev
+ T _ZNSt8bad_castC2Ev
+ D _ZTISt8bad_cast
+ D _ZTSSt8bad_cast
+ D _ZTVSt8bad_cast
diff --git a/tests/aniso.png b/tests/aniso.png
index 5f5812d2..2bcb2f5f 100644
--- a/tests/aniso.png
+++ b/tests/aniso.png
Binary files differ
diff --git a/tests/cubegeom.c b/tests/cubegeom.c
index c137ad80..6158b124 100644
--- a/tests/cubegeom.c
+++ b/tests/cubegeom.c
@@ -207,6 +207,20 @@ int main(int argc, char *argv[])
glNormalPointer(GL_BYTE, 32, (void*)12);
glColorPointer(4, GL_UNSIGNED_BYTE, 32, (void*)28);
+ int temp; // test glGetPointerv, glGetIntegerv
+ glGetPointerv(GL_VERTEX_ARRAY_POINTER, &temp); assert(temp == 0);
+ glGetPointerv(GL_COLOR_ARRAY_POINTER, &temp); assert(temp == 28);
+ glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &temp); assert(temp == 16);
+ glGetIntegerv(GL_VERTEX_ARRAY_SIZE, &temp); assert(temp == 3);
+ glGetIntegerv(GL_VERTEX_ARRAY_TYPE, &temp); assert(temp == GL_FLOAT);
+ glGetIntegerv(GL_VERTEX_ARRAY_STRIDE, &temp); assert(temp == 32);
+ glGetIntegerv(GL_COLOR_ARRAY_SIZE, &temp); assert(temp == 4);
+ glGetIntegerv(GL_COLOR_ARRAY_TYPE, &temp); assert(temp == GL_UNSIGNED_BYTE);
+ glGetIntegerv(GL_COLOR_ARRAY_STRIDE, &temp); assert(temp == 32);
+ glGetIntegerv(GL_TEXTURE_COORD_ARRAY_SIZE, &temp); assert(temp == 2);
+ glGetIntegerv(GL_TEXTURE_COORD_ARRAY_TYPE, &temp); assert(temp == GL_FLOAT);
+ glGetIntegerv(GL_TEXTURE_COORD_ARRAY_STRIDE, &temp); assert(temp == 32);
+
glBindTexture(GL_TEXTURE_2D, texture); // diffuse?
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE1);
diff --git a/tests/cubegeom_pre2_vao.c b/tests/cubegeom_pre2_vao.c
new file mode 100644
index 00000000..98bedd54
--- /dev/null
+++ b/tests/cubegeom_pre2_vao.c
@@ -0,0 +1,380 @@
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays_ = NULL;
+PFNGLBINDVERTEXARRAYPROC glBindVertexArray_ = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays_ = NULL;
+
+void verify() {
+ int width = 640, height = 480;
+ unsigned char *data = (unsigned char*)malloc(width*height*4);
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ int sum = 0;
+ for (int x = 0; x < width*height*4; x++) {
+ if (x % 4 != 3) sum += x * data[x];
+ }
+#if EMSCRIPTEN
+ int result = sum;
+ REPORT_RESULT();
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ screen = SDL_SetVideoMode( 640, 480, 24, SDL_OPENGL );
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ glClearColor( 0, 0, 0, 0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glGenVertexArrays_ = (PFNGLGENVERTEXARRAYSPROC) SDL_GL_GetProcAddress("glGenVertexArrays");
+ assert(glGenVertexArrays_);
+ glBindVertexArray_ = (PFNGLBINDVERTEXARRAYPROC) SDL_GL_GetProcAddress("glBindVertexArray");
+ assert(glBindVertexArray_);
+ glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC) SDL_GL_GetProcAddress("glDeleteVertexArrays");
+ assert(glDeleteVertexArrays_);
+
+ // Generate a VAO
+ GLuint vao;
+ glGenVertexArrays_(1, &vao);
+ glBindVertexArray_(vao);
+
+ // Create a texture
+
+ GLuint texture;
+ glGenTextures( 1, &texture );
+ glBindTexture( GL_TEXTURE_2D, texture );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte textureData[16*16*4];
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ *((int*)&textureData[(x*16 + y) * 4]) = x*16 + ((y*16) << 8);
+ }
+ }
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, textureData );
+
+ // Create a second texture
+
+ GLuint texture2;
+ glGenTextures( 1, &texture2 );
+ glBindTexture( GL_TEXTURE_2D, texture2 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte texture2Data[] = { 0xff, 0, 0, 0xff,
+ 0, 0xff, 0, 0xaa,
+ 0, 0, 0xff, 0x55,
+ 0x80, 0x90, 0x70, 0 };
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texture2Data );
+
+ // BEGIN
+
+#if USE_GLEW
+ glewInit();
+#endif
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ // original: glFrustum(-0.6435469817188064, 0.6435469817188064 ,-0.48266022190470925, 0.48266022190470925 ,0.5400000214576721, 2048);
+ //glFrustum(-0.6435469817188064, 0.1435469817188064 ,-0.48266022190470925, 0.88266022190470925 ,0.5400000214576721, 2048);
+ GLfloat pm[] = { 1.372136116027832, 0, 0, 0, 0, 0.7910231351852417, 0, 0, -0.6352481842041016, 0.29297152161598206, -1.0005275011062622, -1, 0, 0, -1.080284833908081, 0 };
+ glLoadMatrixf(pm);
+
+ glMatrixMode(GL_MODELVIEW);
+ GLfloat matrixData[] = { -1, 0, 0, 0,
+ 0, 0,-1, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1 };
+ glLoadMatrixf(matrixData);
+ //glTranslated(-512,-512,-527); // XXX this should be uncommented, but if it is then nothing is shown
+
+// glEnable(GL_CULL_FACE);
+ // glEnable(GL_DEPTH_TEST);
+
+ //glClear(GL_DEPTH_BUFFER_BIT);
+
+// glEnableClientState(GL_NORMAL_ARRAY);
+ // glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ GLuint arrayBuffer, elementBuffer;
+ glGenBuffers(1, &arrayBuffer);
+ glGenBuffers(1, &elementBuffer);
+
+ GLubyte arrayData[] = {
+/*
+[0, 0, 0, 67] ==> 128 float
+[0, 0, 128, 67] ==> 256 float
+[0, 0, 0, 68] ==> 512 float
+[0, 0, 128, 68] ==> 1024 float
+
+[vertex x ] [vertex y ] [vertex z ] [nr] [texture u ] [texture v ] [lm u ] [lm v ] [color r,g,b,a ] */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 0
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 1
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 2
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 3
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 4
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 5
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 6
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 7
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 8
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 9
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 10
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 11
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 12
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 13
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 14
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 15
+
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128
+ };
+ assert(sizeof(arrayData) == 1408);
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(arrayData), arrayData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ GLushort elementData[] = { 1, 2, 0, 2, 3, 0, 5, 6, 4, 6, 7, 4, 9, 10, 8, 10, 11, 8, 13, 14, 12, 14, 15, 12 };
+ assert(sizeof(elementData) == 48);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), elementData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+
+ // sauer vertex data is apparently 0-12: V3F, 12: N1B, 16-24: T2F, 24-28: T2S, 28-32: C4B
+ glVertexPointer(3, GL_FLOAT, 32, (void*)0); // all these apply to the ARRAY_BUFFER that is bound
+ glTexCoordPointer(2, GL_FLOAT, 32, (void*)16);
+// glClientActiveTexture(GL_TEXTURE1); // XXX seems to be ignored in native build
+// glTexCoordPointer(2, GL_SHORT, 32, (void*)24);
+// glClientActiveTexture(GL_TEXTURE0); // likely not needed, it is a cleanup
+// glNormalPointer(GL_BYTE, 32, (void*)12);
+// glColorPointer(4, GL_UNSIGNED_BYTE, 32, (void*)28);
+
+ glBindTexture(GL_TEXTURE_2D, texture); // diffuse?
+ glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, texture2); // lightmap?
+ glActiveTexture(GL_TEXTURE0);
+
+ GLint ok;
+
+ const char *vertexShader = "uniform mat4 u_modelView;\n"
+ "uniform mat4 u_projection;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n" // (gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex)
+ // (u_projection * u_modelView * a_position)
+ " gl_Position = (u_projection * u_modelView * gl_Vertex) + vec4(200, 0, 0, 0);\n"
+ " v_texCoord0.xy = gl_MultiTexCoord0.xy/20.0;\n" // added /100 here
+ "}\n";
+ const char *fragmentShader = "uniform sampler2D diffusemap;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " vec4 diffuse = texture2D(diffusemap, v_texCoord0.xy);\n"
+ " gl_FragColor = diffuse;\n"
+ "}\n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with vertex\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with fragment\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+
+ //GLint lightmapLocation = glGetUniformLocation(program, "lightmap");
+ //assert(lightmapLocation >= 0);
+ //glUniform1i(lightmapLocation, 1); // sampler2D? Is it the texture unit?
+
+ GLint diffusemapLocation = glGetUniformLocation(program, "diffusemap");
+ assert(diffusemapLocation >= 0);
+ glUniform1i(diffusemapLocation, 0);
+
+ //GLint texgenscrollLocation = glGetUniformLocation(program, "texgenscroll");
+ //assert(texgenscrollLocation >= 0);
+
+ //GLint colorparamsLocation = glGetUniformLocation(program, "colorparams");
+ //assert(colorparamsLocation >= 0);
+
+ //GLfloat texgenscrollData[] = { 0, 0, 0, 0 };
+ //glUniform4fv(texgenscrollLocation, 1, texgenscrollData);
+
+ //GLfloat colorparamsData[] = { 2, 2, 2, 1 };
+ //glUniform4fv(colorparamsLocation, 1, colorparamsData);
+
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_MODELVIEW_MATRIX, data);
+ printf("Modelview: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ //memset(data, 0, 16*4);
+ GLint modelViewLocation = glGetUniformLocation(program, "u_modelView");
+ assert(modelViewLocation >= 0);
+ glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, data);
+ }
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_PROJECTION_MATRIX, data);
+ printf("Projection: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ //memset(data, 0, 16*4);
+ GLint projectionLocation = glGetUniformLocation(program, "u_projection");
+ assert(projectionLocation >= 0);
+ glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, data);
+ }
+
+/*
+ glBindAttribLocation(program, 0, "a_position");
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, (void*)0);
+ glEnableVertexAttribArray(0);
+
+ glBindAttribLocation(program, 1, "v_texCoord0");
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 32, (void*)16);
+ glEnableVertexAttribArray(1);
+*/
+
+ // stop recording in the VAO
+
+ glBindVertexArray_(0);
+
+ // unbind all the stuff the VAO would save for us, so this is a valid test
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ // draw with VAO
+
+ glBindVertexArray_(vao);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)12);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*) 0);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)24);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)36);
+
+ // END
+
+ SDL_GL_SwapBuffers();
+
+ verify();
+
+#if !EMSCRIPTEN
+ SDL_Delay(1500);
+#endif
+
+ // SDL_Quit();
+
+ return 0;
+}
+
diff --git a/tests/cubegeom_pre2_vao2.c b/tests/cubegeom_pre2_vao2.c
new file mode 100644
index 00000000..e3ab4d62
--- /dev/null
+++ b/tests/cubegeom_pre2_vao2.c
@@ -0,0 +1,381 @@
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays_ = NULL;
+PFNGLBINDVERTEXARRAYPROC glBindVertexArray_ = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays_ = NULL;
+
+void verify() {
+ int width = 640, height = 480;
+ unsigned char *data = (unsigned char*)malloc(width*height*4);
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ int sum = 0;
+ for (int x = 0; x < width*height*4; x++) {
+ if (x % 4 != 3) sum += x * data[x];
+ }
+#if EMSCRIPTEN
+ int result = sum;
+ REPORT_RESULT();
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ screen = SDL_SetVideoMode( 640, 480, 24, SDL_OPENGL );
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ glClearColor( 0, 0, 0, 0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glGenVertexArrays_ = (PFNGLGENVERTEXARRAYSPROC) SDL_GL_GetProcAddress("glGenVertexArrays");
+ assert(glGenVertexArrays_);
+ glBindVertexArray_ = (PFNGLBINDVERTEXARRAYPROC) SDL_GL_GetProcAddress("glBindVertexArray");
+ assert(glBindVertexArray_);
+ glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC) SDL_GL_GetProcAddress("glDeleteVertexArrays");
+ assert(glDeleteVertexArrays_);
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY); // enabling it *before* the vao does nothing, the vao should wipe it out!
+
+ // Generate a VAO
+ GLuint vao;
+ glGenVertexArrays_(1, &vao);
+ glBindVertexArray_(vao);
+
+ // Create a texture
+
+ GLuint texture;
+ glGenTextures( 1, &texture );
+ glBindTexture( GL_TEXTURE_2D, texture );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte textureData[16*16*4];
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ *((int*)&textureData[(x*16 + y) * 4]) = x*16 + ((y*16) << 8);
+ }
+ }
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, textureData );
+
+ // Create a second texture
+
+ GLuint texture2;
+ glGenTextures( 1, &texture2 );
+ glBindTexture( GL_TEXTURE_2D, texture2 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte texture2Data[] = { 0xff, 0, 0, 0xff,
+ 0, 0xff, 0, 0xaa,
+ 0, 0, 0xff, 0x55,
+ 0x80, 0x90, 0x70, 0 };
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texture2Data );
+
+ // BEGIN
+
+#if USE_GLEW
+ glewInit();
+#endif
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ // original: glFrustum(-0.6435469817188064, 0.6435469817188064 ,-0.48266022190470925, 0.48266022190470925 ,0.5400000214576721, 2048);
+ //glFrustum(-0.6435469817188064, 0.1435469817188064 ,-0.48266022190470925, 0.88266022190470925 ,0.5400000214576721, 2048);
+ GLfloat pm[] = { 1.372136116027832, 0, 0, 0, 0, 0.7910231351852417, 0, 0, -0.6352481842041016, 0.29297152161598206, -1.0005275011062622, -1, 0, 0, -1.080284833908081, 0 };
+ glLoadMatrixf(pm);
+
+ glMatrixMode(GL_MODELVIEW);
+ GLfloat matrixData[] = { -1, 0, 0, 0,
+ 0, 0,-1, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1 };
+ glLoadMatrixf(matrixData);
+ //glTranslated(-512,-512,-527); // XXX this should be uncommented, but if it is then nothing is shown
+
+// glEnable(GL_CULL_FACE);
+ // glEnable(GL_DEPTH_TEST);
+
+ //glClear(GL_DEPTH_BUFFER_BIT);
+
+// glEnableClientState(GL_NORMAL_ARRAY);
+ // glEnableClientState(GL_COLOR_ARRAY);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ GLuint arrayBuffer, elementBuffer;
+ glGenBuffers(1, &arrayBuffer);
+ glGenBuffers(1, &elementBuffer);
+
+ GLubyte arrayData[] = {
+/*
+[0, 0, 0, 67] ==> 128 float
+[0, 0, 128, 67] ==> 256 float
+[0, 0, 0, 68] ==> 512 float
+[0, 0, 128, 68] ==> 1024 float
+
+[vertex x ] [vertex y ] [vertex z ] [nr] [texture u ] [texture v ] [lm u ] [lm v ] [color r,g,b,a ] */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 0
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 1
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 2
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 3
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 4
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 5
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 6
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 7
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 8
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 9
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 10
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 11
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 12
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 13
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 14
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 15
+
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128
+ };
+ assert(sizeof(arrayData) == 1408);
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(arrayData), arrayData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ GLushort elementData[] = { 1, 2, 0, 2, 3, 0, 5, 6, 4, 6, 7, 4, 9, 10, 8, 10, 11, 8, 13, 14, 12, 14, 15, 12 };
+ assert(sizeof(elementData) == 48);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), elementData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+
+ // sauer vertex data is apparently 0-12: V3F, 12: N1B, 16-24: T2F, 24-28: T2S, 28-32: C4B
+ glVertexPointer(3, GL_FLOAT, 32, (void*)0); // all these apply to the ARRAY_BUFFER that is bound
+ glTexCoordPointer(2, GL_FLOAT, 32, (void*)16);
+// glClientActiveTexture(GL_TEXTURE1); // XXX seems to be ignored in native build
+// glTexCoordPointer(2, GL_SHORT, 32, (void*)24);
+// glClientActiveTexture(GL_TEXTURE0); // likely not needed, it is a cleanup
+// glNormalPointer(GL_BYTE, 32, (void*)12);
+// glColorPointer(4, GL_UNSIGNED_BYTE, 32, (void*)28);
+
+ glBindTexture(GL_TEXTURE_2D, texture); // diffuse?
+ glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, texture2); // lightmap?
+ glActiveTexture(GL_TEXTURE0);
+
+ GLint ok;
+
+ const char *vertexShader = "uniform mat4 u_modelView;\n"
+ "uniform mat4 u_projection;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n" // (gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex)
+ // (u_projection * u_modelView * a_position)
+ " gl_Position = (u_projection * u_modelView * gl_Vertex) + vec4(200, 0, 0, 0);\n"
+ " v_texCoord0.xy = gl_MultiTexCoord0.xy/20.0;\n" // added /100 here
+ "}\n";
+ const char *fragmentShader = "uniform sampler2D diffusemap;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " vec4 diffuse = texture2D(diffusemap, v_texCoord0.xy);\n"
+ " gl_FragColor = diffuse;\n"
+ "}\n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with vertex\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with fragment\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+
+ //GLint lightmapLocation = glGetUniformLocation(program, "lightmap");
+ //assert(lightmapLocation >= 0);
+ //glUniform1i(lightmapLocation, 1); // sampler2D? Is it the texture unit?
+
+ GLint diffusemapLocation = glGetUniformLocation(program, "diffusemap");
+ assert(diffusemapLocation >= 0);
+ glUniform1i(diffusemapLocation, 0);
+
+ //GLint texgenscrollLocation = glGetUniformLocation(program, "texgenscroll");
+ //assert(texgenscrollLocation >= 0);
+
+ //GLint colorparamsLocation = glGetUniformLocation(program, "colorparams");
+ //assert(colorparamsLocation >= 0);
+
+ //GLfloat texgenscrollData[] = { 0, 0, 0, 0 };
+ //glUniform4fv(texgenscrollLocation, 1, texgenscrollData);
+
+ //GLfloat colorparamsData[] = { 2, 2, 2, 1 };
+ //glUniform4fv(colorparamsLocation, 1, colorparamsData);
+
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_MODELVIEW_MATRIX, data);
+ printf("Modelview: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ //memset(data, 0, 16*4);
+ GLint modelViewLocation = glGetUniformLocation(program, "u_modelView");
+ assert(modelViewLocation >= 0);
+ glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, data);
+ }
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_PROJECTION_MATRIX, data);
+ printf("Projection: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ //memset(data, 0, 16*4);
+ GLint projectionLocation = glGetUniformLocation(program, "u_projection");
+ assert(projectionLocation >= 0);
+ glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, data);
+ }
+
+/*
+ glBindAttribLocation(program, 0, "a_position");
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, (void*)0);
+ glEnableVertexAttribArray(0);
+
+ glBindAttribLocation(program, 1, "v_texCoord0");
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 32, (void*)16);
+ glEnableVertexAttribArray(1);
+*/
+
+ // stop recording in the VAO
+
+ glBindVertexArray_(0);
+
+ // unbind all the stuff the VAO would save for us, so this is a valid test
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ // draw with VAO
+
+ glBindVertexArray_(vao);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)12);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*) 0);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)24);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)36);
+
+ // END
+
+ SDL_GL_SwapBuffers();
+
+ verify();
+
+#if !EMSCRIPTEN
+ SDL_Delay(1500);
+#endif
+
+ // SDL_Quit();
+
+ return 0;
+}
+
diff --git a/tests/cubegeom_pre_vao.c b/tests/cubegeom_pre_vao.c
new file mode 100644
index 00000000..f1d35fb5
--- /dev/null
+++ b/tests/cubegeom_pre_vao.c
@@ -0,0 +1,333 @@
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void verify() {
+ int width = 640, height = 480;
+ unsigned char *data = (unsigned char*)malloc(width*height*4);
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ int sum = 0;
+ for (int x = 0; x < width*height*4; x++) {
+ if (x % 4 != 3) sum += x * data[x];
+ }
+#if EMSCRIPTEN
+ int result = sum;
+ REPORT_RESULT();
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ screen = SDL_SetVideoMode( 640, 480, 24, SDL_OPENGL );
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ glClearColor( 0, 0, 0, 0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ // Create a texture
+
+ GLuint texture;
+ glGenTextures( 1, &texture );
+ glBindTexture( GL_TEXTURE_2D, texture );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte textureData[16*16*4];
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ *((int*)&textureData[(x*16 + y) * 4]) = x*16 + ((y*16) << 8);
+ }
+ }
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, textureData );
+
+ // Create a second texture
+
+ GLuint texture2;
+ glGenTextures( 1, &texture2 );
+ glBindTexture( GL_TEXTURE_2D, texture2 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ GLubyte texture2Data[] = { 0xff, 0, 0, 0xff,
+ 0, 0xff, 0, 0xaa,
+ 0, 0, 0xff, 0x55,
+ 0x80, 0x90, 0x70, 0 };
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texture2Data );
+
+ // BEGIN
+
+#if USE_GLEW
+ glewInit();
+#endif
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ // original: glFrustum(-0.6435469817188064, 0.6435469817188064 ,-0.48266022190470925, 0.48266022190470925 ,0.5400000214576721, 2048);
+ //glFrustum(-0.6435469817188064, 0.1435469817188064 ,-0.48266022190470925, 0.88266022190470925 ,0.5400000214576721, 2048);
+ GLfloat pm[] = { 1.372136116027832, 0, 0, 0, 0, 0.7910231351852417, 0, 0, -0.6352481842041016, 0.29297152161598206, -1.0005275011062622, -1, 0, 0, -1.080284833908081, 0 };
+ glLoadMatrixf(pm);
+
+ glMatrixMode(GL_MODELVIEW);
+ GLfloat matrixData[] = { -1, 0, 0, 0,
+ 0, 0,-1, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1 };
+ glLoadMatrixf(matrixData);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ GLuint arrayBuffer, elementBuffer;
+ glGenBuffers(1, &arrayBuffer);
+ glGenBuffers(1, &elementBuffer);
+
+ GLubyte arrayData[] = {
+/*
+[0, 0, 0, 67] ==> 128 float
+[0, 0, 128, 67] ==> 256 float
+[0, 0, 0, 68] ==> 512 float
+[0, 0, 128, 68] ==> 1024 float
+
+[vertex x ] [vertex y ] [vertex z ] [nr] [texture u ] [texture v ] [lm u ] [lm v ] [color r,g,b,a ] */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 0
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 1
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 2
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 3
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 4
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, // 5
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 6
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 7
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 8
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 9
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 10
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 11
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 12
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 0, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 13
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 14
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 128, 67, 0, 0, 0, 0, 128, 128, 128, 128, // 15
+
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 128, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128,
+ 0, 0, 128, 68, 0, 0, 128, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128
+ };
+
+ // Generate a VAO
+ GLuint vao;
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+
+ assert(sizeof(arrayData) == 1408);
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(arrayData), arrayData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ GLushort elementData[] = { 1, 2, 0, 2, 3, 0, 5, 6, 4, 6, 7, 4, 9, 10, 8, 10, 11, 8, 13, 14, 12, 14, 15, 12 };
+ assert(sizeof(elementData) == 48);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), elementData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
+
+ glBindTexture(GL_TEXTURE_2D, texture); // diffuse?
+ glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, texture2); // lightmap?
+ glActiveTexture(GL_TEXTURE0);
+
+ GLint ok;
+
+ const char *vertexShader = "attribute vec4 a_position;\n"
+ "attribute vec4 a_texCoord0;\n"
+ "uniform mat4 u_modelView;\n"
+ "uniform mat4 u_projection;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = (u_projection * u_modelView * a_position) + vec4(200, 0, 0, 0);\n"
+ " v_texCoord0.xy = a_texCoord0.xy/20.0;\n" // added /20 here
+ "}\n";
+ const char *fragmentShader = "uniform sampler2D diffusemap;\n"
+ "varying vec4 v_texCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " vec4 diffuse = texture2D(diffusemap, v_texCoord0.xy);\n"
+ " gl_FragColor = diffuse;\n"
+ "}\n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with vertex\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ printf("Shader compilation error with fragment\n");
+ GLint infoLen = 0;
+ glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char *)malloc(sizeof(char) * infoLen+1);
+ glGetShaderInfoLog(vs, infoLen, NULL, infoLog);
+ printf("Error compiling shader:\n%s\n", infoLog);
+ }
+ }
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+
+ GLint diffusemapLocation = glGetUniformLocation(program, "diffusemap");
+ assert(diffusemapLocation >= 0);
+ glUniform1i(diffusemapLocation, 0);
+
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_MODELVIEW_MATRIX, data);
+ printf("Modelview: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ GLint modelViewLocation = glGetUniformLocation(program, "u_modelView");
+ assert(modelViewLocation >= 0);
+ glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, data);
+ }
+ {
+ GLfloat data[16];
+ glGetFloatv(GL_PROJECTION_MATRIX, data);
+ printf("Projection: ");
+ for (int i = 0; i < 16; i++) printf("%.3f, ", data[i]);
+ printf("\n");
+ GLint projectionLocation = glGetUniformLocation(program, "u_projection");
+ assert(projectionLocation >= 0);
+ glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, data);
+ }
+
+ glBindAttribLocation(program, 0, "a_position");
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, (void*)0);
+ glEnableVertexAttribArray(0);
+
+ glBindAttribLocation(program, 1, "a_texCoord0");
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 32, (void*)16);
+ glEnableVertexAttribArray(1);
+
+ // stop recording in the VAO
+
+ glBindVertexArray(0);
+
+ // unbind all the stuff the VAO would save for us, so this is a valid test
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+
+ // draw with VAO
+
+ glBindVertexArray(vao);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)12);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*) 0);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)24);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)36);
+
+ glBindVertexArray(0);
+
+ glDeleteVertexArrays(1, &vao);
+
+ // END
+
+ SDL_GL_SwapBuffers();
+
+ verify();
+
+#if !EMSCRIPTEN
+ SDL_Delay(1500);
+#endif
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/float_tex.png b/tests/float_tex.png
index 8c3c6502..8fc005ff 100644
--- a/tests/float_tex.png
+++ b/tests/float_tex.png
Binary files differ
diff --git a/tests/fuzz/1.c b/tests/fuzz/1.c
new file mode 100644
index 00000000..2017fb76
--- /dev/null
+++ b/tests/fuzz/1.c
@@ -0,0 +1,117 @@
+/*
+ * This is a RANDOMLY GENERATED PROGRAM.
+ *
+ * Generator: csmith 2.2.0
+ * Git version: a8697aa
+ * Options: --no-volatiles --no-math64 --max-block-depth 2 --max-block-size 2 --max-expr-complexity 2 --max-funcs 2
+ * Seed: 1880513882
+ */
+
+#include "csmith.h"
+
+
+static long __undefined;
+
+/* --- Struct/Union Declarations --- */
+union U0 {
+ int32_t f0;
+ int8_t f1;
+ const int8_t f2;
+};
+
+/* --- GLOBAL VARIABLES --- */
+static uint32_t g_4 = 9UL;
+static int32_t g_6 = 0xB9DD952EL;
+static const int32_t *g_5 = &g_6;
+static union U0 g_7[3][9][6] = {{{{-8L},{5L},{0x901516EAL},{7L},{7L},{0x901516EAL}},{{0x520EA0C8L},{0x520EA0C8L},{0x0920A6FFL},{0x0021FBB9L},{0x888C5540L},{-8L}},{{0xDC87A9B6L},{0x42B48371L},{8L},{7L},{-8L},{0x0920A6FFL}},{{-1L},{0xDC87A9B6L},{8L},{5L},{0x520EA0C8L},{-8L}},{{-3L},{5L},{0x0920A6FFL},{0x865B49D5L},{0xDC87A9B6L},{0x901516EAL}},{{0x865B49D5L},{0xDC87A9B6L},{0x901516EAL},{0x0021FBB9L},{-1L},{-1L}},{{0x865B49D5L},{0x42B48371L},{0x42B48371L},{0x865B49D5L},{-3L},{0x0920A6FFL}},{{-3L},{0x520EA0C8L},{0x0021FBB9L},{5L},{0x865B49D5L},{-1L}},{{-1L},{5L},{0L},{7L},{0x865B49D5L},{0x901516EAL}}},{{{0xDC87A9B6L},{0x520EA0C8L},{7L},{0x0021FBB9L},{-3L},{-8L}},{{0x520EA0C8L},{0x42B48371L},{5L},{7L},{-1L},{0x0920A6FFL}},{{-8L},{0xDC87A9B6L},{5L},{5L},{0xDC87A9B6L},{-8L}},{{0x888C5540L},{5L},{7L},{0x865B49D5L},{0x520EA0C8L},{0x901516EAL}},{{7L},{0xDC87A9B6L},{0L},{0x0021FBB9L},{-8L},{-1L}},{{7L},{0x42B48371L},{0x0021FBB9L},{0x865B49D5L},{0x888C5540L},{0x0920A6FFL}},{{0x888C5540L},{0x520EA0C8L},{0x42B48371L},{5L},{7L},{-1L}},{{-8L},{5L},{0x901516EAL},{7L},{7L},{0x901516EAL}},{{0x520EA0C8L},{0x520EA0C8L},{0x0920A6FFL},{0x0021FBB9L},{0x888C5540L},{-8L}}},{{{0xDC87A9B6L},{0x42B48371L},{8L},{7L},{-8L},{0x0920A6FFL}},{{-1L},{0xDC87A9B6L},{8L},{5L},{0x520EA0C8L},{-8L}},{{-3L},{5L},{0x0920A6FFL},{0x865B49D5L},{0xDC87A9B6L},{0x901516EAL}},{{0x865B49D5L},{0xDC87A9B6L},{0x901516EAL},{0x0021FBB9L},{-1L},{-1L}},{{0x865B49D5L},{0x42B48371L},{0x42B48371L},{0x865B49D5L},{-3L},{0x0920A6FFL}},{{-3L},{0x520EA0C8L},{0x0021FBB9L},{5L},{0x865B49D5L},{-1L}},{{-1L},{5L},{0L},{7L},{0x865B49D5L},{0x901516EAL}},{{0xDC87A9B6L},{0x520EA0C8L},{7L},{0x0021FBB9L},{-3L},{-8L}},{{0x520EA0C8L},{0x42B48371L},{5L},{7L},{-1L},{0x0920A6FFL}}}};
+static int32_t g_31 = 1L;
+static uint32_t g_32 = 4294967289UL;
+
+
+/* --- FORWARD DECLARATIONS --- */
+static uint16_t func_1(void);
+static int32_t * func_9(int32_t * p_10, uint16_t p_11);
+
+
+/* --- FUNCTIONS --- */
+/* ------------------------------------------ */
+/*
+ * reads : g_4 g_5 g_7 g_32
+ * writes: g_5 g_32
+ */
+static uint16_t func_1(void)
+{ /* block id: 0 */
+ int32_t l_3 = (-1L);
+ if (((safe_unary_minus_func_int16_t_s(l_3)) >= g_4))
+ { /* block id: 1 */
+ int32_t *l_8 = &l_3;
+ g_5 = g_5;
+ (*l_8) ^= (g_7[1][3][2] , 0x44688D23L);
+ }
+ else
+ { /* block id: 4 */
+ int32_t *l_12 = &l_3;
+ int32_t **l_13 = &l_12;
+ (*l_13) = func_9(((*l_13) = l_12), l_3);
+ }
+ return l_3;
+}
+
+
+/* ------------------------------------------ */
+/*
+ * reads : g_32
+ * writes: g_32
+ */
+static int32_t * func_9(int32_t * p_10, uint16_t p_11)
+{ /* block id: 6 */
+ int32_t *l_14 = &g_6;
+ int32_t *l_15 = &g_7[1][3][2].f0;
+ int32_t *l_16 = &g_6;
+ int32_t *l_17 = &g_6;
+ int32_t *l_18 = &g_6;
+ int32_t *l_19 = &g_6;
+ int32_t *l_20 = &g_6;
+ int32_t *l_21 = &g_6;
+ int32_t *l_22 = &g_6;
+ int32_t *l_23 = &g_7[1][3][2].f0;
+ int32_t l_24[8] = {0xF9F11119L,0xF9F11119L,0xF9F11119L,0xF9F11119L,0xF9F11119L,0xF9F11119L,0xF9F11119L,0xF9F11119L};
+ int32_t *l_25 = &l_24[7];
+ int32_t *l_26 = &l_24[2];
+ int32_t *l_27 = &l_24[2];
+ int32_t *l_28 = &l_24[0];
+ int32_t *l_29 = &g_7[1][3][2].f0;
+ int32_t *l_30[10] = {(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0};
+ int i;
+ ++g_32;
+ return p_10;
+}
+
+
+
+
+/* ---------------------------------------- */
+int main (int argc, char* argv[])
+{
+ int i, j, k;
+ int print_hash_value = 0;
+ if (argc == 2 && strcmp(argv[1], "1") == 0) print_hash_value = 1;
+ platform_main_begin();
+ crc32_gentab();
+ func_1();
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 1; j++)
+ {
+ for (k = 0; k < 1; k++)
+ {
+ transparent_crc(g_7[i][j][k].f0, "g_7[i][j][k].f0", print_hash_value);
+ transparent_crc(g_7[i][j][k].f1, "g_7[i][j][k].f1", print_hash_value);
+ if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k);
+ }
+ }
+ }
+ platform_main_end(crc32_context ^ 0xFFFFFFFFUL, print_hash_value);
+ return 0;
+}
+
diff --git a/tests/fuzz/1.c.txt b/tests/fuzz/1.c.txt
new file mode 100644
index 00000000..701369f3
--- /dev/null
+++ b/tests/fuzz/1.c.txt
@@ -0,0 +1 @@
+checksum = 504CCDC
diff --git a/tests/fuzz/creduce_tester.py b/tests/fuzz/creduce_tester.py
new file mode 100755
index 00000000..c3460e9d
--- /dev/null
+++ b/tests/fuzz/creduce_tester.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+
+'''
+Runs csmith, a C fuzzer, and looks for bugs
+'''
+
+import os, sys, difflib
+from subprocess import Popen, PIPE, STDOUT
+
+sys.path += [os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'tools')]
+import shared
+
+filename = sys.argv[1]
+print 'testing file', filename
+
+print '2) Compile natively'
+shared.try_delete(filename)
+shared.execute([shared.CLANG_CC, '-O2', filename + '.c', '-o', filename] + CSMITH_CFLAGS, stderr=PIPE)
+assert os.path.exists(filename)
+print '3) Run natively'
+try:
+ correct = shared.timeout_run(Popen([filename], stdout=PIPE, stderr=PIPE), 3)
+except Exception, e:
+ print 'Failed or infinite looping in native, skipping', e
+ notes['invalid'] += 1
+ os.exit(0) # boring
+
+print '4) Compile JS-ly and compare'
+
+def try_js(args):
+ shared.try_delete(filename + '.js')
+ shared.execute([shared.EMCC, '-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1', '-s', 'PRECISE_I32_MUL=1', filename + '.c', '-o', filename + '.js'] + CSMITH_CFLAGS + args, stderr=PIPE)
+ assert os.path.exists(filename + '.js')
+ js = shared.run_js(filename + '.js', stderr=PIPE, engine=engine1)
+ assert correct == js, ''.join([a.rstrip()+'\n' for a in difflib.unified_diff(correct.split('\n'), js.split('\n'), fromfile='expected', tofile='actual')])
+
+# Try normally, then try unaligned because csmith does generate nonportable code that requires x86 alignment
+ok = False
+normal = True
+for args, note in [([], None), (['-s', 'UNALIGNED_MEMORY=1'], 'unaligned')]:
+ try:
+ try_js(args)
+ ok = True
+ if note:
+ notes[note] += 1
+ break
+ except Exception, e:
+ print e
+ normal = False
+if not ok: sys.exit(1)
+
+sys.exit(0) # boring
+
diff --git a/tests/fuzz/csmith.h b/tests/fuzz/csmith.h
new file mode 100644
index 00000000..f1334a37
--- /dev/null
+++ b/tests/fuzz/csmith.h
@@ -0,0 +1,130 @@
+/* -*- mode: C -*-
+ *
+ * Copyright (c) 2007-2010 The University of Utah
+ * All rights reserved.
+ *
+ * This file is part of `csmith', a random generator of C programs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RANDOM_RUNTIME_H
+#define RANDOM_RUNTIME_H
+
+#ifdef CSMITH_MINIMAL
+#include "csmith_minimal.h"
+#else
+
+/*****************************************************************************/
+
+#include <string.h>
+
+#define __STDC_LIMIT_MACROS
+#include "random_inc.h"
+
+static uint32_t crc32_tab[256];
+static uint32_t crc32_context = 0xFFFFFFFFUL;
+
+static void
+crc32_gentab (void)
+{
+ uint32_t crc;
+ const uint32_t poly = 0xEDB88320UL;
+ int i, j;
+
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ poly;
+ } else {
+ crc >>= 1;
+ }
+ }
+ crc32_tab[i] = crc;
+ }
+}
+
+static void
+crc32_byte (uint8_t b) {
+ crc32_context =
+ ((crc32_context >> 8) & 0x00FFFFFF) ^
+ crc32_tab[(crc32_context ^ b) & 0xFF];
+}
+
+#if defined(__SPLAT__) || defined (__COMPCERT__) || defined(NO_LONGLONG)
+static void
+crc32_8bytes (uint32_t val)
+{
+ crc32_byte ((val>>0) & 0xff);
+ crc32_byte ((val>>8) & 0xff);
+ crc32_byte ((val>>16) & 0xff);
+ crc32_byte ((val>>24) & 0xff);
+}
+
+static void
+transparent_crc (uint32_t val, char* vname, int flag)
+{
+ crc32_8bytes(val);
+ if (flag) {
+ printf("...checksum after hashing %s : %X\n", vname, crc32_context ^ 0xFFFFFFFFU);
+ }
+}
+#else
+static void
+crc32_8bytes (uint64_t val)
+{
+ crc32_byte ((val>>0) & 0xff);
+ crc32_byte ((val>>8) & 0xff);
+ crc32_byte ((val>>16) & 0xff);
+ crc32_byte ((val>>24) & 0xff);
+ crc32_byte ((val>>32) & 0xff);
+ crc32_byte ((val>>40) & 0xff);
+ crc32_byte ((val>>48) & 0xff);
+ crc32_byte ((val>>56) & 0xff);
+}
+
+static void
+transparent_crc (uint64_t val, char* vname, int flag)
+{
+ crc32_8bytes(val);
+ if (flag) {
+ printf("...checksum after hashing %s : %lX\n", vname, crc32_context ^ 0xFFFFFFFFUL);
+ }
+}
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+#endif /* RANDOM_RUNTIME_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
+/* End of file. */
diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py
new file mode 100755
index 00000000..1cb85451
--- /dev/null
+++ b/tests/fuzz/csmith_driver.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+
+'''
+Runs csmith, a C fuzzer, and looks for bugs
+'''
+
+import os, sys, difflib
+from subprocess import Popen, PIPE, STDOUT
+
+sys.path += [os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'tools')]
+import shared
+
+engine1 = eval('shared.' + sys.argv[1]) if len(sys.argv) > 1 else shared.JS_ENGINES[0]
+engine2 = eval('shared.' + sys.argv[2]) if len(sys.argv) > 2 else None
+
+print 'testing js engines', engine1, engine2
+
+CSMITH = os.path.expanduser('~/Dev/csmith/src/csmith')
+CSMITH_CFLAGS = ['-I' + os.path.expanduser('~/Dev/csmith/runtime/')]
+
+filename = os.path.join(shared.CANONICAL_TEMP_DIR, 'fuzzcode')
+
+shared.DEFAULT_TIMEOUT = 1
+
+tried = 0
+
+notes = { 'invalid': 0, 'unaligned': 0, 'embug': 0 }
+
+while 1:
+ print 'Tried %d, notes: %s' % (tried, notes)
+ tried += 1
+ print '1) Generate C'
+ shared.execute([CSMITH, '--no-volatiles', '--no-math64'], stdout=open(filename + '.c', 'w'))
+
+ print '2) Compile natively'
+ shared.try_delete(filename)
+ shared.execute([shared.CLANG_CC, '-O2', filename + '.c', '-o', filename] + CSMITH_CFLAGS, stderr=PIPE)
+ assert os.path.exists(filename)
+ print '3) Run natively'
+ try:
+ correct = shared.timeout_run(Popen([filename], stdout=PIPE, stderr=PIPE), 3)
+ except Exception, e:
+ print 'Failed or infinite looping in native, skipping', e
+ notes['invalid'] += 1
+ continue
+
+ print '4) Compile JS-ly and compare'
+
+ def try_js(args):
+ shared.try_delete(filename + '.js')
+ shared.execute([shared.EMCC, '-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1', '-s', 'PRECISE_I32_MUL=1', filename + '.c', '-o', filename + '.js'] + CSMITH_CFLAGS + args, stderr=PIPE)
+ assert os.path.exists(filename + '.js')
+ js = shared.run_js(filename + '.js', stderr=PIPE, engine=engine1, check_timeout=True)
+ assert correct == js, ''.join([a.rstrip()+'\n' for a in difflib.unified_diff(correct.split('\n'), js.split('\n'), fromfile='expected', tofile='actual')])
+
+ # Try normally, then try unaligned because csmith does generate nonportable code that requires x86 alignment
+ ok = False
+ normal = True
+ for args, note in [([], None), (['-s', 'UNALIGNED_MEMORY=1'], 'unaligned')]:
+ try:
+ try_js(args)
+ ok = True
+ if note:
+ notes[note] += 1
+ break
+ except Exception, e:
+ print e
+ normal = False
+ if not ok:
+ print "EMSCRIPTEN BUG"
+ notes['embug'] += 1
+ continue #break
+ #if not ok:
+ # try: # finally, try with safe heap. if that is triggered, this is nonportable code almost certainly
+ # try_js(['-s', 'SAFE_HEAP=1'])
+ # except Exception, e:
+ # print e
+ # js = shared.run_js(filename + '.js', stderr=PIPE, full_output=True)
+ # print js
+ # if 'SAFE_HEAP' in js:
+ # notes['safeheap'] += 1
+ # else:
+ # break
+
+ # This is ok. Try in secondary JS engine too
+ if engine2 and normal:
+ try:
+ js2 = shared.run_js(filename + '.js', stderr=PIPE, engine=engine2, full_output=True, check_timeout=True)
+ except:
+ print 'failed to run in secondary', js2
+ break
+
+ # asm.js testing
+ assert 'warning: Successfully compiled asm.js code' in js2, 'must validate'
+ js2 = js2.replace('\nwarning: Successfully compiled asm.js code\n', '')
+
+ assert js2 == correct, ''.join([a.rstrip()+'\n' for a in difflib.unified_diff(correct.split('\n'), js2.split('\n'), fromfile='expected', tofile='actual')]) + 'ODIN FAIL'
+ print 'odin ok'
+
+
diff --git a/tests/fuzz/platform_generic.h b/tests/fuzz/platform_generic.h
new file mode 100644
index 00000000..b2ef33a3
--- /dev/null
+++ b/tests/fuzz/platform_generic.h
@@ -0,0 +1,132 @@
+/* -*- mode: C -*-
+ *
+ *
+ * Copyright (c) 2007, 2008 The University of Utah
+ * All rights reserved.
+ *
+ * This file is part of `csmith', a random generator of C programs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PLATFORM_GENERIC_H
+#define PLATFORM_GENERIC_H
+
+/*****************************************************************************/
+
+#ifdef STANDALONE
+extern int printf (const char *, ...);
+#else
+#include <stdio.h>
+#endif
+
+static void
+platform_main_begin(void)
+{
+ /* Nothing to do. */
+}
+
+static void
+platform_main_end(uint32_t crc, int flag)
+{
+#if defined (__FRAMAC)
+ Frama_C_dump_assert_each();
+#endif
+ printf ("checksum = %X\n", crc);
+#if defined (LOG_WRAPPERS)
+ {
+ int i, first;
+
+ printf ("executed wrappers: ");
+ first = 1;
+ for (i=1; i<N_WRAP+1; i++) {
+ if (__executed_checks[i]) {
+ if (!first) {
+ printf (",");
+ } else {
+ first = 0;
+ }
+ printf ("%d", i);
+ }
+ }
+ printf ("\n");
+
+ printf ("dead wrappers: ");
+ first = 1;
+ for (i=1; i<N_WRAP+1; i++) {
+ if (!__executed_checks[i]) {
+ if (!first) {
+ printf (",");
+ } else {
+ first = 0;
+ }
+ printf ("%d", i);
+ }
+ }
+ printf ("\n");
+
+ printf ("wrappers that failed at least once: ");
+ first = 1;
+ for (i=1; i<N_WRAP+1; i++) {
+ if (__failed_checks[i]) {
+ if (!first) {
+ printf (",");
+ } else {
+ first = 0;
+ }
+ printf ("%d", i);
+ }
+ }
+ printf ("\n");
+
+ printf ("wrappers that never failed (or never executed): ");
+ first = 1;
+ for (i=1; i<N_WRAP+1; i++) {
+ if (!__failed_checks[i]) {
+ if (!first) {
+ printf (",");
+ } else {
+ first = 0;
+ }
+ printf ("%d", i);
+ }
+ }
+ printf ("\n");
+ }
+#endif
+}
+
+#define MB (1<<20)
+
+/*****************************************************************************/
+
+#endif /* PLATFORM_GENERIC_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
+/* End of file. */
diff --git a/tests/fuzz/random_inc.h b/tests/fuzz/random_inc.h
new file mode 100644
index 00000000..7559cbd7
--- /dev/null
+++ b/tests/fuzz/random_inc.h
@@ -0,0 +1,129 @@
+/* -*- mode: C -*-
+ *
+ * Copyright (c) 2007-2010 The University of Utah
+ * All rights reserved.
+ *
+ * This file is part of `csmith', a random generator of C programs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RANDOM_INC_H
+#define RANDOM_INC_H
+
+
+#if defined(STANDALONE)
+ #if defined(_MSC_VER)
+ #include <limits.h>
+ #include "windows/stdint.h"
+ #elif defined (IA32_ARCH)
+ #include "stdint_ia32.h"
+ #elif defined (IA64_ARCH)
+ #include "stdint_ia64.h"
+ #elif defined (MSP430)
+ #include "stdint_msp430.h"
+ #elif defined (AVR_ARCH)
+ #include "stdint_avr.h"
+ #else
+ #include "stdint_ia32.h"
+ #endif
+#else
+ #include <limits.h>
+ #if defined(_MSC_VER)
+ #include "windows/stdint.h"
+ #else
+ #include <stdint.h>
+ #endif
+#endif
+
+#include <assert.h>
+
+/*****************************************************************************/
+
+#ifndef DEPUTY
+#define COUNT(n)
+#define TC
+#define SAFE
+#endif
+
+/*****************************************************************************/
+
+#ifdef LOG_WRAPPERS
+#include "wrapper.h"
+char __failed_checks[N_WRAP+1];
+char __executed_checks[N_WRAP+1];
+#define UNDEFINED(__val) (__failed_checks[index]=1,(__val))
+#define LOG_INDEX , int index
+#define LOG_EXEC __executed_checks[index]=1;
+#else
+#define UNDEFINED(__val) (__val)
+#define LOG_INDEX
+#define LOG_EXEC
+#endif
+
+#if defined(AVR_ARCH)
+#include "platform_avr.h"
+#elif defined (MSP430)
+#include "platform_msp430.h"
+#else
+#include "platform_generic.h"
+#endif
+
+#define STATIC static
+
+#if defined (USE_MATH_MACROS_NOTMP)
+#include "safe_math_macros_notmp.h"
+#elif defined (USE_MATH_MACROS)
+#include "safe_math_macros.h"
+#else
+#define FUNC_NAME(x) (safe_##x)
+#include "safe_math.h"
+#undef FUNC_NAME
+#endif
+
+#define INT_BIT (sizeof(int)*CHAR_BIT)
+#define _CSMITH_BITFIELD(x) (((x)>INT_BIT)?((x)%INT_BIT):(x))
+
+#ifdef TCC
+
+void* memcpy(void* dest, const void* src, size_t count) {
+ char* dst8 = (char*)dest;
+ char* src8 = (char*)src;
+
+ while (count--) {
+ *dst8++ = *src8++;
+ }
+ return dest;
+}
+
+void *memset(void *s, int c, size_t n)
+{
+ unsigned char* p=s;
+ while(n--)
+ *p++ = (unsigned char)c;
+ return s;
+}
+
+#endif
+
+#endif // RANDOM_INC_H
diff --git a/tests/fuzz/safe_math.h b/tests/fuzz/safe_math.h
new file mode 100644
index 00000000..393ebba1
--- /dev/null
+++ b/tests/fuzz/safe_math.h
@@ -0,0 +1,947 @@
+
+#ifndef SAFE_MATH_H
+#define SAFE_MATH_H
+
+
+
+
+
+
+
+
+
+STATIC int8_t
+FUNC_NAME(unary_minus_func_int8_t_s)(int8_t si LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT8_MAX>=INT_MAX)
+ (si==INT8_MIN) ?
+ (UNDEFINED(si)) :
+#endif
+#endif
+ -si;
+}
+
+STATIC int8_t
+FUNC_NAME(add_func_int8_t_s_s)(int8_t si1, int8_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT8_MAX>=INT_MAX)
+ (((si1>0) && (si2>0) && (si1 > (INT8_MAX-si2))) || ((si1<0) && (si2<0) && (si1 < (INT8_MIN-si2)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 + si2);
+}
+
+STATIC int8_t
+FUNC_NAME(sub_func_int8_t_s_s)(int8_t si1, int8_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT8_MAX>=INT_MAX)
+ (((si1^si2) & (((si1 ^ ((si1^si2) & (~INT8_MAX)))-si2)^si2)) < 0) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 - si2);
+}
+
+STATIC int8_t
+FUNC_NAME(mul_func_int8_t_s_s)(int8_t si1, int8_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT8_MAX>=INT_MAX)
+ (((si1 > 0) && (si2 > 0) && (si1 > (INT8_MAX / si2))) || ((si1 > 0) && (si2 <= 0) && (si2 < (INT8_MIN / si1))) || ((si1 <= 0) && (si2 > 0) && (si1 < (INT8_MIN / si2))) || ((si1 <= 0) && (si2 <= 0) && (si1 != 0) && (si2 < (INT8_MAX / si1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ si1 * si2;
+}
+
+STATIC int8_t
+FUNC_NAME(mod_func_int8_t_s_s)(int8_t si1, int8_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT8_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 % si2);
+}
+
+STATIC int8_t
+FUNC_NAME(div_func_int8_t_s_s)(int8_t si1, int8_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT8_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 / si2);
+}
+
+STATIC int8_t
+FUNC_NAME(lshift_func_int8_t_s_s)(int8_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32) || (left > (INT8_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC int8_t
+FUNC_NAME(lshift_func_int8_t_s_u)(int8_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32) || (left > (INT8_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC int8_t
+FUNC_NAME(rshift_func_int8_t_s_s)(int8_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32))?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC int8_t
+FUNC_NAME(rshift_func_int8_t_s_u)(int8_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+
+
+STATIC int16_t
+FUNC_NAME(unary_minus_func_int16_t_s)(int16_t si LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT16_MAX>=INT_MAX)
+ (si==INT16_MIN) ?
+ (UNDEFINED(si)) :
+#endif
+#endif
+ -si;
+}
+
+STATIC int16_t
+FUNC_NAME(add_func_int16_t_s_s)(int16_t si1, int16_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT16_MAX>=INT_MAX)
+ (((si1>0) && (si2>0) && (si1 > (INT16_MAX-si2))) || ((si1<0) && (si2<0) && (si1 < (INT16_MIN-si2)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 + si2);
+}
+
+STATIC int16_t
+FUNC_NAME(sub_func_int16_t_s_s)(int16_t si1, int16_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT16_MAX>=INT_MAX)
+ (((si1^si2) & (((si1 ^ ((si1^si2) & (~INT16_MAX)))-si2)^si2)) < 0) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 - si2);
+}
+
+STATIC int16_t
+FUNC_NAME(mul_func_int16_t_s_s)(int16_t si1, int16_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT16_MAX>=INT_MAX)
+ (((si1 > 0) && (si2 > 0) && (si1 > (INT16_MAX / si2))) || ((si1 > 0) && (si2 <= 0) && (si2 < (INT16_MIN / si1))) || ((si1 <= 0) && (si2 > 0) && (si1 < (INT16_MIN / si2))) || ((si1 <= 0) && (si2 <= 0) && (si1 != 0) && (si2 < (INT16_MAX / si1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ si1 * si2;
+}
+
+STATIC int16_t
+FUNC_NAME(mod_func_int16_t_s_s)(int16_t si1, int16_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT16_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 % si2);
+}
+
+STATIC int16_t
+FUNC_NAME(div_func_int16_t_s_s)(int16_t si1, int16_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT16_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 / si2);
+}
+
+STATIC int16_t
+FUNC_NAME(lshift_func_int16_t_s_s)(int16_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32) || (left > (INT16_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC int16_t
+FUNC_NAME(lshift_func_int16_t_s_u)(int16_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32) || (left > (INT16_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC int16_t
+FUNC_NAME(rshift_func_int16_t_s_s)(int16_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32))?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC int16_t
+FUNC_NAME(rshift_func_int16_t_s_u)(int16_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+
+
+STATIC int32_t
+FUNC_NAME(unary_minus_func_int32_t_s)(int32_t si LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT32_MAX>=INT_MAX)
+ (si==INT32_MIN) ?
+ (UNDEFINED(si)) :
+#endif
+#endif
+ -si;
+}
+
+STATIC int32_t
+FUNC_NAME(add_func_int32_t_s_s)(int32_t si1, int32_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT32_MAX>=INT_MAX)
+ (((si1>0) && (si2>0) && (si1 > (INT32_MAX-si2))) || ((si1<0) && (si2<0) && (si1 < (INT32_MIN-si2)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 + si2);
+}
+
+STATIC int32_t
+FUNC_NAME(sub_func_int32_t_s_s)(int32_t si1, int32_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT32_MAX>=INT_MAX)
+ (((si1^si2) & (((si1 ^ ((si1^si2) & (~INT32_MAX)))-si2)^si2)) < 0) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 - si2);
+}
+
+STATIC int32_t
+FUNC_NAME(mul_func_int32_t_s_s)(int32_t si1, int32_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT32_MAX>=INT_MAX)
+ (((si1 > 0) && (si2 > 0) && (si1 > (INT32_MAX / si2))) || ((si1 > 0) && (si2 <= 0) && (si2 < (INT32_MIN / si1))) || ((si1 <= 0) && (si2 > 0) && (si1 < (INT32_MIN / si2))) || ((si1 <= 0) && (si2 <= 0) && (si1 != 0) && (si2 < (INT32_MAX / si1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ si1 * si2;
+}
+
+STATIC int32_t
+FUNC_NAME(mod_func_int32_t_s_s)(int32_t si1, int32_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT32_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 % si2);
+}
+
+STATIC int32_t
+FUNC_NAME(div_func_int32_t_s_s)(int32_t si1, int32_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT32_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 / si2);
+}
+
+STATIC int32_t
+FUNC_NAME(lshift_func_int32_t_s_s)(int32_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32) || (left > (INT32_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC int32_t
+FUNC_NAME(lshift_func_int32_t_s_u)(int32_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32) || (left > (INT32_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC int32_t
+FUNC_NAME(rshift_func_int32_t_s_s)(int32_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32))?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC int32_t
+FUNC_NAME(rshift_func_int32_t_s_u)(int32_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+#ifndef NO_LONGLONG
+
+
+STATIC int64_t
+FUNC_NAME(unary_minus_func_int64_t_s)(int64_t si LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT64_MAX>=INT_MAX)
+ (si==INT64_MIN) ?
+ (UNDEFINED(si)) :
+#endif
+#endif
+ -si;
+}
+
+STATIC int64_t
+FUNC_NAME(add_func_int64_t_s_s)(int64_t si1, int64_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT64_MAX>=INT_MAX)
+ (((si1>0) && (si2>0) && (si1 > (INT64_MAX-si2))) || ((si1<0) && (si2<0) && (si1 < (INT64_MIN-si2)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 + si2);
+}
+
+STATIC int64_t
+FUNC_NAME(sub_func_int64_t_s_s)(int64_t si1, int64_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT64_MAX>=INT_MAX)
+ (((si1^si2) & (((si1 ^ ((si1^si2) & (~INT64_MAX)))-si2)^si2)) < 0) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ (si1 - si2);
+}
+
+STATIC int64_t
+FUNC_NAME(mul_func_int64_t_s_s)(int64_t si1, int64_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+#if (INT64_MAX>=INT_MAX)
+ (((si1 > 0) && (si2 > 0) && (si1 > (INT64_MAX / si2))) || ((si1 > 0) && (si2 <= 0) && (si2 < (INT64_MIN / si1))) || ((si1 <= 0) && (si2 > 0) && (si1 < (INT64_MIN / si2))) || ((si1 <= 0) && (si2 <= 0) && (si1 != 0) && (si2 < (INT64_MAX / si1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+#endif
+ si1 * si2;
+}
+
+STATIC int64_t
+FUNC_NAME(mod_func_int64_t_s_s)(int64_t si1, int64_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT64_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 % si2);
+}
+
+STATIC int64_t
+FUNC_NAME(div_func_int64_t_s_s)(int64_t si1, int64_t si2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((si2 == 0) || ((si1 == INT64_MIN) && (si2 == (-1)))) ?
+ (UNDEFINED(si1)) :
+#endif
+ (si1 / si2);
+}
+
+STATIC int64_t
+FUNC_NAME(lshift_func_int64_t_s_s)(int64_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32) || (left > (INT64_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC int64_t
+FUNC_NAME(lshift_func_int64_t_s_u)(int64_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32) || (left > (INT64_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC int64_t
+FUNC_NAME(rshift_func_int64_t_s_s)(int64_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((int)right) < 0) || (((int)right) >= 32))?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC int64_t
+FUNC_NAME(rshift_func_int64_t_s_u)(int64_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((left < 0) || (((unsigned int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+#endif
+
+
+
+
+
+STATIC uint8_t
+FUNC_NAME(unary_minus_func_uint8_t_u)(uint8_t ui LOG_INDEX)
+{
+ LOG_EXEC
+ return -ui;
+}
+
+STATIC uint8_t
+FUNC_NAME(add_func_uint8_t_u_u)(uint8_t ui1, uint8_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 + ui2;
+}
+
+STATIC uint8_t
+FUNC_NAME(sub_func_uint8_t_u_u)(uint8_t ui1, uint8_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 - ui2;
+}
+
+STATIC uint8_t
+FUNC_NAME(mul_func_uint8_t_u_u)(uint8_t ui1, uint8_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ((unsigned int)ui1) * ((unsigned int)ui2);
+}
+
+STATIC uint8_t
+FUNC_NAME(mod_func_uint8_t_u_u)(uint8_t ui1, uint8_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 % ui2);
+}
+
+STATIC uint8_t
+FUNC_NAME(div_func_uint8_t_u_u)(uint8_t ui1, uint8_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 / ui2);
+}
+
+STATIC uint8_t
+FUNC_NAME(lshift_func_uint8_t_u_s)(uint8_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32) || (left > (UINT8_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC uint8_t
+FUNC_NAME(lshift_func_uint8_t_u_u)(uint8_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((unsigned int)right) >= 32) || (left > (UINT8_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC uint8_t
+FUNC_NAME(rshift_func_uint8_t_u_s)(uint8_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC uint8_t
+FUNC_NAME(rshift_func_uint8_t_u_u)(uint8_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (((unsigned int)right) >= 32) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+
+
+STATIC uint16_t
+FUNC_NAME(unary_minus_func_uint16_t_u)(uint16_t ui LOG_INDEX)
+{
+ LOG_EXEC
+ return -ui;
+}
+
+STATIC uint16_t
+FUNC_NAME(add_func_uint16_t_u_u)(uint16_t ui1, uint16_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 + ui2;
+}
+
+STATIC uint16_t
+FUNC_NAME(sub_func_uint16_t_u_u)(uint16_t ui1, uint16_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 - ui2;
+}
+
+STATIC uint16_t
+FUNC_NAME(mul_func_uint16_t_u_u)(uint16_t ui1, uint16_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ((unsigned int)ui1) * ((unsigned int)ui2);
+}
+
+STATIC uint16_t
+FUNC_NAME(mod_func_uint16_t_u_u)(uint16_t ui1, uint16_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 % ui2);
+}
+
+STATIC uint16_t
+FUNC_NAME(div_func_uint16_t_u_u)(uint16_t ui1, uint16_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 / ui2);
+}
+
+STATIC uint16_t
+FUNC_NAME(lshift_func_uint16_t_u_s)(uint16_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32) || (left > (UINT16_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC uint16_t
+FUNC_NAME(lshift_func_uint16_t_u_u)(uint16_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((unsigned int)right) >= 32) || (left > (UINT16_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC uint16_t
+FUNC_NAME(rshift_func_uint16_t_u_s)(uint16_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC uint16_t
+FUNC_NAME(rshift_func_uint16_t_u_u)(uint16_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (((unsigned int)right) >= 32) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+
+
+STATIC uint32_t
+FUNC_NAME(unary_minus_func_uint32_t_u)(uint32_t ui LOG_INDEX)
+{
+ LOG_EXEC
+ return -ui;
+}
+
+STATIC uint32_t
+FUNC_NAME(add_func_uint32_t_u_u)(uint32_t ui1, uint32_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 + ui2;
+}
+
+STATIC uint32_t
+FUNC_NAME(sub_func_uint32_t_u_u)(uint32_t ui1, uint32_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 - ui2;
+}
+
+STATIC uint32_t
+FUNC_NAME(mul_func_uint32_t_u_u)(uint32_t ui1, uint32_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ((unsigned int)ui1) * ((unsigned int)ui2);
+}
+
+STATIC uint32_t
+FUNC_NAME(mod_func_uint32_t_u_u)(uint32_t ui1, uint32_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 % ui2);
+}
+
+STATIC uint32_t
+FUNC_NAME(div_func_uint32_t_u_u)(uint32_t ui1, uint32_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 / ui2);
+}
+
+STATIC uint32_t
+FUNC_NAME(lshift_func_uint32_t_u_s)(uint32_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32) || (left > (UINT32_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC uint32_t
+FUNC_NAME(lshift_func_uint32_t_u_u)(uint32_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((unsigned int)right) >= 32) || (left > (UINT32_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC uint32_t
+FUNC_NAME(rshift_func_uint32_t_u_s)(uint32_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC uint32_t
+FUNC_NAME(rshift_func_uint32_t_u_u)(uint32_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (((unsigned int)right) >= 32) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+#ifndef NO_LONGLONG
+
+
+STATIC uint64_t
+FUNC_NAME(unary_minus_func_uint64_t_u)(uint64_t ui LOG_INDEX)
+{
+ LOG_EXEC
+ return -ui;
+}
+
+STATIC uint64_t
+FUNC_NAME(add_func_uint64_t_u_u)(uint64_t ui1, uint64_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 + ui2;
+}
+
+STATIC uint64_t
+FUNC_NAME(sub_func_uint64_t_u_u)(uint64_t ui1, uint64_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ui1 - ui2;
+}
+
+STATIC uint64_t
+FUNC_NAME(mul_func_uint64_t_u_u)(uint64_t ui1, uint64_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return ((unsigned long long int)ui1) * ((unsigned long long int)ui2);
+}
+
+STATIC uint64_t
+FUNC_NAME(mod_func_uint64_t_u_u)(uint64_t ui1, uint64_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 % ui2);
+}
+
+STATIC uint64_t
+FUNC_NAME(div_func_uint64_t_u_u)(uint64_t ui1, uint64_t ui2 LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (ui2 == 0) ?
+ (UNDEFINED(ui1)) :
+#endif
+ (ui1 / ui2);
+}
+
+STATIC uint64_t
+FUNC_NAME(lshift_func_uint64_t_u_s)(uint64_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32) || (left > (UINT64_MAX >> ((int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((int)right));
+}
+
+STATIC uint64_t
+FUNC_NAME(lshift_func_uint64_t_u_u)(uint64_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((unsigned int)right) >= 32) || (left > (UINT64_MAX >> ((unsigned int)right)))) ?
+ (UNDEFINED(left)) :
+#endif
+ (left << ((unsigned int)right));
+}
+
+STATIC uint64_t
+FUNC_NAME(rshift_func_uint64_t_u_s)(uint64_t left, int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ ((((int)right) < 0) || (((int)right) >= 32)) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((int)right));
+}
+
+STATIC uint64_t
+FUNC_NAME(rshift_func_uint64_t_u_u)(uint64_t left, unsigned int right LOG_INDEX)
+{
+ LOG_EXEC
+ return
+#ifndef UNSAFE
+ (((unsigned int)right) >= 32) ?
+ (UNDEFINED(left)) :
+#endif
+ (left >> ((unsigned int)right));
+}
+
+#endif
+
+#endif
diff --git a/tests/gears.png b/tests/gears.png
index ffb855c4..a35db625 100644
--- a/tests/gears.png
+++ b/tests/gears.png
Binary files differ
diff --git a/tests/gl_ps.c b/tests/gl_ps.c
index 81579c1d..6ea0e3db 100644
--- a/tests/gl_ps.c
+++ b/tests/gl_ps.c
@@ -78,6 +78,9 @@ void shaders() {
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &ok);
assert(ok);
+ assert(glIsProgram(program));
+ assert(!glIsProgram(0));
+ assert(!glIsProgram(program+1)); // a number that can't be a real shader
glUseProgram(program);
diff --git a/tests/gl_ps.png b/tests/gl_ps.png
index 185f7166..ac13ec0b 100644
--- a/tests/gl_ps.png
+++ b/tests/gl_ps.png
Binary files differ
diff --git a/tests/gl_ps_packed.c b/tests/gl_ps_packed.c
new file mode 100644
index 00000000..9ab99cb8
--- /dev/null
+++ b/tests/gl_ps_packed.c
@@ -0,0 +1,230 @@
+/*******************************************************************
+ * *
+ * Using SDL With OpenGL *
+ * *
+ * Tutorial by Kyle Foley (sdw) *
+ * *
+ * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
+ * *
+ *******************************************************************/
+
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_image.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void shaders() {
+#if USE_GLEW
+ glewInit();
+#endif
+
+ GLint ok;
+
+ const char *vertexShader = "void main(void) \n"
+ "{ \n"
+ " gl_Position = ftransform(); \n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "} \n";
+ const char *fragmentShader = "uniform sampler2D tex0; \n"
+ "void main(void) \n"
+ "{ \n"
+ " gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy); \n"
+ "} \n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ // Slightly different SDL initialization
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
+
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ // Set the OpenGL state after creating the context with SDL_SetVideoMode
+
+ glClearColor( 0, 0, 0, 0 );
+
+#if !EMSCRIPTEN
+ glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL
+#endif
+
+ glViewport( 0, 0, 640, 480 );
+
+ glMatrixMode( GL_PROJECTION );
+ GLfloat matrixData[] = { 2.0/640, 0, 0, 0,
+ 0, -2.0/480, 0, 0,
+ 0, 0, -1, 0,
+ -1, 1, 0, 1 };
+ glLoadMatrixf(matrixData); // test loadmatrix
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ // Load the OpenGL texture
+
+ GLuint texture; // Texture object handle
+ SDL_Surface *surface; // Gives us the information to make the texture
+
+ if ( (surface = IMG_Load("screenshot.png")) ) {
+
+ // Check that the image's width is a power of 2
+ if ( (surface->w & (surface->w - 1)) != 0 ) {
+ printf("warning: image.bmp's width is not a power of 2\n");
+ }
+
+ // Also check if the height is a power of 2
+ if ( (surface->h & (surface->h - 1)) != 0 ) {
+ printf("warning: image.bmp's height is not a power of 2\n");
+ }
+
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures( 1, &texture );
+
+ // Bind the texture object
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Set the texture's stretching properties
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ //SDL_LockSurface(surface);
+
+ // Add some greyness
+ memset(surface->pixels, 0x66, surface->w*surface->h);
+
+ // Edit the texture object's image data using the information SDL_Surface gives us
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
+
+ //SDL_UnlockSurface(surface);
+ }
+ else {
+ printf("SDL could not load image.bmp: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ // Free the SDL_Surface only if it was successfully created
+ if ( surface ) {
+ SDL_FreeSurface( surface );
+ }
+
+ // Clear the screen before drawing
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ shaders();
+
+ // Bind the texture to which subsequent calls refer to
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Use clientside vertex pointers to render two items. In this test we have each
+ // attribute in a separate buffer, packed (i.e. stride == 0)
+ GLfloat vertexData[] = { 10, 10,
+ 300, 10,
+ 300, 128,
+ 10, 128,
+ 410, 10,
+ 600, 10,
+ 630, 200,
+ 310, 250,
+ 100, 300,
+ 300, 300,
+ 300, 400,
+ 100, 400 };
+ GLfloat textureData[] = { 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0.5,
+ 1, 0.5,
+ 1, 1,
+ 0.5, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1, };
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, textureData);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertexData);
+
+ glDrawArrays(GL_QUADS, 0, 12);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ SDL_GL_SwapBuffers();
+
+#if !EMSCRIPTEN
+ // Wait for 3 seconds to give us a chance to see the image
+ SDL_Delay(3000);
+#endif
+
+ // Now we can delete the OpenGL texture and close down SDL
+ glDeleteTextures( 1, &texture );
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/gl_ps_workaround.c b/tests/gl_ps_workaround.c
new file mode 100644
index 00000000..1e2a5c41
--- /dev/null
+++ b/tests/gl_ps_workaround.c
@@ -0,0 +1,230 @@
+/*******************************************************************
+ * *
+ * Using SDL With OpenGL *
+ * *
+ * Tutorial by Kyle Foley (sdw) *
+ * *
+ * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
+ * *
+ *******************************************************************/
+
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_image.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void shaders() {
+#if USE_GLEW
+ glewInit();
+#endif
+
+ GLint ok;
+
+ const char *vertexShader = "void main(void) \n"
+ "{ \n"
+ " gl_Position = ftransform(); \n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "} \n";
+ const char *fragmentShader = "uniform sampler2D tex0; \n"
+ "void main(void) \n"
+ "{ \n"
+ " gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy); \n"
+ "} \n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ // Slightly different SDL initialization
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
+
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ // Set the OpenGL state after creating the context with SDL_SetVideoMode
+
+ glClearColor( 0, 0, 0, 0 );
+
+#if !EMSCRIPTEN
+ glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL
+#endif
+
+ glViewport( 0, 0, 640, 480 );
+
+ glMatrixMode( GL_PROJECTION );
+ GLfloat matrixData[] = { 2.0/640, 0, 0, 0,
+ 0, -2.0/480, 0, 0,
+ 0, 0, -1, 0,
+ -1, 1, 0, 1 };
+ glLoadMatrixf(matrixData); // test loadmatrix
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ // Load the OpenGL texture
+
+ GLuint texture; // Texture object handle
+ SDL_Surface *surface; // Gives us the information to make the texture
+
+ if ( (surface = IMG_Load("screenshot.png")) ) {
+
+ // Check that the image's width is a power of 2
+ if ( (surface->w & (surface->w - 1)) != 0 ) {
+ printf("warning: image.bmp's width is not a power of 2\n");
+ }
+
+ // Also check if the height is a power of 2
+ if ( (surface->h & (surface->h - 1)) != 0 ) {
+ printf("warning: image.bmp's height is not a power of 2\n");
+ }
+
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures( 1, &texture );
+
+ // Bind the texture object
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Set the texture's stretching properties
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ //SDL_LockSurface(surface);
+
+ // Add some greyness
+ memset(surface->pixels, 0x66, surface->w*surface->h);
+
+ // Edit the texture object's image data using the information SDL_Surface gives us
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
+
+ //SDL_UnlockSurface(surface);
+ }
+ else {
+ printf("SDL could not load image.bmp: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ // Free the SDL_Surface only if it was successfully created
+ if ( surface ) {
+ SDL_FreeSurface( surface );
+ }
+
+ // Clear the screen before drawing
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ shaders();
+
+ // Bind the texture to which subsequent calls refer to
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Use clientside vertex pointers to render two items. In this test we have each
+ // attribute in a separate buffer, packed (i.e. stride == 0)
+ GLfloat vertexData[] = { 10, 10,
+ 300, 10,
+ 300, 128,
+ 10, 128,
+ 410, 10,
+ 600, 10,
+ 630, 200,
+ 310, 250,
+ 100, 300,
+ 300, 300,
+ 300, 400,
+ 100, 400 };
+ GLfloat textureData[] = { 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0.5,
+ 1, 0.5,
+ 1, 1,
+ 0.5, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1, };
+
+ glEnableClientState(GL_TEXTURE_2D); // XXX should be GL_TEXTURE_COORD_ARRAY); // XXX
+ glTexCoordPointer(2, GL_FLOAT, 0, textureData);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertexData);
+
+ glDrawArrays(GL_QUADS, 0, 12);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ SDL_GL_SwapBuffers();
+
+#if !EMSCRIPTEN
+ // Wait for 3 seconds to give us a chance to see the image
+ SDL_Delay(3000);
+#endif
+
+ // Now we can delete the OpenGL texture and close down SDL
+ glDeleteTextures( 1, &texture );
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/gl_ps_workaround2.c b/tests/gl_ps_workaround2.c
new file mode 100644
index 00000000..e5bd2fd1
--- /dev/null
+++ b/tests/gl_ps_workaround2.c
@@ -0,0 +1,230 @@
+/*******************************************************************
+ * *
+ * Using SDL With OpenGL *
+ * *
+ * Tutorial by Kyle Foley (sdw) *
+ * *
+ * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
+ * *
+ *******************************************************************/
+
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#if !EMSCRIPTEN
+#define USE_GLEW 1
+#endif
+
+#if USE_GLEW
+#include "GL/glew.h"
+#endif
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_image.h"
+#if !USE_GLEW
+#include "SDL/SDL_opengl.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+void shaders() {
+#if USE_GLEW
+ glewInit();
+#endif
+
+ GLint ok;
+
+ const char *vertexShader = "void main(void) \n"
+ "{ \n"
+ " gl_Position = ftransform(); \n"
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
+ " gl_FrontColor = gl_Color; \n"
+ "} \n";
+ const char *fragmentShader = "uniform sampler2D tex0; \n"
+ "void main(void) \n"
+ "{ \n"
+ " gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy); \n"
+ "} \n";
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vertexShader, NULL);
+ glCompileShader(vs);
+ glGetShaderiv(vs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fragmentShader, NULL);
+ glCompileShader(fs);
+ glGetShaderiv(fs, GL_COMPILE_STATUS, &ok);
+ assert(ok);
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ glGetProgramiv(program, GL_LINK_STATUS, &ok);
+ assert(ok);
+
+ glUseProgram(program);
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ // Slightly different SDL initialization
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
+
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ // Set the OpenGL state after creating the context with SDL_SetVideoMode
+
+ glClearColor( 0, 0, 0, 0 );
+
+#if !EMSCRIPTEN
+ glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL
+#endif
+
+ glViewport( 0, 0, 640, 480 );
+
+ glMatrixMode( GL_PROJECTION );
+ GLfloat matrixData[] = { 2.0/640, 0, 0, 0,
+ 0, -2.0/480, 0, 0,
+ 0, 0, -1, 0,
+ -1, 1, 0, 1 };
+ glLoadMatrixf(matrixData); // test loadmatrix
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ // Load the OpenGL texture
+
+ GLuint texture; // Texture object handle
+ SDL_Surface *surface; // Gives us the information to make the texture
+
+ if ( (surface = IMG_Load("screenshot.png")) ) {
+
+ // Check that the image's width is a power of 2
+ if ( (surface->w & (surface->w - 1)) != 0 ) {
+ printf("warning: image.bmp's width is not a power of 2\n");
+ }
+
+ // Also check if the height is a power of 2
+ if ( (surface->h & (surface->h - 1)) != 0 ) {
+ printf("warning: image.bmp's height is not a power of 2\n");
+ }
+
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures( 1, &texture );
+
+ // Bind the texture object
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Set the texture's stretching properties
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ //SDL_LockSurface(surface);
+
+ // Add some greyness
+ memset(surface->pixels, 0x66, surface->w*surface->h);
+
+ // Edit the texture object's image data using the information SDL_Surface gives us
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
+
+ //SDL_UnlockSurface(surface);
+ }
+ else {
+ printf("SDL could not load image.bmp: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ // Free the SDL_Surface only if it was successfully created
+ if ( surface ) {
+ SDL_FreeSurface( surface );
+ }
+
+ // Clear the screen before drawing
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ shaders();
+
+ // Bind the texture to which subsequent calls refer to
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Use clientside vertex pointers to render two items. In this test we have each
+ // attribute in a separate buffer, packed (i.e. stride == 0)
+ GLfloat vertexData[] = { 10, 10,
+ 300, 10,
+ 300, 128,
+ 10, 128,
+ 410, 10,
+ 600, 10,
+ 630, 200,
+ 310, 250,
+ 100, 300,
+ 300, 300,
+ 300, 400,
+ 100, 400 };
+ GLfloat textureData[] = { 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0.5,
+ 1, 0.5,
+ 1, 1,
+ 0.5, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1, };
+
+ glEnable(GL_TEXTURE_2D); // XXX should be GL_TEXTURE_COORD_ARRAY); and also glEnableClientState! XXX two workarounds here
+ glTexCoordPointer(2, GL_FLOAT, 0, textureData);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertexData);
+
+ glDrawArrays(GL_QUADS, 0, 12);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ SDL_GL_SwapBuffers();
+
+#if !EMSCRIPTEN
+ // Wait for 3 seconds to give us a chance to see the image
+ SDL_Delay(3000);
+#endif
+
+ // Now we can delete the OpenGL texture and close down SDL
+ glDeleteTextures( 1, &texture );
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/glbook/CH13_ParticleSystem.png b/tests/glbook/CH13_ParticleSystem.png
index ff9c3496..4b69414f 100644
--- a/tests/glbook/CH13_ParticleSystem.png
+++ b/tests/glbook/CH13_ParticleSystem.png
Binary files differ
diff --git a/tests/perspective.c b/tests/perspective.c
new file mode 100644
index 00000000..72f4c50f
--- /dev/null
+++ b/tests/perspective.c
@@ -0,0 +1,408 @@
+/*
+ * SDL OpenGL Tutorial.
+ * (c) Michael Vance, 2000
+ * briareos@lokigames.com
+ *
+ * Distributed under terms of the LGPL.
+ */
+
+#include <SDL/SDL.h>
+
+#ifdef EMSCRIPTEN
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "emscripten.h"
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef EMSCRIPTEN
+ #define emColor4ubv(x)
+#else
+#define emColor4ubv(x) glColor4ubv(x)
+#endif
+
+static GLboolean should_rotate = GL_TRUE;
+
+static void quit_tutorial( int code )
+{
+ /*
+ * Quit SDL so we can release the fullscreen
+ * mode and restore the previous video settings,
+ * etc.
+ */
+ SDL_Quit( );
+
+ /* Exit program. */
+ exit( code );
+}
+
+static void handle_key_down( SDL_keysym* keysym )
+{
+
+ /*
+ * We're only interested if 'Esc' has
+ * been presssed.
+ *
+ * EXERCISE:
+ * Handle the arrow keys and have that change the
+ * viewing position/angle.
+ */
+ switch( keysym->sym ) {
+ case SDLK_ESCAPE:
+ quit_tutorial( 0 );
+ break;
+ case SDLK_SPACE:
+ should_rotate = !should_rotate;
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void process_events( void )
+{
+ /* Our SDL event placeholder. */
+ SDL_Event event;
+
+ /* Grab all the events off the queue. */
+ while( SDL_PollEvent( &event ) ) {
+
+ switch( event.type ) {
+ case SDL_KEYDOWN:
+ /* Handle key presses. */
+ handle_key_down( &event.key.keysym );
+ break;
+ case SDL_QUIT:
+ /* Handle quit requests (like Ctrl-c). */
+ quit_tutorial( 0 );
+ break;
+ }
+
+ }
+
+}
+
+static void draw_screen( void )
+{
+ /* Our angle of rotation. */
+ static float angle = 0.0f;
+
+ /*
+ * EXERCISE:
+ * Replace this awful mess with vertex
+ * arrays and a call to glDrawElements.
+ *
+ * EXERCISE:
+ * After completing the above, change
+ * it to use compiled vertex arrays.
+ *
+ * EXERCISE:
+ * Verify my windings are correct here ;).
+ */
+ static GLfloat v0[] = { -1.0f, -1.0f, 1.0f };
+ static GLfloat v1[] = { 1.0f, -1.0f, 1.0f };
+ static GLfloat v2[] = { 1.0f, 1.0f, 1.0f };
+ static GLfloat v3[] = { -1.0f, 1.0f, 1.0f };
+ static GLfloat v4[] = { -1.0f, -1.0f, -1.0f };
+ static GLfloat v5[] = { 1.0f, -1.0f, -1.0f };
+ static GLfloat v6[] = { 1.0f, 1.0f, -1.0f };
+ static GLfloat v7[] = { -1.0f, 1.0f, -1.0f };
+ static GLubyte red[] = { 255, 0, 0, 255 };
+ static GLubyte green[] = { 0, 255, 0, 255 };
+ static GLubyte blue[] = { 0, 0, 255, 255 };
+ static GLubyte white[] = { 255, 255, 255, 255 };
+ static GLubyte yellow[] = { 0, 255, 255, 255 };
+ static GLubyte black[] = { 0, 0, 0, 255 };
+ static GLubyte orange[] = { 255, 255, 0, 255 };
+ static GLubyte purple[] = { 255, 0, 255, 0 };
+
+ /* Clear the color and depth buffers. */
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ /* We don't want to modify the projection matrix. */
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity( );
+
+ /* Move down the z-axis. */
+ glTranslatef( 0.0, 0.0, -5.0 );
+
+ /* Rotate. */
+ glRotatef( angle, 0.0, 1.0, 0.0 );
+
+ if( should_rotate ) {
+
+ if( ++angle > 360.0f ) {
+ angle = 0.0f;
+ }
+
+ }
+
+ /* Send our triangle data to the pipeline. */
+ glBegin( GL_TRIANGLES );
+
+ emColor4ubv( red );
+ glVertex3fv( v0 );
+ emColor4ubv( green );
+ glVertex3fv( v1 );
+ emColor4ubv( blue );
+ glVertex3fv( v2 );
+
+ emColor4ubv( red );
+ glVertex3fv( v0 );
+ emColor4ubv( blue );
+ glVertex3fv( v2 );
+ emColor4ubv( white );
+ glVertex3fv( v3 );
+
+ emColor4ubv( green );
+ glVertex3fv( v1 );
+ emColor4ubv( black );
+ glVertex3fv( v5 );
+ emColor4ubv( orange );
+ glVertex3fv( v6 );
+
+ emColor4ubv( green );
+ glVertex3fv( v1 );
+ emColor4ubv( orange );
+ glVertex3fv( v6 );
+ emColor4ubv( blue );
+ glVertex3fv( v2 );
+
+ emColor4ubv( black );
+ glVertex3fv( v5 );
+ emColor4ubv( yellow );
+ glVertex3fv( v4 );
+ emColor4ubv( purple );
+ glVertex3fv( v7 );
+
+ emColor4ubv( black );
+ glVertex3fv( v5 );
+ emColor4ubv( purple );
+ glVertex3fv( v7 );
+ emColor4ubv( orange );
+ glVertex3fv( v6 );
+
+ emColor4ubv( yellow );
+ glVertex3fv( v4 );
+ emColor4ubv( red );
+ glVertex3fv( v0 );
+ emColor4ubv( white );
+ glVertex3fv( v3 );
+
+ emColor4ubv( yellow );
+ glVertex3fv( v4 );
+ emColor4ubv( white );
+ glVertex3fv( v3 );
+ emColor4ubv( purple );
+ glVertex3fv( v7 );
+
+ emColor4ubv( white );
+ glVertex3fv( v3 );
+ emColor4ubv( blue );
+ glVertex3fv( v2 );
+ emColor4ubv( orange );
+ glVertex3fv( v6 );
+
+ emColor4ubv( white );
+ glVertex3fv( v3 );
+ emColor4ubv( orange );
+ glVertex3fv( v6 );
+ emColor4ubv( purple );
+ glVertex3fv( v7 );
+
+ emColor4ubv( green );
+ glVertex3fv( v1 );
+ emColor4ubv( red );
+ glVertex3fv( v0 );
+ emColor4ubv( yellow );
+ glVertex3fv( v4 );
+
+ emColor4ubv( green );
+ glVertex3fv( v1 );
+ emColor4ubv( yellow );
+ glVertex3fv( v4 );
+ emColor4ubv( black );
+ glVertex3fv( v5 );
+
+ glEnd( );
+
+ /*
+ * EXERCISE:
+ * Draw text telling the user that 'Spc'
+ * pauses the rotation and 'Esc' quits.
+ * Do it using vetors and textured quads.
+ */
+
+ /*
+ * Swap the buffers. This this tells the driver to
+ * render the next frame from the contents of the
+ * back-buffer, and to set all rendering operations
+ * to occur on what was the front-buffer.
+ *
+ * Double buffering prevents nasty visual tearing
+ * from the application drawing on areas of the
+ * screen that are being updated at the same time.
+ */
+ SDL_GL_SwapBuffers( );
+}
+
+static void setup_opengl( int width, int height )
+{
+ float ratio = (float) width / (float) height;
+
+ /* Our shading model--Gouraud (smooth). */
+ glShadeModel( GL_SMOOTH );
+
+ /* Culling. */
+ glCullFace( GL_BACK );
+ glFrontFace( GL_CCW );
+ glEnable( GL_CULL_FACE );
+
+ /* Set the clear color. */
+ glClearColor( 0, 0, 0, 0 );
+
+ /* Setup our viewport. */
+ glViewport( 0, 0, width, height );
+
+ /*
+ * Change to the projection matrix and set
+ * our viewing volume.
+ */
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity( );
+ /*
+ * EXERCISE:
+ * Replace this with a call to glFrustum.
+ */
+ gluPerspective( 60.0, ratio, 1.0, 1024.0 );
+}
+
+void one_iter();
+void one_iter() {
+ process_events( );
+ /* Draw the screen. */
+ draw_screen( );
+}
+
+int main( int argc, char* argv[] )
+{
+ /* Information about the current video settings. */
+ const SDL_VideoInfo* info = NULL;
+ /* Dimensions of our window. */
+ int width = 0;
+ int height = 0;
+ /* Color depth in bits of our window. */
+ int bpp = 0;
+ /* Flags we will pass into SDL_SetVideoMode. */
+ int flags = 0;
+
+ /* First, initialize SDL's video subsystem. */
+ if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
+ /* Failed, exit. */
+ fprintf( stderr, "Video initialization failed: %s\n",
+ SDL_GetError( ) );
+ quit_tutorial( 1 );
+ }
+
+ /* Let's get some video information. */
+ info = SDL_GetVideoInfo( );
+
+ if( !info ) {
+ /* This should probably never happen. */
+ fprintf( stderr, "Video query failed: %s\n",
+ SDL_GetError( ) );
+ quit_tutorial( 1 );
+ }
+
+ /*
+ * Set our width/height to 640/480 (you would
+ * of course let the user decide this in a normal
+ * app). We get the bpp we will request from
+ * the display. On X11, VidMode can't change
+ * resolution, so this is probably being overly
+ * safe. Under Win32, ChangeDisplaySettings
+ * can change the bpp.
+ */
+ width = 640;
+ height = 480;
+ bpp = info->vfmt->BitsPerPixel;
+
+ /*
+ * Now, we want to setup our requested
+ * window attributes for our OpenGL window.
+ * We want *at least* 5 bits of red, green
+ * and blue. We also want at least a 16-bit
+ * depth buffer.
+ *
+ * The last thing we do is request a double
+ * buffered window. '1' turns on double
+ * buffering, '0' turns it off.
+ *
+ * Note that we do not use SDL_DOUBLEBUF in
+ * the flags to SDL_SetVideoMode. That does
+ * not affect the GL attribute state, only
+ * the standard 2D blitting setup.
+ */
+// SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
+// SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
+// SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
+// SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
+// SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+
+ /*
+ * We want to request that SDL provide us
+ * with an OpenGL window, in a fullscreen
+ * video mode.
+ *
+ * EXERCISE:
+ * Make starting windowed an option, and
+ * handle the resize events properly with
+ * glViewport.
+ */
+ flags = SDL_OPENGL;// | SDL_FULLSCREEN;
+
+ /*
+ * Set the video mode
+ */
+ if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) {
+ /*
+ * This could happen for a variety of reasons,
+ * including DISPLAY not being set, the specified
+ * resolution not being available, etc.
+ */
+ fprintf( stderr, "Video mode set failed: %s\n",
+ SDL_GetError( ) );
+ quit_tutorial( 1 );
+ }
+
+ /*
+ * At this point, we should have a properly setup
+ * double-buffered window for use with OpenGL.
+ */
+ setup_opengl( width, height );
+
+ /*
+ * Now we want to begin our normal app process--
+ * an event loop with a lot of redrawing.
+ */
+ one_iter(); // just one for testing purposes
+
+#ifndef EMSCRIPTEN
+ SDL_Delay(2000);
+#endif
+
+ /*
+ * EXERCISE:
+ * Record timings using SDL_GetTicks() and
+ * and print out frames per second at program
+ * end.
+ */
+
+ /* Never reached. */
+ return 0;
+}
diff --git a/tests/perspective.png b/tests/perspective.png
new file mode 100644
index 00000000..04cedc71
--- /dev/null
+++ b/tests/perspective.png
Binary files differ
diff --git a/tests/runner.py b/tests/runner.py
index b6980933..96a2dabd 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -100,14 +100,8 @@ class RunnerCore(unittest.TestCase):
for temp_file in os.listdir(TEMP_DIR):
if temp_file.endswith('.ll'):
self.has_prev_ll = True
-
+
def tearDown(self):
- if self.save_JS:
- for name in os.listdir(self.get_dir()):
- if name.endswith(('.o.js', '.cc.js')):
- suff = '.'.join(name.split('.')[-2:])
- shutil.copy(os.path.join(self.get_dir(), name),
- os.path.join(TEMP_DIR, self.id().replace('__main__.', '').replace('.test_', '.')+'.'+suff))
if not self.save_dir:
# rmtree() fails on Windows if the current working directory is inside the tree.
os.chdir(os.path.join(self.get_dir(), '..'))
@@ -140,6 +134,12 @@ class RunnerCore(unittest.TestCase):
def get_stdout_path(self):
return os.path.join(self.get_dir(), 'stdout')
+ def hardcode_arguments(self, filename, args):
+ # Hardcode in the arguments, so js is portable without manual commandlinearguments
+ if not args: return
+ js = open(filename).read()
+ open(filename, 'w').write(js.replace('var ret = run();', 'var ret = run(%s);' % str(args)))
+
def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None):
if ll_file.endswith(('.bc', '.o')):
if ll_file != filename + '.o':
@@ -435,6 +435,8 @@ process(sys.argv[1])
sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
+test_index = 0
+
if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv):
# Tests
@@ -448,29 +450,35 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
## Does a complete test - builds, runs, checks output, etc.
def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
- if force_c or (main_file is not None and main_file[-2:]) == '.c':
- basename = 'src.c'
- Building.COMPILER = to_cc(Building.COMPILER)
-
- dirname = self.get_dir()
- filename = os.path.join(dirname, basename)
- if not no_build:
- self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
- build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
-
- # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
- if js_engines is None:
- js_engines = JS_ENGINES
- if Settings.USE_TYPED_ARRAYS:
- js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
- js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
- if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
- for engine in js_engines:
- js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
- self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
- self.assertNotContained('ERROR', js_output)
-
- #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
+ if force_c or (main_file is not None and main_file[-2:]) == '.c':
+ basename = 'src.c'
+ Building.COMPILER = to_cc(Building.COMPILER)
+
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, basename)
+ if not no_build:
+ self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
+ build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
+
+ # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
+ if js_engines is None:
+ js_engines = JS_ENGINES
+ if Settings.USE_TYPED_ARRAYS:
+ js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
+ js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
+ if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
+ for engine in js_engines:
+ js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
+ self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
+ self.assertNotContained('ERROR', js_output)
+
+ #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
+
+ if self.save_JS:
+ global test_index
+ self.hardcode_arguments(filename + '.o.js', args)
+ shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js'))
+ test_index += 1
# No building - just process an existing .ll file (or .bc, which we turn into .ll)
def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]):
@@ -1131,7 +1139,6 @@ m_divisor is 1091269979
def test_i32_mul_precise(self):
if self.emcc_args == None: return self.skip('needs ta2')
- self.emcc_args += ['-s', 'PRECISE_I32_MUL=1']
src = r'''
#include <stdio.h>
@@ -1146,6 +1153,10 @@ m_divisor is 1091269979
self.do_run(src, '3217489085')
def test_i32_mul_semiprecise(self):
+ if Settings.ASM_JS: return self.skip('asm is always fully precise')
+
+ Settings.PRECISE_I32_MUL = 0 # we want semiprecise here
+
src = r'''
#include <stdio.h>
@@ -2845,6 +2856,23 @@ Exiting setjmp function, level: 0, prev_jmp: -1
'''
self.do_run(src, 'a1: 0\na2: 0\na3: 1\nb1: 0\nb2: 1\nb3: 1\nc1: 1\nc2: 1\nc3: 1\n')
+ def test_dynamic_cast_2(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
+ src = r'''
+ #include <stdio.h>
+ #include <typeinfo>
+
+ class Class {};
+
+ int main() {
+ const Class* dp = dynamic_cast<const Class*>(&typeid(Class));
+ // should return dp == NULL,
+ printf("pointer: %p\n", dp);
+ }
+ '''
+ self.do_run(src, "pointer: (nil)")
+
def test_funcptr(self):
src = '''
#include <stdio.h>
@@ -3966,6 +3994,18 @@ The current type of b is: 9
'''
self.do_run(src, '*0\n')
+ def test_time_c(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+
+ int main() {
+ time_t t = time(0);
+ printf("time: %s\n", ctime(&t));
+ }
+ '''
+ self.do_run(src, 'time: ') # compilation check, mainly
+
def test_intentional_fault(self):
if Settings.ASM_JS: return self.skip('no throw support in asm')
# Some programs intentionally segfault themselves, we should compile that into a throw
@@ -4095,10 +4135,12 @@ The current type of b is: 9
'''
self.do_run(src, '*0.00,0.00,0.00*\n*0,77,0*\n*0,77,0*\n*0,77,0*')
- def test_memcpy(self):
+ def test_memcpy_memcmp(self):
src = '''
#include <stdio.h>
#include <string.h>
+ #include <assert.h>
+
#define MAXX 48
void reset(unsigned char *buffer) {
for (int i = 0; i < MAXX; i++) buffer[i] = i+1;
@@ -4119,6 +4161,20 @@ The current type of b is: 9
reset(buffer);
memcpy(buffer+i, buffer+j, k);
dump(buffer);
+ assert(memcmp(buffer+i, buffer+j, k) == 0);
+ buffer[i + k/2]++;
+ if (buffer[i + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ }
+ buffer[i + k/2]--;
+ buffer[j + k/2]++;
+ if (buffer[j + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ }
}
}
}
@@ -4197,6 +4253,19 @@ The current type of b is: 9
'''
self.do_run(src, 'final: -403200.');
+ def test_memmove3(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main() {
+ char str[] = "memmove can be vvery useful....!";
+ memmove(str+15, str+16, 17);
+ puts(str);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'memmove can be very useful....!')
+
def test_bsearch(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1')
@@ -5299,9 +5368,30 @@ Pass: 0.000012 0.000012''')
return(0);
}
'''
-
self.do_run(src, '3\nday 19, month Nov, year 2012');
+ def test_sscanf_5(self):
+ src = r'''
+ #include "stdio.h"
+
+ static const char *colors[] = {
+ " c black",
+ ". c #001100",
+ "X c #111100"
+ };
+
+ int main(){
+ unsigned char code;
+ char color[32];
+ int rcode;
+ for(int i = 0; i < 3; i++) {
+ rcode = sscanf(colors[i], "%c c %s", &code, color);
+ printf("%i, %c, %s\n", rcode, code, color);
+ }
+ }
+ '''
+ self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100');
+
def test_langinfo(self):
src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
@@ -6283,6 +6373,53 @@ int main(int argc, char **argv) {
self.do_run(src, '789:123.46\n0:100.1')
+ def test_reinterpreted_ptrs(self):
+ if self.emcc_args is None: return self.skip('needs emcc and libc')
+
+ src = r'''
+#include <stdio.h>
+
+class Foo {
+private:
+ float bar;
+public:
+ int baz;
+
+ Foo(): bar(0), baz(4711) {};
+
+ int getBar() const;
+};
+
+int Foo::getBar() const {
+ return this->bar;
+};
+
+const Foo *magic1 = reinterpret_cast<Foo*>(0xDEAD111F);
+const Foo *magic2 = reinterpret_cast<Foo*>(0xDEAD888F);
+
+static void runTest() {
+
+ const Foo *a = new Foo();
+ const Foo *b = a;
+
+ if (a->getBar() == 0) {
+ if (a->baz == 4712)
+ b = magic1;
+ else
+ b = magic2;
+ }
+
+ printf("%s\n", (b == magic1 ? "magic1" : (b == magic2 ? "magic2" : "neither")));
+};
+
+extern "C" {
+ int main(int argc, char **argv) {
+ runTest();
+ }
+}
+'''
+ self.do_run(src, 'magic2')
+
def test_jansson(self):
return self.skip('currently broken')
@@ -6783,7 +6920,7 @@ def process(filename):
if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc')
if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
- Settings.CORRECT_SIGNS = 1 # XXX: in default, we fail with 2 here, even though the pgo_data should be correct (and works in s_0_0). Investigate this.
+ Settings.CORRECT_SIGNS = 1
Settings.CORRECT_OVERFLOWS = 0
Settings.CORRECT_ROUNDINGS = 0
if self.emcc_args is None: Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
@@ -6995,6 +7132,14 @@ def process(filename):
self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
print >> sys.stderr, 'debug check %d passed too' % debug
+ try:
+ os.environ['EMCC_FORCE_STDLIBS'] = '1'
+ print 'EMCC_FORCE_STDLIBS'
+ do_test()
+ finally:
+ del os.environ['EMCC_FORCE_STDLIBS']
+ print >> sys.stderr, 'EMCC_FORCE_STDLIBS ok'
+
try_delete(CANONICAL_TEMP_DIR)
else:
print >> sys.stderr, 'not doing debug check'
@@ -7062,6 +7207,16 @@ def process(filename):
finally:
del os.environ['EMCC_LEAVE_INPUTS_RAW']
+ def test_fuzz(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+
+ Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz')]
+
+ for name in glob.glob(path_from_root('tests', 'fuzz', '*.c')):
+ print name
+ self.do_run(open(path_from_root('tests', 'fuzz', name)).read(),
+ open(path_from_root('tests', 'fuzz', name + '.txt')).read(), force_c=True)
+
# Autodebug the code
def do_autodebug(self, filename):
output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
@@ -7113,40 +7268,101 @@ def process(filename):
'''
self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug)
- def test_profiling(self):
- if Settings.ASM_JS: return self.skip('asm does not support profiling')
+ def test_corruption(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
- src = '''
- #include <emscripten.h>
- #include <unistd.h>
+ Settings.CORRUPTION_CHECK = 1
- int main()
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ int main(int argc, char **argv) {
+ int size = 1024*argc;
+ char *buffer = (char*)malloc(size);
+ #if CORRUPT
+ memset(buffer, argc, size+15);
+ #else
+ memset(buffer, argc, size);
+ #endif
+ for (int x = 0; x < size; x += argc*3) buffer[x] = x/3;
+ int ret = 0;
+ for (int x = 0; x < size; x++) ret += buffer[x];
+ free(buffer);
+ printf("All ok, %d\n", ret);
+ }
+ '''
+
+ for corrupt in [1]:
+ self.do_run(src.replace('CORRUPT', str(corrupt)), 'Heap corruption detected!' if corrupt else 'All ok, 4209')
+
+ def test_corruption_2(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
+
+ Settings.SAFE_HEAP = 1
+ Settings.CORRUPTION_CHECK = 1
+
+ # test for free(0), malloc(0), etc.
+ src = r'''
+ #include <iostream>
+ #include <fstream>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main() {
+ atexit(bye);
+
+ std::string testPath = "/Script/WA-KA.txt";
+ std::fstream str(testPath.c_str(), std::ios::in | std::ios::binary);
+
+ if (str.is_open())
{
- EMSCRIPTEN_PROFILE_INIT(3);
- EMSCRIPTEN_PROFILE_BEGIN(0);
- usleep(10 * 1000);
- EMSCRIPTEN_PROFILE_END(0);
- EMSCRIPTEN_PROFILE_BEGIN(1);
- usleep(50 * 1000);
- EMSCRIPTEN_PROFILE_END(1);
- EMSCRIPTEN_PROFILE_BEGIN(2);
- usleep(250 * 1000);
- EMSCRIPTEN_PROFILE_END(2);
- return 0;
+ std::cout << "open!" << std::endl;
+ } else {
+ std::cout << "missing!" << std::endl;
}
+
+ return 1;
+ }
'''
+ self.do_run(src, 'missing!\nall ok\n')
- post1 = '''
-def process(filename):
- src = open(filename, 'a')
- src.write(\'\'\'
- Profiling.dump();
- \'\'\')
- src.close()
-'''
+ def test_corruption_3(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
- self.do_run(src, '''Profiling data:
-Block 0: ''', post_build=post1)
+ Settings.CORRUPTION_CHECK = 1
+
+ # realloc
+ src = r'''
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <assert.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main(int argc, char **argv) {
+ atexit(bye);
+
+ char *buffer = (char*)malloc(100);
+ for (int i = 0; i < 100; i++) buffer[i] = (i*i)%256;
+ buffer = (char*)realloc(buffer, argc + 50);
+ for (int i = 0; i < argc + 50; i++) {
+ //printf("%d : %d : %d : %d\n", i, (int)(buffer + i), buffer[i], (char)((i*i)%256));
+ assert(buffer[i] == (char)((i*i)%256));
+ }
+ return 1;
+ }
+ '''
+ self.do_run(src, 'all ok\n')
### Integration tests
@@ -7676,6 +7892,8 @@ def process(filename):
def test_debug(self):
if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+ if self.emcc_args is not None:
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
src = '''
#include <stdio.h>
@@ -8051,7 +8269,6 @@ class %s(T):
Settings.ASSERTIONS = 1-embetter
Settings.SAFE_HEAP = 1-(embetter and llvm_opts)
Building.LLVM_OPTS = llvm_opts
- Settings.PGO = 0
Settings.CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
Settings.CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
Settings.CORRECT_SIGNS = 0
@@ -8061,7 +8278,6 @@ class %s(T):
Settings.INIT_STACK = 0
Settings.RUNTIME_TYPE_INFO = 0
Settings.DISABLE_EXCEPTION_CATCHING = 0
- Settings.PROFILE = 0
Settings.INCLUDE_FULL_LIBRARY = 0
Settings.BUILD_AS_SHARED_LIB = 0
Settings.RUNTIME_LINKED_LIBS = []
@@ -8084,11 +8300,11 @@ TT = %s
exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "SAFE_HEAP=1"])')
# Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
- exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "--closure", "0"])')
+ exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2"])')
# asm.js
- #exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "--closure", "0", "-s", "ASM_JS=1"])')
- exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "--closure", "0", "-s", "ASM_JS=1"])')
+ #exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "-s", "ASM_JS=1"])')
+ exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])')
# Make custom runs with various options
for compiler, quantum, embetter, typed_arrays, llvm_opts in [
@@ -8114,11 +8330,12 @@ TT = %s
# --version
output = Popen([PYTHON, compiler, '--version'], stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('''emcc (Emscripten GCC-like replacement) 2.0
-Copyright (C) 2012 the Emscripten authors.
+ output = output[0].replace('\r', '')
+ self.assertContained('''emcc (Emscripten GCC-like replacement)''', output)
+ self.assertContained('''Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-''', output[0].replace('\r', ''), output[1].replace('\r', ''))
+''', output)
# -v, without input files
output = Popen([PYTHON, compiler, '-v'], stdout=PIPE, stderr=PIPE).communicate()
@@ -8224,20 +8441,22 @@ Options that are modified or new in %s include:
(['-o', 'something.js', '-O0'], 0, None, 0, 0),
(['-o', 'something.js', '-O1'], 1, None, 0, 0),
(['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 1, 0),
- (['-o', 'something.js', '-O2'], 2, None, 1, 1),
+ (['-o', 'something.js', '-O2'], 2, None, 0, 1),
(['-o', 'something.js', '-O2', '--closure', '0'], 2, None, 0, 0),
+ (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0),
(['-o', 'something.js', '-O3'], 3, None, 1, 1),
(['-o', 'something.js', '-O3', '--closure', '0'], 3, None, 0, 0),
# and, test compiling to bitcode first
(['-o', 'something.bc'], 0, [], 0, 0),
(['-o', 'something.bc'], 0, ['-O0'], 0, 0),
(['-o', 'something.bc'], 1, ['-O1'], 0, 0),
- (['-o', 'something.bc'], 2, ['-O2'], 1, 0),
+ (['-o', 'something.bc'], 2, ['-O2'], 0, 0),
(['-o', 'something.bc'], 3, ['-O3'], 1, 0),
(['-O1', '-o', 'something.bc'], 0, [], 0, 0), # -Ox is ignored and warned about
]:
- #print params, opt_level, bc_params, closure
+ print params, opt_level, bc_params, closure, has_malloc
self.clear()
+ keep_debug = '-g' in params
output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params,
stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
@@ -8261,14 +8480,13 @@ Options that are modified or new in %s include:
else:
# closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure
assert 'Module._main = ' not in generated, 'closure compiler should not have been run'
- # XXX find a way to test this: assert ('& 255' in generated or '&255' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2'
- assert ('(label)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
- assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
- assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on'
+ if keep_debug:
+ assert ('(label)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
+ assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
+ assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on'
if opt_level >= 2:
- assert re.search('HEAP8\[\$\w+ \+ \(+\$\w+ ', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2
+ assert re.search('HEAP8\[\$?\w+ \+ \(+\$?\w+ ', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2
assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts'
- assert ('function _malloc(bytes) {' in generated) == (not has_malloc), 'If malloc is needed, it should be there, if not not'
assert 'function _main() {' in generated, 'Should be unminified, including whitespace'
assert ('-O3' in (params+(bc_params or []))) or'function _dump' in generated, 'No inlining by default'
@@ -8588,6 +8806,21 @@ f.close()
self.assertContained('result: 62', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ def test_asm_undefined(self):
+ src = r'''
+ #include <stdio.h>
+ extern void doit();
+ int main(int argc, char **argv) {
+ if (argc == 121) doit();
+ printf("done\n");
+ return 1;
+ }
+ '''
+ filename = self.in_dir('src.cpp')
+ open(filename, 'w').write(src)
+ out, err = Popen([PYTHON, EMCC, filename, '-s', 'ASM_JS=1', '-O2'], stderr=PIPE).communicate()
+ assert 'Warning: Unresolved symbol' in err, 'always warn on undefs in asm, since it breaks validation'
+
def test_redundant_link(self):
lib = "int mult() { return 1; }"
lib_name = os.path.join(self.get_dir(), 'libA.c')
@@ -9011,7 +9244,7 @@ f.close()
return 0;
}
''')
- Popen([PYTHON, EMCC, '-O2', '--closure', '-0', os.path.join(self.get_dir(), 'main.cpp')]).communicate()
+ Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'main.cpp')]).communicate()
output = run_js(os.path.join(self.get_dir(), 'a.out.js'), full_output=True, stderr=PIPE)
self.assertContained('''0:0
1:1
@@ -9223,6 +9456,26 @@ f.close()
finally:
del os.environ['EMCC_DEBUG']
+ def test_debuginfo(self):
+ if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ # llvm debug info is kept only when we can see it, which is without the js optimize, -O0. js debug info is lost by registerize in -O2, so - g disables it
+ for args, expect_llvm, expect_js in [
+ (['-O0'], True, True),
+ (['-O0', '-g'], True, True),
+ (['-O1'], False, True),
+ (['-O1', '-g'], False, True),
+ (['-O2'], False, False),
+ (['-O2', '-g'], False, True),
+ ]:
+ print args, expect_llvm, expect_js
+ output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
+ assert expect_llvm == ('strip-debug' not in err)
+ assert expect_js == ('registerize' not in err)
+ finally:
+ del os.environ['EMCC_DEBUG']
+
def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1
try_delete(os.path.join(self.get_dir(), 'test'))
shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test'))
@@ -9958,6 +10211,12 @@ elif 'browser' in str(sys.argv):
Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html']).communicate()
self.run_browser('page.html', '', '/report_result?600')
+ def test_sdl_image_jpeg(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg'))
+ open(os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image_jpeg.c')).read()))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), '--preload-file', 'screenshot.jpeg', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', '', '/report_result?600')
+
def test_sdl_image_compressed(self):
for image, width in [(path_from_root('tests', 'screenshot2.png'), 300),
(path_from_root('tests', 'screenshot.jpg'), 600)]:
@@ -9977,12 +10236,12 @@ elif 'browser' in str(sys.argv):
self.run_browser('page.html', '', '/report_result?' + str(width))
def test_sdl_image_prepare(self):
- # load an image file, get pixel data. Also O2 coverage for --preload-file
+ # load an image file, get pixel data.
shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
def test_sdl_image_prepare_data(self):
- # load an image file, get pixel data. Also O2 coverage for --preload-file
+ # load an image file, get pixel data.
shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
@@ -10080,56 +10339,56 @@ elif 'browser' in str(sys.argv):
# SDL, OpenGL, textures, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-gray-purple.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl.c'), '-O2', '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl.c'), '-O2', '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with gray at the top.', '/report_result?0')
def test_sdl_ogl_defaultmatrixmode(self):
# SDL, OpenGL, textures, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-gray-purple.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl_defaultMatrixMode.c'), '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl_defaultMatrixMode.c'), '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with gray at the top.', '/report_result?0')
def test_sdl_ogl_p(self):
# Immediate mode with pointers
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-gray.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl_p.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_ogl_p.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with gray at the top.', '/report_result?0')
def test_sdl_fog_simple(self):
# SDL, OpenGL, textures, fog, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-fog-simple.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_simple.c'), '-O2', '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_simple.c'), '-O2', '--minify', '0', '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0')
def test_sdl_fog_negative(self):
# SDL, OpenGL, textures, fog, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-fog-negative.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_negative.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_negative.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0')
def test_sdl_fog_density(self):
# SDL, OpenGL, textures, fog, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-fog-density.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_density.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_density.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0')
def test_sdl_fog_exp2(self):
# SDL, OpenGL, textures, fog, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-fog-exp2.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_exp2.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_exp2.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0')
def test_sdl_fog_linear(self):
# SDL, OpenGL, textures, fog, immediate mode. Closure for more coverage
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.reftest(path_from_root('tests', 'screenshot-fog-linear.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_linear.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_linear.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0')
def test_worker(self):
@@ -10269,26 +10528,26 @@ elif 'browser' in str(sys.argv):
def test_glgears(self):
self.reftest(path_from_root('tests', 'gears.png'))
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html',
- '-DHAVE_BUILTIN_SINCOS', '--pre-js', 'reftest.js']).communicate()
+ '-DHAVE_BUILTIN_SINCOS', '--pre-js', 'reftest.js', '-s', 'GL_TESTING=1']).communicate()
self.run_browser('something.html', 'You should see animating gears.', '/report_result?0')
def test_glgears_animation(self):
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html',
- '-DHAVE_BUILTIN_SINCOS',
+ '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1',
'--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')]).communicate()
self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true')
def test_glgears_bad(self):
# Make sure that OpenGL ES is not available if typed arrays are not used
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html',
- '-DHAVE_BUILTIN_SINCOS',
+ '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1',
'-s', 'USE_TYPED_ARRAYS=0',
'--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')]).communicate()
self.run_browser('something.html', 'You should not see animating gears.', '/report_gl_result?false')
def test_glgears_deriv(self):
self.reftest(path_from_root('tests', 'gears.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_deriv.c'), '-o', 'something.html',
+ Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_deriv.c'), '-o', 'something.html', '-s', 'GL_TESTING=1',
'-DHAVE_BUILTIN_SINCOS', '--pre-js', 'reftest.js']).communicate()
self.run_browser('something.html', 'You should see animating gears.', '/report_result?0')
src = open('something.html').read()
@@ -10319,7 +10578,7 @@ elif 'browser' in str(sys.argv):
args = ['--preload-file', 'smoke.tga', '-O2'] # test optimizations and closure here as well for more coverage
self.reftest(book_path(basename.replace('.bc', '.png')))
- Popen([PYTHON, EMCC, program, '-o', 'program.html', '--pre-js', 'reftest.js'] + args).communicate()
+ Popen([PYTHON, EMCC, program, '-o', 'program.html', '--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] + args).communicate()
self.run_browser('program.html', '', '/report_result?0')
def btest(self, filename, expected=None, reference=None, reference_slack=0, args=[]): # TODO: use in all other tests
@@ -10334,7 +10593,7 @@ elif 'browser' in str(sys.argv):
expected = [str(i) for i in range(0, reference_slack+1)]
shutil.copyfile(path_from_root('tests', filename), os.path.join(self.get_dir(), filename))
self.reftest(path_from_root('tests', reference))
- args = args + ['--pre-js', 'reftest.js']
+ args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1']
Popen([PYTHON, EMCC, os.path.join(self.get_dir(), filename), '-o', 'test.html'] + args).communicate()
if type(expected) is str: expected = [expected]
self.run_browser('test.html', '.', ['/report_result?' + e for e in expected])
@@ -10369,6 +10628,19 @@ elif 'browser' in str(sys.argv):
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'])
+ def test_gl_ps_packed(self):
+ # packed data that needs to be strided
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'])
+
+ def test_gl_ps_workaround(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps_workaround.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'])
+
+ def test_gl_ps_workaround2(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps_workaround2.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'])
+
def test_matrix_identity(self):
self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'])
@@ -10417,6 +10689,15 @@ elif 'browser' in str(sys.argv):
def test_cubegeom_fog(self):
self.btest('cubegeom_fog.c', expected=['1617140399', '-898782526', '-946179526'])
+ def test_cubegeom_pre_vao(self):
+ self.btest('cubegeom_pre_vao.c', expected=['-1472804742', '-1626058463', '-2046234971'])
+
+ def test_cubegeom_pre2_vao(self):
+ self.btest('cubegeom_pre2_vao.c', expected=['-1472804742', '-1626058463', '-2046234971'])
+
+ def test_cubegeom_pre2_vao2(self):
+ self.btest('cubegeom_pre2_vao2.c', expected=['-790445118'])
+
def test_cube_explosion(self):
self.btest('cube_explosion.c', expected=['667220544', '-1543354600', '-1485258415'])
@@ -10499,14 +10780,17 @@ elif 'browser' in str(sys.argv):
def test_subdata(self):
self.btest('gl_subdata.cpp', reference='float_tex.png')
+ def test_perspective(self):
+ self.btest('perspective.c', reference='perspective.png')
+
def test_runtimelink(self):
main, supp = self.setup_runtimelink_test()
open(self.in_dir('supp.cpp'), 'w').write(supp)
- Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2', '--closure', '0']).communicate()
+ Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2']).communicate()
shutil.move(self.in_dir('supp.js'), self.in_dir('supp.so'))
- self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2', '--closure', '0'], expected='76')
+ self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2'], expected='76')
def test_pre_run_deps(self):
# Adding a dependency in preRun will delay run
@@ -10802,12 +11086,15 @@ elif 'benchmark' in str(sys.argv):
try_delete(final_filename)
output = Popen([PYTHON, EMCC, filename, #'-O3',
- '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
- '-s', 'ASM_JS=1',# '-s', 'USE_MATH_IMUL=1',
+ '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'EXPLICIT_ZEXT=1',
+ '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1',
'-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024',
'-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate()
assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0]
+ if self.save_JS:
+ self.hardcode_arguments(final_filename, args)
+
# Run JS
global total_times, tests_done
times = []
@@ -11060,7 +11347,7 @@ elif 'benchmark' in str(sys.argv):
def test_dlmalloc(self):
# XXX This seems to have regressed slightly with emcc. Are -g and the signs lines passed properly?
src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
- self.do_benchmark('dlmalloc', src, ['400', '3000'], '*3000,0*', emcc_args=['-g', '-s', 'CORRECT_SIGNS=2', '-s', 'CORRECT_SIGNS_LINES=[4820, 4195, 4250, 4203, 4209, 4239, 4231]'])
+ self.do_benchmark('dlmalloc', src, ['400', '3000'], '*3000,0*')
def test_zlib(self):
src = open(path_from_root('tests', 'zlib', 'benchmark.c'), 'r').read()
@@ -11220,12 +11507,12 @@ elif 'sanity' in str(sys.argv):
f = open(CONFIG_FILE, 'a')
f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n')
f.close()
- output = self.check_working([EMCC, '-O2', 'tests/hello_world.cpp'], CLOSURE_FATAL)
+ output = self.check_working([EMCC, '-O2', '--closure', '1', 'tests/hello_world.cpp'], CLOSURE_FATAL)
# With a working path, all is well
restore()
try_delete('a.out.js')
- output = self.check_working([EMCC, '-O2', 'tests/hello_world.cpp'], '')
+ output = self.check_working([EMCC, '-O2', '--closure', '1', 'tests/hello_world.cpp'], '')
assert os.path.exists('a.out.js')
def test_llvm(self):
@@ -11427,7 +11714,7 @@ fi
try_delete(basebc_name) # we might need to check this file later
try_delete(dcebc_name) # we might need to check this file later
for ll_name in ll_names: try_delete(ll_name)
- output = self.do([EMCC, '-O' + str(i), '--closure', '0', '-s', 'RELOOP=0', '--llvm-lto', '0', path_from_root('tests', filename)])
+ output = self.do([EMCC, '-O' + str(i), '-s', 'RELOOP=0', '--llvm-lto', '0', path_from_root('tests', filename)])
#print output
assert INCLUDING_MESSAGE.replace('X', libname) in output
if libname == 'libc':
@@ -11475,7 +11762,7 @@ fi
print >> sys.stderr, phase, i
opt = min(i, 2)
try_delete('a.out.js')
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '--closure', '0'],
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt)],
stdout=PIPE, stderr=PIPE).communicate()
self.assertContained('hello, world!', run_js('a.out.js'))
output = '\n'.join(output)
@@ -11530,12 +11817,12 @@ fi
(['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []),
([], 'hello_libcxx.cpp', False, False, False, False, False, False, []),
# finally, build a file close to the previous, to see that some chunks are found in the cache and some not
- (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, False, []), # win on pre, mix on funcs, lose on jsfuncs
+ (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, True, []), # win on pre, mix on funcs, mix on jsfuncs
(['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []),
]:
print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
self.clear()
- out, err = Popen([PYTHON, EMCC, '-O2', '--closure', '0', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ out, err = Popen([PYTHON, EMCC, '-O2', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
errtail = err.split('emcc invocation')[-1]
self.assertContained('hello, world!', run_js('a.out.js'), errtail)
assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail
diff --git a/tests/s3tc_crunch.png b/tests/s3tc_crunch.png
index 3510b83b..067be7aa 100644
--- a/tests/s3tc_crunch.png
+++ b/tests/s3tc_crunch.png
Binary files differ
diff --git a/tests/screenshot-fog-density.png b/tests/screenshot-fog-density.png
index cd1f6f1b..60f0c9ef 100644
--- a/tests/screenshot-fog-density.png
+++ b/tests/screenshot-fog-density.png
Binary files differ
diff --git a/tests/screenshot-fog-exp2.png b/tests/screenshot-fog-exp2.png
index cd5e6a63..4737a536 100644
--- a/tests/screenshot-fog-exp2.png
+++ b/tests/screenshot-fog-exp2.png
Binary files differ
diff --git a/tests/screenshot-fog-linear.png b/tests/screenshot-fog-linear.png
index 57534566..747c0c25 100644
--- a/tests/screenshot-fog-linear.png
+++ b/tests/screenshot-fog-linear.png
Binary files differ
diff --git a/tests/screenshot-fog-negative.png b/tests/screenshot-fog-negative.png
index 5b18a201..747063c9 100644
--- a/tests/screenshot-fog-negative.png
+++ b/tests/screenshot-fog-negative.png
Binary files differ
diff --git a/tests/screenshot-fog-simple.png b/tests/screenshot-fog-simple.png
index 527768fc..7624076c 100644
--- a/tests/screenshot-fog-simple.png
+++ b/tests/screenshot-fog-simple.png
Binary files differ
diff --git a/tests/screenshot-gray-purple.png b/tests/screenshot-gray-purple.png
index 514b29a1..eaf08e6a 100644
--- a/tests/screenshot-gray-purple.png
+++ b/tests/screenshot-gray-purple.png
Binary files differ
diff --git a/tests/screenshot-gray.png b/tests/screenshot-gray.png
index 16e45a7a..af06c256 100644
--- a/tests/screenshot-gray.png
+++ b/tests/screenshot-gray.png
Binary files differ
diff --git a/tests/sdl_gl_read.c b/tests/sdl_gl_read.c
index 552eb8c0..d752f94d 100644
--- a/tests/sdl_gl_read.c
+++ b/tests/sdl_gl_read.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
GLuint programObject;
int width = 512;
@@ -118,8 +119,14 @@ void Draw ()
}
void Verify() {
- unsigned char *data = malloc(width*height*4);
+ unsigned char *data = malloc(width*height*4 + 16);
+ int *last = (int*)(data + width*height*4 - 4);
+ int *after = (int*)(data + width*height*4);
+ *last = 0xdeadbeef;
+ *after = 0x12345678;
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ assert(*last != 0xdeadbeef); // should overwrite the buffer to the end
+ assert(*after == 0x12345678); // nothing should be written afterwards!
// Should see some blue, and nothing else
int seen = 0;
int ok = 1;
diff --git a/tests/sdl_image_jpeg.c b/tests/sdl_image_jpeg.c
new file mode 100644
index 00000000..10619dad
--- /dev/null
+++ b/tests/sdl_image_jpeg.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <assert.h>
+#include <emscripten.h>
+
+int testImage(SDL_Surface* screen, const char* fileName) {
+ SDL_Surface *image = IMG_Load(fileName);
+ if (!image)
+ {
+ printf("IMG_Load: %s\n", IMG_GetError());
+ return 0;
+ }
+ assert(image->format->BitsPerPixel == 32);
+ assert(image->format->BytesPerPixel == 4);
+ assert(image->pitch == 4*image->w);
+ int result = image->w;
+
+ SDL_BlitSurface (image, NULL, screen, NULL);
+ SDL_FreeSurface (image);
+
+ return result;
+}
+
+int main() {
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_SWSURFACE);
+
+ int result = 0;
+ result = testImage(screen, "screenshot.jpeg"); // relative path
+ assert(result != 0);
+ result |= testImage(screen, "/screenshot.jpeg"); // absolute path
+ assert(result != 0);
+
+ SDL_Flip(screen);
+
+ printf("you should see an image.\n");
+
+ SDL_Quit();
+
+ REPORT_RESULT();
+
+ return 0;
+}
+
diff --git a/tests/websockets.c b/tests/websockets.c
index 59acbd69..34aa44b4 100644
--- a/tests/websockets.c
+++ b/tests/websockets.c
@@ -82,7 +82,7 @@ void iter(void *arg) {
printf("sum: %d\n", sum);
#if EMSCRIPTEN
- assert(not_always_data == 1);
+ //assert(not_always_data == 1);
int result = sum;
REPORT_RESULT();
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 7e196efd..bfa8e2f0 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -228,7 +228,7 @@ if has_preloaded:
curr = open(file_['localname'], 'rb').read()
file_['data_end'] = start + len(curr)
if AV_WORKAROUND: curr += '\x00'
- print >> sys.stderr, 'bundling', file_['name'], file_['localname'], file_['data_start'], file_['data_end']
+ #print >> sys.stderr, 'bundling', file_['name'], file_['localname'], file_['data_start'], file_['data_end']
start += len(curr)
data.write(curr)
data.close()
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index efbfa8aa..f2dc516a 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1598,7 +1598,7 @@ function registerize(ast) {
fun[2].push(reg);
}
}
- getStatements(fun).unshift(['var', vars]);
+ if (vars.length > 0) getStatements(fun).unshift(['var', vars]);
}
} else {
//printErr('unfake params: \n\n' + astToSrc(fun) + '\n\n');
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index f2e610d0..cbf64486 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -88,10 +88,11 @@ def run_on_js(filename, passes, js_engine, jcache):
if i < len(parts)-1: func += '\n}\n' # last part needs no }
m = func_sig.search(func)
if m:
- ident = m.group(1)
+ ident = m.group(2)
else:
if suffix: continue # ignore whitespace
ident = 'anon_%d' % i
+ assert ident
funcs.append((ident, func))
parts = None
total_size = len(js)
diff --git a/tools/shared.py b/tools/shared.py
index c283c1f5..ce9001fb 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -566,12 +566,10 @@ class Settings:
if opt_level >= 2:
Settings.RELOOP = 1
if opt_level >= 3:
+ # Aside from these, -O3 also runs closure compiler
Settings.INLINING_LIMIT = 0
Settings.DOUBLE_MODE = 0
Settings.PRECISE_I64_MATH = 0
- Settings.CORRECT_SIGNS = 0
- Settings.CORRECT_OVERFLOWS = 0
- Settings.CORRECT_ROUNDINGS = 0
if noisy: print >> sys.stderr, 'Warning: Applying some potentially unsafe optimizations! (Use -O2 if this fails.)'
global Settings
@@ -665,6 +663,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
def make(args, stdout=None, stderr=None, env=None):
if env is None:
env = Building.get_building_env()
+ if not args:
+ print >> sys.stderr, 'Error: Executable to run not specified.'
+ sys.exit(1)
#args += ['VERBOSE=1']
try:
Popen(args, stdout=stdout, stderr=stderr, env=env).communicate()
@@ -748,12 +749,16 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
resolved_symbols = set()
temp_dirs = []
files = map(os.path.abspath, files)
+ has_ar = False
+ for f in files:
+ has_ar = has_ar or Building.is_ar(f)
for f in files:
if not Building.is_ar(f):
if Building.is_bitcode(f):
- new_symbols = Building.llvm_nm(f)
- resolved_symbols = resolved_symbols.union(new_symbols.defs)
- unresolved_symbols = unresolved_symbols.union(new_symbols.undefs.difference(resolved_symbols)).difference(new_symbols.defs)
+ if has_ar:
+ new_symbols = Building.llvm_nm(f)
+ resolved_symbols = resolved_symbols.union(new_symbols.defs)
+ unresolved_symbols = unresolved_symbols.union(new_symbols.undefs.difference(resolved_symbols)).difference(new_symbols.defs)
actual_files.append(f)
else:
# Extract object files from ar archives, and link according to gnu ld semantics
@@ -828,6 +833,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
def llvm_opt(filename, opts):
if type(opts) is int:
opts = Building.pick_llvm_opts(opts)
+ #opts += ['-debug-pass=Arguments']
if DEBUG: print >> sys.stderr, 'emcc: LLVM opts:', opts
output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0]
assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output
@@ -864,8 +870,14 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
assert os.path.exists(output_filename), 'Could not create bc file: ' + output
return output_filename
+ nm_cache = {} # cache results of nm - it can be slow to run
+
@staticmethod
def llvm_nm(filename, stdout=PIPE, stderr=None):
+ if filename in Building.nm_cache:
+ #if DEBUG: print >> sys.stderr, 'loading nm results for %s from cache' % filename
+ return Building.nm_cache[filename]
+
# LLVM binary ==> list of symbols
output = Popen([LLVM_NM, filename], stdout=stdout, stderr=stderr).communicate()[0]
class ret:
@@ -886,6 +898,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
ret.defs = set(ret.defs)
ret.undefs = set(ret.undefs)
ret.commons = set(ret.commons)
+ Building.nm_cache[filename] = ret
return ret
@staticmethod
@@ -1086,24 +1099,6 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
@staticmethod
def is_bitcode(filename):
- # checks if a file contains LLVM bitcode
- # if the file doesn't exist or doesn't have valid symbols, it isn't bitcode
- try:
- defs = Building.llvm_nm(filename, stderr=PIPE)
- # If no symbols found, it might just be an empty bitcode file, try to dis it
- if len(defs.defs) + len(defs.undefs) + len(defs.commons) == 0:
- # llvm-nm 3.0 has a bug when reading symbols from ar files
- # so try to see if we're dealing with an ar file, in which
- # case we should try to dis it.
- if not Building.is_ar(filename):
- test_ll = os.path.join(EMSCRIPTEN_TEMP_DIR, 'test.ll')
- Building.llvm_dis(filename, test_ll)
- assert os.path.exists(test_ll)
- try_delete(test_ll)
- except Exception, e:
- if DEBUG: print >> sys.stderr, 'shared.Building.is_bitcode failed to test whether file \'%s\' is a llvm bitcode file! Failed on exception: %s' % (filename, e)
- return False
-
# look for magic signature
b = open(filename, 'r').read(4)
if b[0] == 'B' and b[1] == 'C':
@@ -1267,6 +1262,7 @@ class JCache:
if os.path.exists(chunking_file):
try:
previous_mapping = cPickle.Unpickler(open(chunking_file, 'rb')).load() # maps a function identifier to the chunk number it will be in
+ #if DEBUG: print >> sys.stderr, 'jscache previous mapping', previous_mapping
except:
pass
chunks = []
@@ -1275,20 +1271,25 @@ class JCache:
news = []
for func in funcs:
ident, data = func
+ assert ident, 'need names for jcache chunking'
if not ident in previous_mapping:
news.append(func)
else:
n = previous_mapping[ident]
while n >= len(chunks): chunks.append([])
chunks[n].append(func)
+ if DEBUG: print >> sys.stderr, 'jscache not in previous chunking', len(news)
# add news and adjust for new sizes
spilled = news
- for chunk in chunks:
+ for i in range(len(chunks)):
+ chunk = chunks[i]
size = sum([len(func[1]) for func in chunk])
- while size > 1.5*chunk_size and len(chunk) > 0:
+ #if DEBUG: print >> sys.stderr, 'need spilling?', i, size, len(chunk), 'vs', chunk_size, 1.5*chunk_size
+ while size > 1.5*chunk_size and len(chunk) > 1:
spill = chunk.pop()
spilled.append(spill)
size -= len(spill[1])
+ #if DEBUG: print >> sys.stderr, 'jscache new + spilled', len(spilled)
for chunk in chunks:
size = sum([len(func[1]) for func in chunk])
while size < 0.66*chunk_size and len(spilled) > 0:
@@ -1297,6 +1298,7 @@ class JCache:
size += len(spill[1])
chunks = filter(lambda chunk: len(chunk) > 0, chunks) # might have empty ones, eliminate them
funcs = spilled # we will allocate these into chunks as if they were normal inputs
+ #if DEBUG: print >> sys.stderr, 'leftover spills', len(spilled)
# initialize reasonably, the rest of the funcs we need to split out
curr = []
total_size = 0
@@ -1322,15 +1324,18 @@ class JCache:
for i in range(len(chunks)):
chunk = chunks[i]
for ident, data in chunk:
+ assert ident not in new_mapping, 'cannot have duplicate names in jcache chunking'
new_mapping[ident] = i
cPickle.Pickler(open(chunking_file, 'wb')).dump(new_mapping)
#if DEBUG:
+ # for i in range(len(chunks)):
+ # chunk = chunks[i]
+ # print >> sys.stderr, 'final chunk', i, len(chunk)
+ # print >> sys.stderr, 'new mapping:', new_mapping
# if previous_mapping:
# for ident in set(previous_mapping.keys() + new_mapping.keys()):
# if previous_mapping.get(ident) != new_mapping.get(ident):
# print >> sys.stderr, 'mapping inconsistency', ident, previous_mapping.get(ident), new_mapping.get(ident)
- # for key, value in new_mapping.iteritems():
- # print >> sys.stderr, 'mapping:', key, value
return [''.join([func[1] for func in chunk]) for chunk in chunks] # remove function names
class JS:
diff --git a/tools/test-js-optimizer-regs-output.js b/tools/test-js-optimizer-regs-output.js
index 36006b7c..fe7de5fb 100644
--- a/tools/test-js-optimizer-regs-output.js
+++ b/tools/test-js-optimizer-regs-output.js
@@ -225,4 +225,8 @@ function switchey(r1) {
r9 = r1 + 2;
pp(r9);
}
+function __ZN14NetworkAddressC1EPKcti(r1) {
+ __ZN14NetworkAddressC2EPKcti(r1);
+ return;
+}
diff --git a/tools/test-js-optimizer-regs.js b/tools/test-js-optimizer-regs.js
index 4802afa3..3013e518 100644
--- a/tools/test-js-optimizer-regs.js
+++ b/tools/test-js-optimizer-regs.js
@@ -230,4 +230,8 @@ function switchey(x) {
var aaa = x+2;
pp(aaa);
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["test", "primes", "atomic", "fcntl_open", "ex", "switchey"]
+function __ZN14NetworkAddressC1EPKcti($this) {
+ __ZN14NetworkAddressC2EPKcti($this);
+ return;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["test", "primes", "atomic", "fcntl_open", "ex", "switchey", "__ZN14NetworkAddressC1EPKcti"]