Check against reference images/state.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Sun, 4 Dec 2011 15:30:49 +0000 (15:30 +0000)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Sun, 4 Dec 2011 15:30:49 +0000 (15:30 +0000)
.gitignore
apps/gl/default.ref.json [new file with mode: 0644]
apps/gl/tri.ref.png [new file with mode: 0644]
apps/gl/tri.ref.txt
driver.py

index 353306b8a8878105068b9e7e7e9af7f19830ea77..a90aef1090be5dad37f0be6b738b616be08600df 100644 (file)
@@ -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 (file)
index 0000000..ab066c8
--- /dev/null
@@ -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 (file)
index 0000000..c89183b
Binary files /dev/null and b/apps/gl/tri.ref.png differ
index 460ee63886f8a095492b99779d22db76d294ea7b..724154b28ee95b786508e517fbd054d6dfc09833 100644 (file)
@@ -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
index 60699099e2b9623693131839c292f44e26df989a..27eef97074db66b0358ba78045b063abeb352baa 100755 (executable)
--- 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]