From 5a03bade408b2288bbf905b0165a5d79002a0f6a Mon Sep 17 00:00:00 2001
From: =?utf8?q?Jos=C3=A9=20Fonseca?= <jose.r.fonseca@gmail.com>
Date: Sun, 4 Dec 2011 15:30:49 +0000
Subject: [PATCH] Check against reference images/state.

---
 .gitignore               |   3 +
 apps/gl/default.ref.json | 670 +++++++++++++++++++++++++++++++++++++++
 apps/gl/tri.ref.png      | Bin 0 -> 5274 bytes
 apps/gl/tri.ref.txt      |   2 +
 driver.py                | 371 +++++++++++++++-------
 5 files changed, 925 insertions(+), 121 deletions(-)
 create mode 100644 apps/gl/default.ref.json
 create mode 100644 apps/gl/tri.ref.png

diff --git a/.gitignore b/.gitignore
index 353306b..a90aef1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
 *.o
 *.pyc
 *.so
+*.diff.*
+*.thumb.*
+index.html
 CMakeCache.txt
 CMakeFiles
 CTestTestfile.cmake
diff --git a/apps/gl/default.ref.json b/apps/gl/default.ref.json
new file mode 100644
index 0000000..ab066c8
--- /dev/null
+++ b/apps/gl/default.ref.json
@@ -0,0 +1,670 @@
+{
+  "parameters": {
+    "GL_CURRENT_COLOR": [1, 1, 1, 1],
+    "GL_CURRENT_INDEX": 1,
+    "GL_CURRENT_NORMAL": [0, 0, 1],
+    "GL_CURRENT_TEXTURE_COORDS": [0, 0, 0, 1],
+    "GL_CURRENT_RASTER_COLOR": [1, 1, 1, 1],
+    "GL_CURRENT_RASTER_INDEX": 1,
+    "GL_CURRENT_RASTER_TEXTURE_COORDS": [0, 0, 0, 1],
+    "GL_CURRENT_RASTER_POSITION": [0, 0, 0, 1],
+    "GL_CURRENT_RASTER_POSITION_VALID": 1,
+    "GL_CURRENT_RASTER_DISTANCE": 0,
+    "GL_POINT_SMOOTH": false,
+    "GL_POINT_SIZE": 1,
+    "GL_LINE_SMOOTH": false,
+    "GL_LINE_WIDTH": 1,
+    "GL_LINE_STIPPLE": false,
+    "GL_LINE_STIPPLE_PATTERN": 65535,
+    "GL_LINE_STIPPLE_REPEAT": 1,
+    "GL_LIST_MODE": "GL_ZERO",
+    "GL_LIST_BASE": 0,
+    "GL_LIST_INDEX": 0,
+    "GL_POLYGON_MODE": ["GL_FILL", "GL_FILL"],
+    "GL_POLYGON_SMOOTH": false,
+    "GL_POLYGON_STIPPLE": false,
+    "GL_EDGE_FLAG": true,
+    "GL_CULL_FACE": false,
+    "GL_CULL_FACE_MODE": "GL_BACK",
+    "GL_FRONT_FACE": "GL_CCW",
+    "GL_LIGHTING": false,
+    "GL_LIGHT_MODEL_LOCAL_VIEWER": false,
+    "GL_LIGHT_MODEL_TWO_SIDE": false,
+    "GL_LIGHT_MODEL_AMBIENT": [0.200000003, 0.200000003, 0.200000003, 1],
+    "GL_SHADE_MODEL": "GL_SMOOTH",
+    "GL_COLOR_MATERIAL_FACE": "GL_FRONT_AND_BACK",
+    "GL_COLOR_MATERIAL_PARAMETER": "GL_AMBIENT_AND_DIFFUSE",
+    "GL_COLOR_MATERIAL": false,
+    "GL_FOG": false,
+    "GL_FOG_INDEX": 0,
+    "GL_FOG_DENSITY": 1,
+    "GL_FOG_START": 0,
+    "GL_FOG_END": 1,
+    "GL_FOG_MODE": "GL_EXP",
+    "GL_FOG_COLOR": [0, 0, 0, 0],
+    "GL_DEPTH_RANGE": [0, 1],
+    "GL_DEPTH_TEST": false,
+    "GL_DEPTH_WRITEMASK": true,
+    "GL_DEPTH_CLEAR_VALUE": 1,
+    "GL_DEPTH_FUNC": "GL_LESS",
+    "GL_ACCUM_CLEAR_VALUE": [0, 0, 0, 0],
+    "GL_STENCIL_TEST": false,
+    "GL_STENCIL_CLEAR_VALUE": 0,
+    "GL_STENCIL_FUNC": "GL_ALWAYS",
+    "GL_STENCIL_VALUE_MASK": -1,
+    "GL_STENCIL_FAIL": "GL_KEEP",
+    "GL_STENCIL_PASS_DEPTH_FAIL": "GL_KEEP",
+    "GL_STENCIL_PASS_DEPTH_PASS": "GL_KEEP",
+    "GL_STENCIL_REF": 0,
+    "GL_STENCIL_WRITEMASK": -1,
+    "GL_MATRIX_MODE": "GL_MODELVIEW",
+    "GL_NORMALIZE": false,
+    "GL_VIEWPORT": [0, 0, 32, 32],
+    "GL_MODELVIEW_STACK_DEPTH": 1,
+    "GL_PROJECTION_STACK_DEPTH": 1,
+    "GL_TEXTURE_STACK_DEPTH": 1,
+    "GL_MODELVIEW_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_PROJECTION_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_TEXTURE_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_ATTRIB_STACK_DEPTH": 0,
+    "GL_CLIENT_ATTRIB_STACK_DEPTH": 0,
+    "GL_ALPHA_TEST": false,
+    "GL_ALPHA_TEST_FUNC": "GL_ALWAYS",
+    "GL_ALPHA_TEST_REF": 0,
+    "GL_DITHER": true,
+    "GL_BLEND_DST": "GL_ZERO",
+    "GL_BLEND_SRC": "GL_ONE",
+    "GL_BLEND": false,
+    "GL_LOGIC_OP_MODE": "GL_COPY",
+    "GL_INDEX_LOGIC_OP": false,
+    "GL_COLOR_LOGIC_OP": false,
+    "GL_AUX_BUFFERS": 0,
+    "GL_DRAW_BUFFER": "GL_BACK",
+    "GL_READ_BUFFER": "GL_BACK",
+    "GL_SCISSOR_BOX": [0, 0, 32, 32],
+    "GL_SCISSOR_TEST": false,
+    "GL_INDEX_CLEAR_VALUE": 0,
+    "GL_INDEX_WRITEMASK": -1,
+    "GL_COLOR_CLEAR_VALUE": [0, 0, 0, 0],
+    "GL_COLOR_WRITEMASK": [true, true, true, true],
+    "GL_INDEX_MODE": false,
+    "GL_RGBA_MODE": true,
+    "GL_DOUBLEBUFFER": true,
+    "GL_STEREO": false,
+    "GL_RENDER_MODE": "GL_RENDER",
+    "GL_PERSPECTIVE_CORRECTION_HINT": "GL_DONT_CARE",
+    "GL_POINT_SMOOTH_HINT": "GL_DONT_CARE",
+    "GL_LINE_SMOOTH_HINT": "GL_DONT_CARE",
+    "GL_POLYGON_SMOOTH_HINT": "GL_DONT_CARE",
+    "GL_FOG_HINT": "GL_DONT_CARE",
+    "GL_TEXTURE_GEN_S": false,
+    "GL_TEXTURE_GEN_T": false,
+    "GL_TEXTURE_GEN_R": false,
+    "GL_TEXTURE_GEN_Q": false,
+    "GL_PIXEL_MAP_I_TO_I_SIZE": 1,
+    "GL_PIXEL_MAP_S_TO_S_SIZE": 1,
+    "GL_PIXEL_MAP_I_TO_R_SIZE": 1,
+    "GL_PIXEL_MAP_I_TO_G_SIZE": 1,
+    "GL_PIXEL_MAP_I_TO_B_SIZE": 1,
+    "GL_PIXEL_MAP_I_TO_A_SIZE": 1,
+    "GL_PIXEL_MAP_R_TO_R_SIZE": 1,
+    "GL_PIXEL_MAP_G_TO_G_SIZE": 1,
+    "GL_PIXEL_MAP_B_TO_B_SIZE": 1,
+    "GL_PIXEL_MAP_A_TO_A_SIZE": 1,
+    "GL_UNPACK_SWAP_BYTES": false,
+    "GL_UNPACK_LSB_FIRST": false,
+    "GL_UNPACK_ROW_LENGTH": 0,
+    "GL_UNPACK_SKIP_ROWS": 0,
+    "GL_UNPACK_SKIP_PIXELS": 0,
+    "GL_UNPACK_ALIGNMENT": 4,
+    "GL_PACK_SWAP_BYTES": false,
+    "GL_PACK_LSB_FIRST": false,
+    "GL_PACK_ROW_LENGTH": 0,
+    "GL_PACK_SKIP_ROWS": 0,
+    "GL_PACK_SKIP_PIXELS": 0,
+    "GL_PACK_ALIGNMENT": 4,
+    "GL_MAP_COLOR": false,
+    "GL_MAP_STENCIL": false,
+    "GL_INDEX_SHIFT": 0,
+    "GL_INDEX_OFFSET": 0,
+    "GL_RED_SCALE": 1,
+    "GL_RED_BIAS": 0,
+    "GL_ZOOM_X": 1,
+    "GL_ZOOM_Y": 1,
+    "GL_GREEN_SCALE": 1,
+    "GL_GREEN_BIAS": 0,
+    "GL_BLUE_SCALE": 1,
+    "GL_BLUE_BIAS": 0,
+    "GL_ALPHA_SCALE": 1,
+    "GL_ALPHA_BIAS": 0,
+    "GL_DEPTH_SCALE": 1,
+    "GL_DEPTH_BIAS": 0,
+    "GL_SUBPIXEL_BITS": 4,
+    "GL_INDEX_BITS": 0,
+    "GL_RED_BITS": 8,
+    "GL_GREEN_BITS": 8,
+    "GL_BLUE_BITS": 8,
+    "GL_ALPHA_BITS": 8,
+    "GL_DEPTH_BITS": 24,
+    "GL_STENCIL_BITS": 8,
+    "GL_ACCUM_RED_BITS": 0,
+    "GL_ACCUM_GREEN_BITS": 0,
+    "GL_ACCUM_BLUE_BITS": 0,
+    "GL_ACCUM_ALPHA_BITS": 0,
+    "GL_NAME_STACK_DEPTH": 0,
+    "GL_AUTO_NORMAL": false,
+    "GL_MAP1_COLOR_4": false,
+    "GL_MAP1_INDEX": false,
+    "GL_MAP1_NORMAL": false,
+    "GL_MAP1_TEXTURE_COORD_1": false,
+    "GL_MAP1_TEXTURE_COORD_2": false,
+    "GL_MAP1_TEXTURE_COORD_3": false,
+    "GL_MAP1_TEXTURE_COORD_4": false,
+    "GL_MAP1_VERTEX_3": false,
+    "GL_MAP1_VERTEX_4": false,
+    "GL_MAP2_COLOR_4": false,
+    "GL_MAP2_INDEX": false,
+    "GL_MAP2_NORMAL": false,
+    "GL_MAP2_TEXTURE_COORD_1": false,
+    "GL_MAP2_TEXTURE_COORD_2": false,
+    "GL_MAP2_TEXTURE_COORD_3": false,
+    "GL_MAP2_TEXTURE_COORD_4": false,
+    "GL_MAP2_VERTEX_3": false,
+    "GL_MAP2_VERTEX_4": false,
+    "GL_MAP1_GRID_DOMAIN": [0, 1],
+    "GL_MAP1_GRID_SEGMENTS": 1,
+    "GL_MAP2_GRID_DOMAIN": [0, 1, 0, 1],
+    "GL_MAP2_GRID_SEGMENTS": [1, 1],
+    "GL_FEEDBACK_BUFFER_POINTER": 0,
+    "GL_FEEDBACK_BUFFER_SIZE": 0,
+    "GL_FEEDBACK_BUFFER_TYPE": "GL_2D",
+    "GL_SELECTION_BUFFER_POINTER": 0,
+    "GL_SELECTION_BUFFER_SIZE": 0,
+    "GL_POLYGON_OFFSET_UNITS": 0,
+    "GL_POLYGON_OFFSET_POINT": false,
+    "GL_POLYGON_OFFSET_LINE": false,
+    "GL_CLIP_DISTANCE0": false,
+    "GL_CLIP_DISTANCE1": false,
+    "GL_CLIP_DISTANCE2": false,
+    "GL_CLIP_DISTANCE3": false,
+    "GL_CLIP_DISTANCE4": false,
+    "GL_CLIP_DISTANCE5": false,
+    "GL_BLEND_COLOR": [0, 0, 0, 0],
+    "GL_BLEND_EQUATION": "GL_FUNC_ADD",
+    "GL_POLYGON_OFFSET_FILL": false,
+    "GL_POLYGON_OFFSET_FACTOR": 0,
+    "GL_RESCALE_NORMAL": false,
+    "GL_PACK_SKIP_IMAGES": 0,
+    "GL_PACK_IMAGE_HEIGHT": 0,
+    "GL_UNPACK_SKIP_IMAGES": 0,
+    "GL_UNPACK_IMAGE_HEIGHT": 0,
+    "GL_TEXTURE_3D": false,
+    "GL_VERTEX_ARRAY": false,
+    "GL_NORMAL_ARRAY": false,
+    "GL_COLOR_ARRAY": false,
+    "GL_INDEX_ARRAY": false,
+    "GL_TEXTURE_COORD_ARRAY": false,
+    "GL_EDGE_FLAG_ARRAY": false,
+    "GL_VERTEX_ARRAY_SIZE": 4,
+    "GL_VERTEX_ARRAY_TYPE": "GL_FLOAT",
+    "GL_VERTEX_ARRAY_STRIDE": 0,
+    "GL_NORMAL_ARRAY_TYPE": "GL_FLOAT",
+    "GL_NORMAL_ARRAY_STRIDE": 0,
+    "GL_COLOR_ARRAY_SIZE": 4,
+    "GL_COLOR_ARRAY_TYPE": "GL_FLOAT",
+    "GL_COLOR_ARRAY_STRIDE": 0,
+    "GL_INDEX_ARRAY_TYPE": "GL_FLOAT",
+    "GL_INDEX_ARRAY_STRIDE": 0,
+    "GL_TEXTURE_COORD_ARRAY_SIZE": 4,
+    "GL_TEXTURE_COORD_ARRAY_TYPE": "GL_FLOAT",
+    "GL_TEXTURE_COORD_ARRAY_STRIDE": 0,
+    "GL_EDGE_FLAG_ARRAY_STRIDE": 0,
+    "GL_VERTEX_ARRAY_POINTER": 0,
+    "GL_NORMAL_ARRAY_POINTER": 0,
+    "GL_COLOR_ARRAY_POINTER": 0,
+    "GL_INDEX_ARRAY_POINTER": 0,
+    "GL_TEXTURE_COORD_ARRAY_POINTER": 0,
+    "GL_EDGE_FLAG_ARRAY_POINTER": 0,
+    "GL_MULTISAMPLE": 1,
+    "GL_SAMPLE_ALPHA_TO_COVERAGE": 0,
+    "GL_SAMPLE_ALPHA_TO_ONE": 0,
+    "GL_SAMPLE_COVERAGE": 0,
+    "GL_SAMPLE_BUFFERS": 0,
+    "GL_SAMPLES": 0,
+    "GL_SAMPLE_COVERAGE_VALUE": 1,
+    "GL_SAMPLE_COVERAGE_INVERT": 0,
+    "GL_BLEND_DST_RGB": "GL_ZERO",
+    "GL_BLEND_SRC_RGB": "GL_ONE",
+    "GL_BLEND_DST_ALPHA": "GL_ZERO",
+    "GL_BLEND_SRC_ALPHA": "GL_ONE",
+    "GL_POINT_FADE_THRESHOLD_SIZE": 1,
+    "GL_POINT_DISTANCE_ATTENUATION": [1, 0, 0],
+    "GL_GENERATE_MIPMAP_HINT": "GL_DONT_CARE",
+    "GL_LIGHT_MODEL_COLOR_CONTROL": "GL_SINGLE_COLOR",
+    "GL_FOG_COORD_SRC": "GL_FRAGMENT_DEPTH",
+    "GL_CURRENT_FOG_COORD": 0,
+    "GL_FOG_COORD_ARRAY_TYPE": "GL_FLOAT",
+    "GL_FOG_COORD_ARRAY_STRIDE": 0,
+    "GL_FOG_COORD_ARRAY": false,
+    "GL_COLOR_SUM": false,
+    "GL_CURRENT_SECONDARY_COLOR": [0, 0, 0],
+    "GL_SECONDARY_COLOR_ARRAY_SIZE": 3,
+    "GL_SECONDARY_COLOR_ARRAY_TYPE": "GL_FLOAT",
+    "GL_SECONDARY_COLOR_ARRAY_STRIDE": 0,
+    "GL_SECONDARY_COLOR_ARRAY": false,
+    "GL_ACTIVE_TEXTURE": "GL_TEXTURE0",
+    "GL_CLIENT_ACTIVE_TEXTURE": "GL_TEXTURE0",
+    "GL_TRANSPOSE_MODELVIEW_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_TRANSPOSE_PROJECTION_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_TRANSPOSE_TEXTURE_MATRIX": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
+    "GL_TEXTURE_COMPRESSION_HINT": "GL_DONT_CARE",
+    "GL_VERTEX_ARRAY_BINDING": 0,
+    "GL_PROGRAM_POINT_SIZE": false,
+    "GL_VERTEX_PROGRAM_TWO_SIDE": false,
+    "GL_PACK_INVERT_MESA": false,
+    "GL_STENCIL_BACK_FUNC": "GL_ALWAYS",
+    "GL_STENCIL_BACK_FAIL": "GL_KEEP",
+    "GL_STENCIL_BACK_PASS_DEPTH_FAIL": "GL_KEEP",
+    "GL_STENCIL_BACK_PASS_DEPTH_PASS": "GL_KEEP",
+    "GL_DRAW_BUFFER0": "GL_BACK",
+    "GL_DRAW_BUFFER1": "GL_ZERO",
+    "GL_DRAW_BUFFER2": "GL_ZERO",
+    "GL_DRAW_BUFFER3": "GL_ZERO",
+    "GL_DRAW_BUFFER4": "GL_ZERO",
+    "GL_DRAW_BUFFER5": "GL_ZERO",
+    "GL_DRAW_BUFFER6": "GL_ZERO",
+    "GL_DRAW_BUFFER7": "GL_ZERO",
+    "GL_BLEND_EQUATION_ALPHA": "GL_FUNC_ADD",
+    "GL_ARRAY_BUFFER_BINDING": 0,
+    "GL_ELEMENT_ARRAY_BUFFER_BINDING": 0,
+    "GL_VERTEX_ARRAY_BUFFER_BINDING": 0,
+    "GL_NORMAL_ARRAY_BUFFER_BINDING": 0,
+    "GL_COLOR_ARRAY_BUFFER_BINDING": 0,
+    "GL_INDEX_ARRAY_BUFFER_BINDING": 0,
+    "GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING": 0,
+    "GL_EDGE_FLAG_ARRAY_BUFFER_BINDING": 0,
+    "GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING": 0,
+    "GL_FOG_COORD_ARRAY_BUFFER_BINDING": 0,
+    "GL_PIXEL_PACK_BUFFER_BINDING": 0,
+    "GL_PIXEL_UNPACK_BUFFER_BINDING": 0,
+    "GL_CURRENT_PROGRAM": 0,
+    "GL_POINT_SPRITE_COORD_ORIGIN": "GL_UPPER_LEFT",
+    "GL_DRAW_FRAMEBUFFER_BINDING": 0,
+    "GL_RENDERBUFFER_BINDING": 0,
+    "GL_READ_FRAMEBUFFER_BINDING": 0,
+    "GL_FRONT": {
+      "GL_AMBIENT": [0.200000003, 0.200000003, 0.200000003, 1],
+      "GL_DIFFUSE": [0.800000012, 0.800000012, 0.800000012, 1],
+      "GL_SPECULAR": [0, 0, 0, 1],
+      "GL_EMISSION": [0, 0, 0, 1],
+      "GL_SHININESS": 0,
+      "GL_COLOR_INDEXES": [0, 1, 1]
+    },
+    "GL_BACK": {
+      "GL_AMBIENT": [0.200000003, 0.200000003, 0.200000003, 1],
+      "GL_DIFFUSE": [0.800000012, 0.800000012, 0.800000012, 1],
+      "GL_SPECULAR": [0, 0, 0, 1],
+      "GL_EMISSION": [0, 0, 0, 1],
+      "GL_SHININESS": 0,
+      "GL_COLOR_INDEXES": [0, 1, 1]
+    },
+    "GL_VERTEX_ATTRIB_ARRAY0": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY1": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY2": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY3": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY4": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY5": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY6": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY7": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY8": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY9": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY10": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY11": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY12": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY13": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY14": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_VERTEX_ATTRIB_ARRAY15": {
+      "GL_VERTEX_ATTRIB_ARRAY_ENABLED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_SIZE": 4,
+      "GL_VERTEX_ATTRIB_ARRAY_STRIDE": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_TYPE": "GL_FLOAT",
+      "GL_CURRENT_VERTEX_ATTRIB": [0, 0, 0, 1],
+      "GL_VERTEX_ATTRIB_ARRAY_POINTER": 0,
+      "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED": false,
+      "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 0
+    },
+    "GL_TEXTURE_FILTER_CONTROL": {
+      "GL_TEXTURE_LOD_BIAS": 0
+    },
+    "GL_TEXTURE0": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE1": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE2": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE3": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE4": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE5": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE6": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE7": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE8": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE9": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE10": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE11": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE12": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE13": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE14": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    },
+    "GL_TEXTURE15": {
+      "GL_TEXTURE_1D": false,
+      "GL_TEXTURE_BINDING_1D": 0,
+      "GL_TEXTURE_2D": false,
+      "GL_TEXTURE_BINDING_2D": 0,
+      "GL_TEXTURE_3D": false,
+      "GL_TEXTURE_BINDING_3D": 0,
+      "GL_TEXTURE_RECTANGLE": false,
+      "GL_TEXTURE_BINDING_RECTANGLE": 0,
+      "GL_TEXTURE_CUBE_MAP": false,
+      "GL_TEXTURE_BINDING_CUBE_MAP": 0
+    }
+  },
+  "shaders": {},
+  "uniforms": {},
+  "textures": {},
+  "framebuffer": {}
+}
diff --git a/apps/gl/tri.ref.png b/apps/gl/tri.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..c89183ba9de557ad6c201fd2652887e8a766b4e4
GIT binary patch
literal 5274
zcmb7Ic{o&k*q$-=C84p5tx$@Ph)S|#eeJuf*&<#`jG3viOnQ6mG$d^pQkX1}G0a$B
zyrE)*Fw<xvTbeN?TVwgo^lkrr*Y#a<ojG&n`aRFNpZk7(_j9h3>Fj7NCJYk>fk0xm
zHWseH`4{&P<N>|~^4>)PCvbwRwK=GMSYa8s;19O5wgByOKe&#nLf{{vIGf7}AdrX@
z_W*+)J(1;x!fhQa1!$tYVh4|ImR}15feyiJEzI0eRA$MIZ~m6h*CRW}v!R+C*NtZ%
z(!zAK?5>^Q6Ha!<4Ro#^`HRshQK9><Y)H=keht3#sQqRnIG}Mj<Lv!p=w0S7>u3&o
z75S+n;p*^1!_Aph+x-fi&kMusAl8$Fi?4q^-w?dDWR>$7diW(>Lhw%{FAq)eRyV@>
z|F~r4QSvnDd?=wQR*8_?6m)U!Ol7_;iZ6365?QLtHv?Ikfi^engp`@c=s@7H34SZX
zXZRby@KssrzWA2RNRK9%PLq4{aXM7ETM@p>KkX3oYuWMnOP#Vih7b}_t3Dz8Jzhi(
zqy&#OrcUmZ@0n~&=zUKy-Q4JlNAj<KB0$(UboO+>gFTbm>RXdeukCo~w1bo6v78gf
z7F@t6N=HdV;C2;1JGL~-i;rYz6a%lScYMkNM0rtId|O1v9uWxrG0d>7P#{a0yS^i|
ztb6rlcUOYsjQr9}duxA5>yP?m%qP%=rI|mPix-^-e};M671XYlW)KBPh9_bY)N`DE
zCnQe?B$_su^mOfCYd5EK$X!o2N(qKRF#>eo?2SypaL8WoGZYqwW?e7#J%2J+xcfG%
z&XNpbET3(6q!@o{r78NBScQR7<~!8>(#N4YLmMugg|OWZLJ{9&+dU}8uUjXzzS}<i
z#gmdaD+DHmXCfN(@v#Mo9#gh<>=?7n_SuWb=2RF#i4EDeJ#4!9(UG|q{_~gAh4tOW
z6@@#7qNGJh@m3{=yTAU1q)Z420KnEl(a9yMbG(5q9n71??N=$uKfmLA+kez|7}$N~
z+uGX)flw4<!)DG^+YU!|^TG&2DCGwhHI3sOp9@0vZRtlIVu(S*)D-}MMkJVxn5wku
zeAZD+V5&sGxuuJbP<>h|z4Zwv1$H!2xJuQBisQLgXaAZ6r3`&Wt>MsLQEwFu-cAnl
zCz*5s{2RM9zX7H2{1XN0>M2L<<Ip73N3Gfof*vUF-&pQlvY71(krU#7f1CNrj5hSi
zumsWF`U+VGl>^C>;(xEn16Apnp$EVnI|9ApOY7=e4$@anm?G(@A;tFdxiFC}AwdC#
z*{1!dHVF6`4oP{n?R}8quUU#%%N6RlCAZac@GmY@gV6lW;0A}MP2jHn3$-Fk+R7uX
zxBp3E66&gfRwz}aTE<rsuDL5Q9D<0CvM0dwqjQ&$S8^IUTA*hX*n$*)Fw^{;dzXIX
z`lm-i`{OYQhd&6yi-i^sFtYeFK4rmpP`pd^-H37p4fR}~)HG!ZUo6o?S{R<63ytYI
zHEKF2{*~p8!n__;gnOBjMHwsFqjDIX^`6yJ0&n<8>8}%FhPPDX4>5MNN0Y%OU%&@(
z=(l(5k9exh6(3#aN$T&;FS!~rVY+!2)x$K>&4me~9Pc+Pv5UkpAUb3;;19~d?u4N$
zk)S}M(QDL`wTer_*~K4ggRDah7~5f|JTR{ZE>ir(nLL=q$#Vzz+7|~pmpNDX%#fc@
z{Y?K7tNAScKG5neNRUD=W3KbA^Cd+bK?^Z1>s=22b|;LNzA|@)SmgvO(u5rZwU0m#
z^1#C@=)~d1PT|wF!;L=$c23)qS4zF@DIFR!ap)}$wXNdT@otVE7z}XVT|?i`_;WUi
z*=ZtJ_r6gN`MMyDHUIrNE!VzB<+zvrK|xfR=3$^47O}<|xMRbU0sFUGfrK3U+LKEc
zWn<eO0(I0!V8pgC<uq?c3SEGC8k0}{FF6;hUUuR*k5I3fu(_zkEPh!N*&iT4Q>DZs
zQqwh|zs9OhV-|-)>p(j*<SSS+q)G*no`VWB^3rFl-yRZR7`PrW-Rv}moha0`(oX-1
zwF<kSBq1?<S?}eze-($rDs=5c3@YG1DM}Er!lO4x*}te^@zsa);k2jNq2ba4B&6ZR
zxUy5bGN-Yf2;FY9324$ll!ScnO}G;Q?iLWGZ#eQy?LNQ7^3VClK{N5X<u589Xe0?#
zA1w=CJx(o3VgeNpE0NyW^Grby{B)z1NxI{mM-9fpY_t9J&(y!oHuEa{LF_PIG2W!5
z{h-#CAS0wTr9-pvKCRq&gCM|jaaJlVN}iui?nT^Eh>V66(W_y45`Fh}IC$mmVHy}7
zn_A0k(Wy*gx?4IMFrKbv068cfA`!)FgvXEcNSSMd^fHEVc#~4Q;?m55_hhs$Dx3c}
z^-MQZYyhOBciC+7$6EXsp_#cHR$^N5qh+s+)#`IS%1v5JGsE5^(Qc<KA%~b;?khm~
z<upKycZZ8Eg*|t1c+ya^^7M=6^3)|FKb<CBNcVi<1lUTr<ULJTMwcoNgY1ZGREWIW
zK=0e8wjnM4>{h-Ag~vM8u0FRSwW|0-{6;~R;?aBzBm2!I$34^}2Edw--qHk4?Yoad
z%LixCD)e(TeAT3QP*|gi>rQ-t3#&bgtkKf@0uFeI9b%`)6!WBfU%;VXg+PdxEnyx8
z=|hnA0Yw*oNf2gLmj29LE9IQ~5BnzJdFQCH>h{-qq4_hS@Yu*dmkjCvyRd)+V~R<t
z6}WO*QLZ}<9Wto>EK*{fU}xYew?|=;tTfPXkKxd3!6C%PaF|Dn&2uHTuHh+&iJ&Zr
zIcfvUC@2%AU5^SR|B1~3F$CZ}ucLW^Ib)D04^7k7z7|MEs6yr0C4(<o?y;=K`=2qQ
zCSxiqT7kSff8)@4!3jjOo=w7=1unYTbK`N{;x|B)4&4YRTx1X=;9NRPa4YMUvU-vN
ze8ji~?v~{YboPYgGB?W)o}_sQhPD0FxCDRa`)y!Z{JC+edS#OnJ4@iDx&xTLmRrLL
zIkXs+e?d7RnTc)r?A?uw4Gny;R2ncLxf+$<EXHjN>y478i%X>;e=;wUevFrT|5tjL
zFlto*MAx$<KgiasYw#yyvu0s6->ww`vn$xwu<dUAb)g04-S^ehT=%1x@J?m!G{|nQ
zaE%Wn+dkw42ul9f+H}(|7)>l~ZSd!3&xivJXJH&f;Q+{j$bJvY-47H^iFZqi{bdrg
z#Ayt#6CveaM8H?1UA47UebjmtN&er7X||Y*O$cc*Z9~Cb>w72SX$fxz+GOKNqUol~
zzr!)nx`AX1_0-DW_$tDTaA@s_5wi(b->b4bs8K7tcXyeg5M0^8J|XHTn_yj<{}dGa
zMZV_zfi3<qV`~o)p|?MM*SxS{59U%2AEoJr>UfL5ofOCD-lqf6U$)O4WJl(@yI^8l
zu~%ywBSxGiR2KhJKph1%7EB-O7qy058$ao;72k;fER1GjIohO1F<!o7kHAX<>SO=l
zSsFlm>*rf4RY4?L2K{g&*l?%>`I_TCEfA7=N7RVTM8zC8W!63Bl-)&MdSb|P4vxz$
z-Upt<1h^ILCiV-Md~j|S0R{XqVIGgPXle;MF+I!%AS`omWY2F4Gn$oten58}jkk73
zSbX^18rl3Q`kAa?{Cy#LeZL9w#&hF6%I<qKIa|*Y(|I*FK<H^Sj-2%E^NiO2#Om*4
z)Y5G{AX^9rI4tS_b<K@X`GXK;=<4!OCU5s!su^-{>P?56O<OCkhgQvRaF@WJNZ4et
za`fN$`^}vQrj<t4W1BFOeS;-!DNZX<q_7Nsl$B)v*3+G7g_rCmUO%?ttx72c8g@K9
z;PIDS_d}a^Lb|r3mz3l=r2RvH@V~c=hakgpHG?X!)%YA|tm+|hZQeNqtdnfr$G=nj
ziI?6R(t^GXz&_8lVEJ?1nja+yqU_6K#`w{Me>@+s8(~x-jR%*`d=rrUMZ{iPIC9OM
zH8<VR2_~iYrLfk`hx(r_bG!dldW@!_Yd=}mbn{g6VpZf3u!mieq$v@r;nNbLlPU&Z
z><6<ZxXV|$65#~^XOYMpM3^EsYW%Gxg1@+HsXhPgMkS1Ap+>zTmecB6ngM+D<dAx_
z<=g(Ep~-rHP`)iSqy-a{bRS;qN>KaBW%MC$uDffKqQ=0X4SAj0taaUy4tIdp_rUPU
z4ow1=vGX!GcOWEAg|Uu@$Y70+MKbdkQ&9q`Qnb5}jYE4Vd<!^PS${Wo=Ynbh;(9+%
zfLi(=6-|mC$?4_BGQT4ZB{7?%YIs2=jNAJkL~!UEC*wwBj+uCftmWB|v5|*!H7;T`
zq}ewXJ@hKjd3fmpH-c=Nk;=4{M!~C^q60fy8wohhm6LEy;Tp|QGY>n8A{MYR+d+iQ
zK)>@QfX(ZfOM(mG?h|~!MRAblbC=#iikZ0c9uW#L>3qcl50px8OO<i;8c4(6&j9kO
zJf!O55voNp3{7Pae3g86&=F{6{C%}fMBxUv+K{dlQ($^qvI2#Yn6qm+D9q$0A={~P
z7TkG6mGf`BDH_;P07`(sH;$FTpqYeYE1RXv^Ync9$gwp-_K4mOp7yJ%9%mVRVMb4M
zo(zu}*EP^9*SU1d&1bp?V8X@ddwV8iyUl)<-2DhlMKbp`kz-r~JA#qXIu!kZ!gP7>
zA73gl*w$+CMih7sP*bO2wGYjADsyh9!m%vtwkn7Pq_Qs3h0RU-9n|1_oO-xBKlcE0
zyT-@HapJUgA?)#`qvxjcG9C4bpSiT<ho^4AiA$Y*#?X_n!^R%jkGM`XB*TupQ{e#K
z$yh2a$6Jm~It~K<9C-Glxyy#oo^|S~Fg-ufiR*)A9@$OY2)q*8N?+)p7HwISp8F(Q
zv$N2osG+2QLk&}Rop|mtjoJS$#jN7EZdx3fpOthcsD0-G^Z*BxWAT}oGJWCZaD%vP
z$;4l|O<8t}QWxU+m`+No{%7k5v|ZGuVZm?1k^IHArlEa^TU2FMV2{BV{ecSkmhbp2
z4ec7IILW$RRTUM^*z22%PO+a6COyVq3#}aLA|;-LTa+i8KI%k#&vc*FoEm=ou-a<m
zma@gM6Y5X$`_G5nmNyniIXsaS`6a$OQZpiTBZ9V+Qh@F=$;I!24cTJFPqXd5<k@UU
zJt?%BufIZTAuo5`9SmkjXQp(|U+ypZ`Wx<uGOMJ+&aQ=Xf^|e!rg)hD-JAYrFU<%h
zJ#$_!EyIx~JhHKFgn`ohZR;-sYu8Q7BfiMwZ3t5XFO2h($`+JF*9cL>&wUG+dwzbA
zNDDyp@0wFty>DCH(Ap4UHN?XYd+u=NNhp$!sk2WtO1^rV$dO~+k_AS%e4Z$S&);td
zh$>?MQE{Zrz=2TRxa{-J{m_Syf;X<$y(oKM_hxFyhVkUGWtI+LPJls1SI<h`V+wxw
zJg?j2be-JL9yJohkRCj`{i<#@a%(`Jv%<NlzB>AnnbN|^z6Z!Grmn!2^SmxJgy3Ca
zH$5CYZwqDK5c{aork2|B8(+B-djQ(p)kZ|l2INk&7D?#PWF|HGEVqC4#`k!|!54Dl
z`Q(c{-Z@YFWB>GnNomBxa?=Av53TBMw7WFmcA3WSaGY&cj2O491LEAf$<a0He`-$M
z?R|@PLt8<JHrj(_(NLKhuj@wx%s6E7O}p^04!RB;`E{F0pv5JD8$7R8?+UR*P(xvS
zuc|n4qum4iF<8F>6PiZ-fWlp>I_irs_0y+OBLw0(ZC3@E-oh=dD&@xMS}q?phOYDc
zs6l3cCQP=cTT4>0wJ03w6?(vCTk3)|JGHfg80v_i?FJ)#VZTA1d6D&|vVQiDuC#OS
zlM`WQfO+tr6c$Y306nmp5zM-dnLWAaO}md;Cw|j0eosT&Y&vg29knC80FdD_VO~&I
z{jcD>v#sMqaK+f$cbCo36IyMQU038Q@60<myrsKzaR{_HqC6t6sl<Mj?tm@9TbfB1
z`$LPz`5o4Ul-klZ9zDL9y^x0@2QI{jN{RKwIx`Iv-p5_fRND?SjKDjwx1et^tnvzQ
z|1IApdHoS!(}+FV_}#lr@;B4p$xkEpbI4}3edebI8(Pc~YGz$E54}s}v$oyLyf!}i
z!pG(ZB=7he4ed53wnCUuk!C~#xsw>TC)mPS{8%P(LZ<jiK_E#?ovfi97Kq-{JPRX<
z+da*5oiP8Q9CyzbTKrQTHRnmu4xI6Qd3YJIpXM6?jFg-Rs8<SvsP>|@V2ipI*fS1q
z*dXLvO_=)tK~6w*>ZnrHv34&?z<$-t&Lzp{O`W!tK0m)Sy!1PRCnxc(J|?GgU!@5x
zv#{LFeuOT5cBnkd?yJ-jwRqE~0cPkqWwd}IzLVZHdw;vq#qEX9Pg)!gSchl^SP6`n
z2JUIdc<aoydTGapLA!IA_vNfQ%5dhRZ@nlp?e@j2z=X+P9O_t&k1OGGPHonUb=5I*
zFX!!3y*~+6&ID(Y_*t08f5TMqq|DrOh~2l;pzX#Z69KDp1$K36cP=i=E<wdZ#M3#O
z71W8~VvJ`<2Zj2Opv}a<iN^_*Y(&>T{?G+rjQ5s{3dEe?P<_vwb_nL1UsmEie)SFl
z8xvUn721ppn5H2crx5$3SGocx0f~nq8J-1>UH5bB3w_N3BRBt_FW%BJmQqLVBC=LY
T20VZlhag)^M~iy%D{21$BY;GB

literal 0
HcmV?d00001

diff --git a/apps/gl/tri.ref.txt b/apps/gl/tri.ref.txt
index 460ee63..724154b 100644
--- a/apps/gl/tri.ref.txt
+++ b/apps/gl/tri.ref.txt
@@ -1,3 +1,4 @@
+#state default.ref.json
 glClearColor(red = 0.3, green = 0.1, blue = 0.3, alpha = 1)
 glViewport(x = 0, y = 0, width = 250, height = 250)
 glMatrixMode(mode = GL_PROJECTION)
@@ -14,3 +15,4 @@ glColor3f(red = 0, green = 0, blue = 0.7)
 glVertex3f(x = 0, y = 0.9, z = -30)
 glEnd()
 glFlush()
+#image tri.ref.png
diff --git a/driver.py b/driver.py
index 6069909..27eef97 100755
--- a/driver.py
+++ b/driver.py
@@ -35,6 +35,33 @@ import shutil
 import subprocess
 import sys
 import time
+import json
+import base64
+
+from PIL import Image
+
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
+
+
+def _exit(status, code, reason=None):
+    if reason is None:
+        reason = ''
+    else:
+        reason = ' (%s)' % reason
+    sys.stdout.write('%s%s\n' % (status, reason))
+    sys.exit(code)
+
+def fail(reason=None):
+    _exit('FAIL', 1, reason)
+
+def skip(reason=None):
+    _exit('SKIP', 0, reason)
+
+def pass_(reason=None):
+    _exit('PASS', 0, reason)
 
 
 def popen(command, *args, **kwargs):
@@ -62,6 +89,105 @@ def _get_build_program(program):
         program += '.exe'
     return _get_build_path(program)
 
+def _get_source_path(path):
+    cache = _get_build_path('CMakeCache.txt')
+    for line in open(cache, 'rt'):
+        if line.startswith('CMAKE_HOME_DIRECTORY:INTERNAL='):
+            _, source_root = line.strip().split('=', 1)
+            return os.path.join(source_root, path)
+    return None
+
+
+class TraceChecker:
+
+    def __init__(self, srcStream, refFileName, verbose=False):
+        self.srcStream = srcStream
+        self.refFileName = refFileName
+        if refFileName:
+            self.refStream = open(refFileName, 'rt')
+        else:
+            self.refStream = None
+        self.verbose = verbose
+        self.doubleBuffer = False
+        self.callNo = 0
+        self.refLine = ''
+        self.images = []
+        self.states = []
+
+    call_re = re.compile(r'^([0-9]+) (\w+)\(')
+
+    def check(self):
+
+        swapbuffers = 0
+        flushes = 0
+
+        srcLines = []
+        self.consumeRefLine()
+        for line in self.srcStream:
+            line = line.rstrip()
+            if self.verbose:
+                sys.stdout.write(line + '\n')
+            mo = self.call_re.match(line)
+            if mo:
+                self.call_no = int(mo.group(1))
+                function_name = mo.group(2)
+                if function_name.find('SwapBuffers') != -1:
+                    swapbuffers += 1
+                if function_name in ('glFlush', 'glFinish'):
+                    flushes += 1
+                srcLine = line[mo.start(2):]
+            else:
+                srcLine = line
+            if self.refLine:
+                if srcLine == self.refLine:
+                    self.consumeRefLine()
+                    srcLines = []
+                else:
+                    srcLines.append(srcLine)
+
+        if self.refLine:
+            if srcLines:
+                fail('missing call `%s` (found `%s`)' % (self.refLine, srcLines[0]))
+            else:
+                fail('missing call %s' % self.refLine)
+
+        if swapbuffers:
+            self.doubleBuffer = True
+        else:
+            self.doubleBuffer = False
+
+    def consumeRefLine(self):
+        if not self.refStream:
+            self.refLine = ''
+            return
+
+        while True:
+            line = self.refStream.readline()
+            if not line:
+                break
+            line = line.rstrip()
+            if line.startswith('#'):
+                self.handlePragma(line)
+            else:
+                break
+        self.refLine = line
+
+    def handlePragma(self, line):
+        pragma, rest = line.split(None, 1)
+        if pragma == '#image':
+            imageFileName = self.getAbsPath(rest)
+            self.images.append((self.callNo, imageFileName))
+        elif pragma == '#state':
+            stateFileName = self.getAbsPath(rest)
+            self.states.append((self.callNo, stateFileName))
+        else:
+            assert False
+
+    def getAbsPath(self, path):
+        '''Get the absolute from a path relative to the reference filename'''
+        return os.path.abspath(os.path.join(os.path.dirname(self.refFileName), path))
+
+
 
 class TestCase:
 
@@ -72,16 +198,26 @@ class TestCase:
     max_frames = None
     trace_file = None
 
-    expected_dump = None
+    ref_dump = None
+
+    doubleBuffer = True
+
+    verbose = False
+
+    def __init__(self):
+        self.stateCache = {}
+    
+    def runApp(self):
+        '''Run the application standalone, skipping this test if it fails by
+        some reason.'''
 
-    def standalone(self):
         if not self.cmd:
             return
 
         p = popen(self.cmd, cwd=self.cwd)
         p.wait()
         if p.returncode:
-            self.skip('application returned code %i' % p.returncode)
+            skip('application returned code %i' % p.returncode)
 
     api_map = {
         'gl': 'gl',
@@ -90,7 +226,7 @@ class TestCase:
         'egl_gles2': 'egl',
     }
 
-    def trace(self):
+    def traceApp(self):
         if not self.cmd:
             return
 
@@ -133,142 +269,127 @@ class TestCase:
                 os.remove(local_wrapper)
 
         if not os.path.exists(self.trace_file):
-            self.fail('no trace file generated\n')
+            fail('no trace file generated\n')
     
-    call_re = re.compile(r'^([0-9]+) (\w+)\(')
-
-    def dump(self):
-
+    def checkTrace(self):
         cmd = [_get_build_program('apitrace'), 'dump', '--color=never', self.trace_file]
         p = popen(cmd, stdout=subprocess.PIPE)
 
-        swapbuffers = 0
-        flushes = 0
-
-        ref_line = ''
-        src_lines = []
-        if self.ref_dump is not None:
-            ref = open(self.ref_dump, 'rt')
-            ref_line = ref.readline().rstrip()
-        for line in p.stdout:
-            line = line.rstrip()
-	    sys.stdout.write(line + '\n')
-            mo = self.call_re.match(line)
-            if mo:
-                call_no = int(mo.group(1))
-                function_name = mo.group(2)
-                if function_name == 'glXSwapBuffers':
-                    swapbuffers += 1
-                if function_name in ('glFlush', 'glFinish'):
-                    flushes += 1
-                src_line = line[mo.start(2):]
-            else:
-                src_line = line
-            if ref_line:
-                if src_line == ref_line:
-                    sys.stdout.write(src_line + '\n')
-                    ref_line = ref.readline().rstrip()
-                    src_lines = []
-                else:
-                    src_lines.append(src_line)
-
+        checker = TraceChecker(p.stdout, self.ref_dump, self.verbose)
+        checker.check()
         p.wait()
         if p.returncode != 0:
-            self.fail('`apitrace dump` returned code %i' % p.returncode)
-        if ref_line:
-            if src_lines:
-                self.fail('missing call `%s` (found `%s`)' % (ref_line, src_lines[0]))
-            else:
-                self.fail('missing call %s' % ref_line)
+            fail('`apitrace dump` returned code %i' % p.returncode)
+
+        self.doubleBuffer = checker.doubleBuffer
+
+        for callNo, refImageFileName in checker.images:
+            self.checkImage(callNo, refImageFileName)
+        for callNo, refStateFileName in checker.states:
+            self.checkState(callNo, refStateFileName)
+
+    def checkImage(self, callNo, refImageFileName):
+        srcImage = self.getImage(callNo)
+        refImage = Image.open(refImageFileName)
+
+        from snapdiff import Comparer
+        comparer = Comparer(refImage, srcImage)
+        match = comparer.ae()
+        if not match:
+            prefix = '%s.%u' % (self.getNamePrefix(), callNo)
+            srcImageFileName = prefix + '.src.png'
+            diffImageFileName = prefix + '.diff.png'
+            comparer.write_diff(diffImageFileName)
+            fail('snapshot from call %u does not match %s' % (callNo, refImageFileName))
+
+    def checkState(self, callNo, refStateFileName):
+        srcState = self.getState(callNo)
+        refState = json.load(open(refStateFileName, 'rt'), strict=False)
+
+        from jsondiff import Comparer, Differ
+        comparer = Comparer(ignore_added = True)
+        match = comparer.visit(refState, srcState)
+        if not match:
+            prefix = '%s.%u' % (self.getNamePrefix(), callNo)
+            srcStateFileName = prefix + '.src.json'
+            diffStateFileName = prefix + '.diff.json'
+            self.saveState(srcState, srcStateFileName)
+            #diffStateFile = open(diffStateFileName, 'wt')
+            diffStateFile = sys.stdout
+            differ = Differ(diffStateFile, ignore_added = True)
+            differ.visit(refState, srcState)
+            fail('state from call %u does not match %s' % (callNo, refStateFileName))
+
+    def getNamePrefix(self):
+        name = os.path.basename(self.ref_dump)
+        try:
+            index = name.index('.')
+        except ValueError:
+            pass
+        else:
+            name = name[:index]
+        return name
+
+    def saveState(self, state, filename):
+        s = json.dumps(state, sort_keys=True, indent=2)
+        open(filename, 'wt').write(s)
 
     def retrace(self):
-        retrace = self.api_map[self.api] + 'retrace'
-        args = [_get_build_path(retrace)]
-        args += [self.trace_file]
-        p = popen(args, stdout=subprocess.PIPE)
+        p = self._retrace()
         p.wait()
         if p.returncode != 0:
-            self.fail('`%s` returned code %i' % (retrace, p.returncode))
-
-    def run(self):
-        self.standalone()
-        self.trace()
-        self.dump()
-        self.retrace()
+            fail('retrace failed with code %i' % (p.returncode))
 
-        self.pass_()
-        return
+    def getImage(self, callNo):
+        state = self.getState(callNo)
+        framebuffer = state['framebuffer']
+        if self.doubleBuffer:
+            imageObj = framebuffer['GL_BACK']
+        else:
+            imageObj = framebuffer['GL_FRONT']
+        data = imageObj['__data__']
+        stream = StringIO(base64.b64decode(data))
+        im = Image.open(stream)
+        im.save('test.png')
+        return im
+
+    def getState(self, callNo):
+        try:
+            state = self.stateCache[callNo]
+        except KeyError:
+            pass
+        else:
+            return state
 
-        ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.'))
-        src_prefix = os.path.join(self.results, self.name + '.src.')
-        diff_prefix = os.path.join(self.results, self.name + '.diff.')
+        p = self._retrace(['-D', str(callNo)])
+        state = json.load(p.stdout, strict=False)
+        p.wait()
+        if p.returncode != 0:
+            fail('retrace returned code %i' % (p.returncode))
 
+        self.stateCache[callNo] = state
 
-        if not os.path.isfile(trace):
-            sys.stdout.write('SKIP (no trace)\n')
-            return
+        return state
 
+    def _retrace(self, args = None, stdout=subprocess.PIPE):
         retrace = self.api_map[self.api] + 'retrace'
-        args = [_get_build_path(retrace)]
-        if swapbuffers:
-            args += ['-db']
-            frames = swapbuffers
+        cmd = [_get_build_path(retrace)]
+        if self.doubleBuffer:
+            cmd += ['-db']
         else:
-            args += ['-sb']
-            frames = flushes
-        args += ['-s', src_prefix]
-        args += [trace]
-        p = popen(args, stdout=subprocess.PIPE)
-        image_re = re.compile(r'^Wrote (.*\.png)$')
-        images = []
-        for line in p.stdout:
-            line = line.rstrip()
-            mo = image_re.match(line)
-            if mo:
-                image = mo.group(1)
-                if image.startswith(src_prefix):
-                    image = image[len(src_prefix):]
-                    images.append(image)
-        p.wait()
-        if p.returncode != 0:
-            sys.stdout.write('FAIL (glretrace)\n')
-            return
+            cmd += ['-sb']
+        if args:
+            cmd += args
+        cmd += [self.trace_file]
+        return popen(cmd, stdout=stdout)
 
-        for image in images:
-            ref_image = ref_prefix + image
-            src_image = src_prefix + image
-            diff_image = diff_prefix + image
-            
-            if not os.path.isfile(ref_image):
-                continue
-            assert os.path.isfile(src_image)
-
-            comparer = Comparer(ref_image, src_image)
-            match = comparer.ae()
-            sys.stdout.write('%s: %s bits\n' % (image, comparer.precision()))
-            if not match:
-                comparer.write_diff(diff_image)
-                #report.add_snapshot(ref_image, src_image, diff_image)
-                sys.stdout.write('FAIL (snapshot)\n')
-                return
-
-    def fail(self, reason=None):
-        self._exit('FAIL', 1, reason)
-
-    def skip(self, reason=None):
-        self._exit('SKIP', 0, reason)
-
-    def pass_(self, reason=None):
-        self._exit('PASS', 0, reason)
-
-    def _exit(self, status, code, reason=None):
-        if reason is None:
-            reason = ''
-        else:
-            reason = ' (%s)' % reason
-        sys.stdout.write('%s%s\n' % (status, reason))
-        sys.exit(code)
+    def run(self):
+        self.runApp()
+        self.traceApp()
+        self.checkTrace()
+        self.retrace()
 
+        pass_()
 
 
 def main():
@@ -278,6 +399,11 @@ def main():
     optparser = optparse.OptionParser(
         usage='\n\t%prog [options] -- [TRACE|PROGRAM] ...',
         version='%%prog')
+    optparser.add_option(
+        '-v', '--verbose',
+        action="store_true",
+        dest="verbose", default=False,
+        help="verbose output")
     optparser.add_option(
         '-a', '--api', metavar='API',
         type='string', dest='api', default='gl',
@@ -306,7 +432,10 @@ def main():
     if not os.path.exists(options.results):
         os.makedirs(options.results)
 
+    sys.path.insert(0, _get_source_path('scripts'))
+
     test = TestCase()
+    test.verbose = options.verbose
 
     if args[0].endswith('.trace'):
         test.trace_file = args[0]
-- 
2.45.2