pkg_check_modules (GLESV2 glesv2)
endif ()
+# Check for the presence of several python packages, which are needed to build
+# generated tests.
+execute_process(
+ COMMAND ${python} -c "import PIL"
+ OUTPUT_QUIET
+ ERROR_QUIET
+ RESULT_VARIABLE IMPORT_PIL_RESULT)
+if (IMPORT_PIL_RESULT EQUAL 0)
+ set (PIL_FOUND 1)
+else ()
+ message (STATUS "python PIL module not found")
+endif ()
+
if (UNIX)
link_libraries(m)
endif (UNIX)
add_subdirectory (apps)
add_subdirectory (traces)
+# FIXME: The tests in the cli directory are intended to be high-level
+# tests of the apitrace command-line interface which would ideally be
+# portable across all platforms. However, these tests all rely on
+# doing image comparisons and the current implementation of the
+# "apitrace dump-images" command relies on direct invocation of the
+# glretrace command.
+#
+# Someday, we should have more unified commands for replaying traces,
+# dumping images, etc. At that point these cli tests should be usable
+# with all targets so that we can drop the "if (OPENGL_FOUND)"
+# condition here.
+if (OPENGL_FOUND AND PIL_FOUND)
+ add_subdirectory (cli)
+ add_subdirectory (trim_stress)
+endif ()
--- /dev/null
+These directories contain many drawing-api-specific test applications.
+
+Within each directory's CMakeLists.txt file are you will see
+definitions of tests such as the following:
+
+ add_app_test (
+ NAME "gl_default_sb"
+ TARGET gl_tri
+ ARGS -sb
+ REF default_sb.ref.txt
+ )
+
+This block specifies a test with NAME "gl_default_sb" that involves
+executing the TARGET program "gl_tri" with ARGS of "-sb". The REF
+script contains a reference trance that should result from tracing the
+given program, along with specifications for additional checks to be
+peformed.
+
+The actual execution of the test (and parsing of the REF script) is
+performed by the python program in ../app_driver.py. This driver
+program runs the application with the given arguments, performs a
+trace of the application, checks the trace against the reference
+script, and then run a "retrace" of the application (replaying the
+commands in the trace).
+
+In addition to a dump of the expected trace content, the reference
+file can contain directives to cause the driver program to perform
+additional checking. Some of the available directives are:
+
+ #image: Dump the current framebuffer image and compare against the
+ given file.
+
+ #state: Dump the current state in JSON format and compare against
+ the given file.
--- /dev/null
+!*.trace
+tri-trim.trace
+tri-out
+glxsimple-ref
+glxsimple-out
+glxsimple-trim.trace
+glxsimple-trim-unused-textures.trace
--- /dev/null
+function (ADD_CLI_TEST)
+ cmake_parse_arguments(
+ TEST
+ # Options
+ ""
+ # One value args
+ "NAME"
+ # Multi value args
+ ""
+ ${ARGN}
+ )
+
+ if (APITRACE_EXECUTABLE)
+ add_test(
+ NAME ${TEST_NAME}
+ COMMAND
+ python ${CMAKE_SOURCE_DIR}/cli_driver.py
+ --apitrace ${APITRACE_EXECUTABLE}
+ --apitrace-source ${APITRACE_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_NAME}
+ )
+ endif ()
+endfunction ()
+
+add_cli_test(NAME "cli-diff-images.script")
+add_cli_test(NAME "cli-diff-images-mismatch.script")
+add_cli_test(NAME "cli-trim-single-swapbuffers.script")
+add_cli_test(NAME "cli-trim-unused-textures.script")
+add_cli_test(NAME "cli-trim-unused-shaders.script")
--- /dev/null
+This directory tests high-level functionality of apitrace command-line
+interface (cli). See also the neighboring "traces" directory which
+also tests the cli, but in ways that can only be verified by doing
+comparisons of resulting dump files.
+
+For writing new tests, if the functionality can be exercised by a
+sequence of apitrace command invocations, and then a final comparison
+of "apitrace dump" output, then it's likely simplest to write a new
+test in the traces directory. Otherwise, a new test program can be
+written in this directory.
+
+The tests in this directory are found in files with names matching
+*.script by convention. The scripts must be listed explicitly in the
+CMakeLists.txt file. Each script consists of simple line-based
+commands with the following meanings (based on the first word of each
+line):
+
+ apitrace: Execute the current apitrace executable being tested
+ with the given arguments. If apitrace returns a
+ non-zero status, the test will fail.
+
+ expect: Compare the results of the previously-executed command
+ with the given (json-quoted) string. If the strings
+ are not identical, the test will fail.
+
+ rm_and_mkdir: Remove any existing directory of the given name and
+ then create it. The directory name is always
+ interpreted locally. If this fails for any reason
+ other than "file does not exist" the test will fail.
+
+Note: Blank lines and lines beginning with '#' are ignored.
+
+Commands can be prefixed with "EXPECT_FAILURE:" to indicate that a
+command is expected to return a non-zero value. In this case, a return
+value of zero from the command will cause the test to fail.
+
+If none of the commands in the script cause the test to fail (as
+described above), then the test will pass.
+
--- /dev/null
+EXPECT_FAILURE: apitrace diff-images --verbose images/white-1x1/ images/black-1x1/
+
+# In addition to getting the return value indicating an error, let's
+# also require that "apitrace diff-images" gave us the output we
+# expect.
+
+expect "Comparing images/white-1x1/0.png and images/black-1x1/0.png ... MISMATCH\n"
--- /dev/null
+apitrace diff-images --verbose images/white-1x1/ images/white-1x1/
+
+# Ensure that the "apitrace diff-images" actually did something. This
+# is important since if it couldn't find images in one directory or
+# the other then it would just silently return 0 and this test would
+# incorrectly pass.
+
+expect "Comparing images/white-1x1/0.png and images/white-1x1/0.png ... MATCH\n"
--- /dev/null
+# First, trim the trace to the final glxSwapBuffers call
+
+apitrace trim --auto --calls=27 tri.trace
+
+# Then dump the image and compare to our reference
+
+rm_and_mkdir ./tri-out
+apitrace dump-images --call-nos=no -o ./tri-out/tri tri-trim.trace
+apitrace diff-images -v ./tri-ref ./tri-out
+
+# In addition to getting the return value indicating no error, let's
+# also require that "apitrace diff-images" gave us the output we
+# expect.
+
+expect "Comparing ./tri-ref/tri0000000000.png and ./tri-out/tri0000000000.png ... MATCH\n"
--- /dev/null
+# Generate reference images from unmodified trace.
+
+# We carefully generate images only for desired frames (dropping the
+# first frame that draws using shaders).
+
+rm_and_mkdir glxsimple-ref
+apitrace dump-images --calls=10,47,50,71,87,88 --call-nos=no -o ./glxsimple-ref/ glxsimple.trace
+
+# Trim to the same callset used to generate reference images
+
+apitrace trim --auto --calls=10,47,50,71,87,88 glxsimple.trace
+
+# Verify that we actually trimmed what we wanted to
+
+apitrace diff --diff=python glxsimple.trace glxsimple-trim.trace
+expect r""" glXChooseVisual(37134976, 0, (GLX_RGBA, GLX_RED_SIZE, GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, GLX_BLUE_SIZE, GLX_RED_SIZE, GLX_ALPHA_SIZE, GLX_RED_SIZE, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, GLX_RED_SIZE, GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR, 0)) = ([37179128, 34, 0, 24, 5, 16711680, 65280, 255, 256, 8])
+ glXCreateContext(37134976, ([37179128, 34, 0, 24, 5, 16711680, 65280, 255, 256, 8]), 0, True) = 37241648
+ glXMakeCurrent(37134976, 41943041, 37241648) = True
+ glViewport(0, 0, 64, 64)
+ glMatrixMode(GL_PROJECTION)
+ glLoadIdentity()
+ glOrtho(0.0, 64.0, 64.0, 0.0, 0.0, 1.0)
+ glMatrixMode(GL_MODELVIEW)
+ glClearColor(0.0, 0.0, 1.0, 1.0)
+ glClear((GL_COLOR_BUFFER_BIT))
+ glXSwapBuffers(37134976, 41943041)
+- glCreateShader(GL_VERTEX_SHADER) = 7
+- glShaderSource(7, 1, ('void main()\n{\n gl_Position = ftransform();\n}\n'), 0)
+- glCompileShader(7)
+- glCreateShader(GL_FRAGMENT_SHADER) = 8
+- glShaderSource(8, 1, ('#version 120\nuniform vec4 color;\nvoid main()\n{\n gl_FragColor = color;\n}\n'), 0)
+- glCompileShader(8)
+- glCreateProgram() = 9
+- glAttachShader(9, 7)
+- glAttachShader(9, 8)
+- glLinkProgram(9)
+- glUseProgram(9)
+- glGetUniformLocation(9, color) = 0
+- glUniform4f(0, 0.0, 1.0, 0.0, 1.0)
+- glBegin(GL_QUADS)
+- glVertex2f(0.0, 0.0)
+- glVertex2f(64.0, 0.0)
+- glVertex2f(64.0, 64.0)
+- glVertex2f(0.0, 64.0)
+- glEnd()
+ glUseProgram(0)
+- glXSwapBuffers(37134976, 41943041)
+ glGenTextures(1, (1))
+ glBindTexture(GL_TEXTURE_2D, 1)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, blob(3))
+ glEnable(GL_TEXTURE_2D)
+ glBegin(GL_QUADS)
+ glTexCoord2f(0.0, 0.0)
+ glVertex2f(0.0, 0.0)
+ glTexCoord2f(1.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glTexCoord2f(1.0, 1.0)
+ glVertex2f(64.0, 64.0)
+ glTexCoord2f(0.0, 1.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glDisable(GL_TEXTURE_2D)
+ glXSwapBuffers(37134976, 41943041)
+ glClearColor(1.0, 0.0, 0.0, 1.0)
+ glClear((GL_COLOR_BUFFER_BIT))
+ glXSwapBuffers(37134976, 41943041)
+ glCreateShader(GL_VERTEX_SHADER) = 10
+ glShaderSource(10, 1, ('void main()\n{\n gl_Position = ftransform();\n}\n'), 0)
+ glCompileShader(10)
+ glCreateShader(GL_FRAGMENT_SHADER) = 11
+ glShaderSource(11, 1, ('#version 120\nuniform vec4 color;\nvoid main()\n{\n gl_FragColor = color;\n}\n'), 0)
+ glCompileShader(11)
+ glCreateProgram() = 12
+ glAttachShader(12, 10)
+ glAttachShader(12, 11)
+ glLinkProgram(12)
+ glUseProgram(12)
+ glGetUniformLocation(12, color) = 0
+ glUniform4f(0, 1.0, 0.0, 1.0, 1.0)
+ glBegin(GL_QUADS)
+ glVertex2f(0.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glVertex2f(64.0, 64.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glUseProgram(0)
+ glXSwapBuffers(37134976, 41943041)
+ glGenTextures(1, (2))
+ glBindTexture(GL_TEXTURE_2D, 2)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, blob(3))
+ glEnable(GL_TEXTURE_2D)
+ glBegin(GL_QUADS)
+ glTexCoord2f(0.0, 0.0)
+ glVertex2f(0.0, 0.0)
+ glTexCoord2f(1.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glTexCoord2f(1.0, 1.0)
+ glVertex2f(64.0, 64.0)
+ glTexCoord2f(0.0, 1.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glDisable(GL_TEXTURE_2D)
+ glXSwapBuffers(37134976, 41943041)
+ glXDestroyContext(37134976, 37241648)
+"""
+
+# Generate output images for all frames in the trimmed trace
+
+rm_and_mkdir glxsimple-out
+apitrace dump-images --call-nos=no -o ./glxsimple-out/ glxsimple-trim.trace
+
+# Compare output to reference images
+
+apitrace diff-images -v ./glxsimple-ref ./glxsimple-out
+expect r"""Comparing ./glxsimple-ref/0000000000.png and ./glxsimple-out/0000000000.png ... MATCH
+Comparing ./glxsimple-ref/0000000001.png and ./glxsimple-out/0000000001.png ... MATCH
+Comparing ./glxsimple-ref/0000000002.png and ./glxsimple-out/0000000002.png ... MATCH
+Comparing ./glxsimple-ref/0000000003.png and ./glxsimple-out/0000000003.png ... MATCH
+Comparing ./glxsimple-ref/0000000004.png and ./glxsimple-out/0000000004.png ... MATCH
+"""
--- /dev/null
+# Generate reference images from unmodified trace.
+
+# We carefully generate images only for desired frames (dropping the
+# first frame that draws using textures).
+
+rm_and_mkdir glxsimple-ref
+apitrace dump-images --calls=10,31,50,71,87,88 --call-nos=no -o ./glxsimple-ref/ glxsimple.trace
+
+# Trim to the same callset used to generate reference images
+
+apitrace trim --auto -o glxsimple-trim-unused-textures.trace --calls=10,31,50,71,87,88 glxsimple.trace
+
+# Verify that we actually trimmed what we wanted to
+
+apitrace diff --diff=python glxsimple.trace glxsimple-trim-unused-textures.trace
+expect r""" glXChooseVisual(37134976, 0, (GLX_RGBA, GLX_RED_SIZE, GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, GLX_BLUE_SIZE, GLX_RED_SIZE, GLX_ALPHA_SIZE, GLX_RED_SIZE, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, GLX_RED_SIZE, GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR, 0)) = ([37179128, 34, 0, 24, 5, 16711680, 65280, 255, 256, 8])
+ glXCreateContext(37134976, ([37179128, 34, 0, 24, 5, 16711680, 65280, 255, 256, 8]), 0, True) = 37241648
+ glXMakeCurrent(37134976, 41943041, 37241648) = True
+ glViewport(0, 0, 64, 64)
+ glMatrixMode(GL_PROJECTION)
+ glLoadIdentity()
+ glOrtho(0.0, 64.0, 64.0, 0.0, 0.0, 1.0)
+ glMatrixMode(GL_MODELVIEW)
+ glClearColor(0.0, 0.0, 1.0, 1.0)
+ glClear((GL_COLOR_BUFFER_BIT))
+ glXSwapBuffers(37134976, 41943041)
+ glCreateShader(GL_VERTEX_SHADER) = 7
+ glShaderSource(7, 1, ('void main()\n{\n gl_Position = ftransform();\n}\n'), 0)
+ glCompileShader(7)
+ glCreateShader(GL_FRAGMENT_SHADER) = 8
+ glShaderSource(8, 1, ('#version 120\nuniform vec4 color;\nvoid main()\n{\n gl_FragColor = color;\n}\n'), 0)
+ glCompileShader(8)
+ glCreateProgram() = 9
+ glAttachShader(9, 7)
+ glAttachShader(9, 8)
+ glLinkProgram(9)
+ glUseProgram(9)
+ glGetUniformLocation(9, color) = 0
+ glUniform4f(0, 0.0, 1.0, 0.0, 1.0)
+ glBegin(GL_QUADS)
+ glVertex2f(0.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glVertex2f(64.0, 64.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glUseProgram(0)
+ glXSwapBuffers(37134976, 41943041)
+- glGenTextures(1, (1))
+ glBindTexture(GL_TEXTURE_2D, 1)
+- glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, blob(3))
+ glEnable(GL_TEXTURE_2D)
+- glBegin(GL_QUADS)
+- glTexCoord2f(0.0, 0.0)
+- glVertex2f(0.0, 0.0)
+- glTexCoord2f(1.0, 0.0)
+- glVertex2f(64.0, 0.0)
+- glTexCoord2f(1.0, 1.0)
+- glVertex2f(64.0, 64.0)
+- glTexCoord2f(0.0, 1.0)
+- glVertex2f(0.0, 64.0)
+- glEnd()
+ glDisable(GL_TEXTURE_2D)
+- glXSwapBuffers(37134976, 41943041)
+ glClearColor(1.0, 0.0, 0.0, 1.0)
+ glClear((GL_COLOR_BUFFER_BIT))
+ glXSwapBuffers(37134976, 41943041)
+ glCreateShader(GL_VERTEX_SHADER) = 10
+ glShaderSource(10, 1, ('void main()\n{\n gl_Position = ftransform();\n}\n'), 0)
+ glCompileShader(10)
+ glCreateShader(GL_FRAGMENT_SHADER) = 11
+ glShaderSource(11, 1, ('#version 120\nuniform vec4 color;\nvoid main()\n{\n gl_FragColor = color;\n}\n'), 0)
+ glCompileShader(11)
+ glCreateProgram() = 12
+ glAttachShader(12, 10)
+ glAttachShader(12, 11)
+ glLinkProgram(12)
+ glUseProgram(12)
+ glGetUniformLocation(12, color) = 0
+ glUniform4f(0, 1.0, 0.0, 1.0, 1.0)
+ glBegin(GL_QUADS)
+ glVertex2f(0.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glVertex2f(64.0, 64.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glUseProgram(0)
+ glXSwapBuffers(37134976, 41943041)
+ glGenTextures(1, (2))
+ glBindTexture(GL_TEXTURE_2D, 2)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, blob(3))
+ glEnable(GL_TEXTURE_2D)
+ glBegin(GL_QUADS)
+ glTexCoord2f(0.0, 0.0)
+ glVertex2f(0.0, 0.0)
+ glTexCoord2f(1.0, 0.0)
+ glVertex2f(64.0, 0.0)
+ glTexCoord2f(1.0, 1.0)
+ glVertex2f(64.0, 64.0)
+ glTexCoord2f(0.0, 1.0)
+ glVertex2f(0.0, 64.0)
+ glEnd()
+ glDisable(GL_TEXTURE_2D)
+ glXSwapBuffers(37134976, 41943041)
+ glXDestroyContext(37134976, 37241648)
+"""
+
+# Generate output images for all frames in the trimmed trace
+
+rm_and_mkdir glxsimple-out
+apitrace dump-images --call-nos=no -o ./glxsimple-out/ glxsimple-trim-unused-textures.trace
+
+# Compare output to reference images
+
+apitrace diff-images -v ./glxsimple-ref ./glxsimple-out
+expect r"""Comparing ./glxsimple-ref/0000000000.png and ./glxsimple-out/0000000000.png ... MATCH
+Comparing ./glxsimple-ref/0000000001.png and ./glxsimple-out/0000000001.png ... MATCH
+Comparing ./glxsimple-ref/0000000002.png and ./glxsimple-out/0000000002.png ... MATCH
+Comparing ./glxsimple-ref/0000000003.png and ./glxsimple-out/0000000003.png ... MATCH
+Comparing ./glxsimple-ref/0000000004.png and ./glxsimple-out/0000000004.png ... MATCH
+"""
--- /dev/null
+*~
+glxsimple
--- /dev/null
+PROGS=glxsimple
+
+all: $(PROGS)
+
+%:%.c
+ $(CC) -Wall -Wextra -g -o $@ $^ -lGL -lX11 -lGLEW
+
+clean:
+ rm -f *.o $(PROGS)
--- /dev/null
+/**************************************************************************
+ * Copyright 2012 Intel corporation
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+int width = 64;
+int height = 64;
+
+static void
+set_2d_projection (void)
+{
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho (0, width, height, 0, 0, 1);
+ glMatrixMode (GL_MODELVIEW);
+}
+
+static void
+draw_fullscreen_quad (void)
+{
+ glBegin (GL_QUADS);
+ glVertex2f (0, 0);
+ glVertex2f (width, 0);
+ glVertex2f (width, height);
+ glVertex2f (0, height);
+ glEnd ();
+}
+
+static void
+draw_fullscreen_textured_quad (void)
+{
+ glBegin (GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f (0, 0);
+ glTexCoord2f(1, 0); glVertex2f (width, 0);
+ glTexCoord2f(1, 1); glVertex2f (width, height);
+ glTexCoord2f(0, 1); glVertex2f (0, height);
+ glEnd ();
+}
+
+static void
+paint_rgb_using_clear (double r, double g, double b)
+{
+ glClearColor(r, g, b, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static void
+paint_rgb_using_glsl (double r, double g, double b)
+{
+ const char * vs_source =
+ "void main()\n"
+ "{\n"
+ " gl_Position = ftransform();\n"
+ "}\n";
+ const char * fs_source =
+ "#version 120\n"
+ "uniform vec4 color;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+
+ GLuint vs, fs, program;
+ GLint color;
+
+ vs = glCreateShader (GL_VERTEX_SHADER);
+ glShaderSource (vs, 1, &vs_source, NULL);
+ glCompileShader (vs);
+
+ fs = glCreateShader (GL_FRAGMENT_SHADER);
+ glShaderSource (fs, 1, &fs_source, NULL);
+ glCompileShader (fs);
+
+ program = glCreateProgram ();
+ glAttachShader (program, vs);
+ glAttachShader (program, fs);
+
+ glLinkProgram (program);
+ glUseProgram (program);
+
+ color = glGetUniformLocation (program, "color");
+
+ glUniform4f (color, r, g, b, 1.0);
+
+ draw_fullscreen_quad ();
+
+ glUseProgram (0);
+}
+
+static GLuint
+create_rgb_texture (double r, double g, double b)
+{
+ uint8_t data[3];
+ GLuint texture = 0;
+
+ data[0] = (uint8_t) (255.0 * r);
+ data[1] = (uint8_t) (255.0 * g);
+ data[2] = (uint8_t) (255.0 * b);
+
+ glGenTextures (1, &texture);
+
+ glBindTexture (GL_TEXTURE_2D, texture);
+
+ glTexImage2D (GL_TEXTURE_2D,
+ 0, GL_COMPRESSED_RGBA,
+ 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, data);
+
+ return texture;
+}
+
+static void
+paint_using_texture (GLuint texture)
+{
+ glBindTexture (GL_TEXTURE_2D, texture);
+
+ glEnable (GL_TEXTURE_2D);
+
+ draw_fullscreen_textured_quad ();
+
+ glDisable (GL_TEXTURE_2D);
+}
+
+static void
+draw (Display *dpy, Window window, int width, int height)
+{
+#define PASSES 2
+ int i;
+ GLenum glew_err;
+ GLuint texture[PASSES];
+
+ int visual_attr[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 24,
+ GLX_STENCIL_SIZE, 8,
+ GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR,
+ None
+ };
+
+ /* Window and context setup. */
+ XVisualInfo *visual_info = glXChooseVisual(dpy, 0, visual_attr);
+ GLXContext ctx = glXCreateContext(dpy, visual_info, NULL, True);
+ glXMakeCurrent(dpy, window, ctx);
+
+ glew_err = glewInit();
+ if (glew_err != GLEW_OK)
+ {
+ fprintf (stderr, "glewInit failed: %s\n",
+ glewGetErrorString(glew_err));
+ exit (1);
+ }
+
+ glViewport(0, 0, width, height);
+
+ set_2d_projection ();
+
+/* Simply count through some colors, frame by frame. */
+#define RGB(frame) (((frame+1)/4) % 2), (((frame+1)/2) % 2), ((frame+1) % 2)
+
+ int frame = 0;
+ for (i = 0; i < PASSES; i++) {
+
+ /* Frame: Draw a solid frame using glClear. */
+ paint_rgb_using_clear (RGB(frame));
+ glXSwapBuffers (dpy, window);
+ frame++;
+
+ /* Frame: Draw a solid frame using GLSL. */
+ paint_rgb_using_glsl (RGB(frame));
+ glXSwapBuffers (dpy, window);
+ frame++;
+
+ /* Frame: Draw a solid frame using a texture. */
+ texture[i] = create_rgb_texture (RGB(frame));
+ paint_using_texture (texture[i]);
+ glXSwapBuffers (dpy, window);
+ frame++;
+ }
+
+ /* Draw another frame with a re-used texture. */
+ paint_using_texture (texture[0]);
+ glXSwapBuffers (dpy, window);
+ frame++;
+
+ /* Cleanup */
+ glXDestroyContext (dpy, ctx);
+}
+
+static void
+handle_events(Display *dpy, Window window, int width, int height)
+{
+ XEvent xev;
+ KeyCode quit_code = XKeysymToKeycode (dpy, XStringToKeysym("Q"));
+
+ XNextEvent (dpy, &xev);
+
+ while (1) {
+ XNextEvent (dpy, &xev);
+ switch (xev.type) {
+ case KeyPress:
+ if (xev.xkey.keycode == quit_code) {
+ return;
+ }
+ break;
+ case ConfigureNotify:
+ width = xev.xconfigure.width;
+ height = xev.xconfigure.height;
+ break;
+ case Expose:
+ if (xev.xexpose.count == 0) {
+ draw (dpy, window, width, height);
+ return;
+ }
+ break;
+ }
+ }
+}
+
+int
+main (void)
+{
+ Display *dpy;
+ Window window;
+
+ dpy = XOpenDisplay (NULL);
+
+ if (dpy == NULL) {
+ fprintf(stderr, "Failed to open display %s\n",
+ XDisplayName(NULL));
+ return 1;
+ }
+
+ window = XCreateSimpleWindow(dpy, DefaultRootWindow (dpy),
+ 0, 0, width, height, 0,
+ BlackPixel (dpy, DefaultScreen (dpy)),
+ BlackPixel (dpy, DefaultScreen (dpy)));
+
+ XSelectInput(dpy, window,
+ KeyPressMask | StructureNotifyMask | ExposureMask);
+
+ XMapWindow (dpy, window);
+
+ handle_events (dpy, window, width, height);
+
+ XDestroyWindow (dpy, window);
+ XCloseDisplay (dpy);
+
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+'''Test driver for scripts in the cli directory.'''
+
+import json
+import errno
+import shutil
+import subprocess
+import difflib
+
+from base_driver import *
+
+class CliDriver(Driver):
+
+ def do_apitrace(self, args):
+ cmd = [self.options.apitrace] + args.split()
+
+ print " ".join(cmd)
+ proc = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ self.output = proc.communicate()[0]
+
+ proc.wait()
+
+ if (self.expect_failure):
+ if (proc.returncode == 0):
+ fail("Command unexpectedly passed when expecting failure:\n " + " ".join(cmd))
+ else:
+ if (proc.returncode != 0):
+ fail("Command failed (returned non-zero):\n " + " ".join(cmd))
+
+ def do_expect(self, args):
+ expected = eval(args)
+ if (self.output != expected):
+ differ = difflib.Differ()
+ diff = differ.compare(expected.splitlines(1), self.output.splitlines(1))
+ diff = ''.join(diff)
+ fail("Unexpected output:\n%s\n" % diff)
+
+ def do_rm_and_mkdir(self, args):
+
+ args = args.split()
+
+ # Operate only on local directories
+ dir = './' + args[0]
+
+ # Failing to delete a directory that doesn't exist is no failure
+ def rmtree_onerror(function, path, excinfo):
+ if excinfo[0] == OSError and excinfo[1].errno != errno.ENOENT:
+ raise
+
+ shutil.rmtree(dir, onerror = rmtree_onerror)
+ os.makedirs(dir)
+
+ def unknown_command(self, args):
+ fail('Broken test script: Unknown command: %s' % (args))
+
+ def run_script(self, cli_script):
+ "Execute the commands in the given cli script."
+
+ commands = {
+ 'apitrace': self.do_apitrace,
+ 'expect': self.do_expect,
+ 'rm_and_mkdir': self.do_rm_and_mkdir
+ }
+
+ script = open(cli_script, 'rt')
+
+ while True:
+
+ self.expect_failure = False
+
+ line = script.readline()
+
+ # Exit loop on EOF
+ if (line == ''):
+ break
+
+ line = line.rstrip()
+
+ if " " in line:
+ (cmd, args) = line.split(None,1)
+ if args.startswith('r"""'):
+ while not line.endswith('"""'):
+ line = script.readline()
+ line = line.rstrip()
+ args += '\n' + line
+ else:
+ cmd = line
+ args = ''
+
+ # Ignore blank lines and comments
+ if (len(cmd) == 0 or cmd == '\n' or cmd[0] == '#'):
+ continue
+
+ if (cmd == 'EXPECT_FAILURE:'):
+ self.expect_failure = True
+ if " " in args:
+ (cmd, args) = args.split(None, 1)
+ else:
+ cmd = args
+ args = ''
+
+ commands.get(cmd, self.unknown_command)(args)
+
+ def run(self):
+ self.parseOptions()
+
+ self.run_script(self.args[0])
+
+ pass_()
+
+if __name__ == '__main__':
+ CliDriver().run()
!*.trace
*.src.trace
+*-trim.trace
+This directory tests various operations of the apitrace command-line
+interface (cli) operating on existings.
+
+All files with a .script extension specify a simple script for
+testing. The test driver (in ../tool_driver.py) will parse the script
+file line-by-line, interpreting each line as arguments to the apitrace
+cli interface and invoking the cli with the given arguments. This
+continues until the first line of the script beginning with the "dump"
+command.
+
+After a "dump" command in the script, the remainder of the script file
+provides the expected output of the given dump command. The tool
+driver will report a test failure if the actual dump output differs
+from that given in the.
+
+Here are descriptions of some of the trace files contained here which
+are used by the test scripts:
+
* zlib-no-eof.trace: is a short, zlib compressed trace, with an unexpected end of
file because the application terminated abnormally (which is actual very
normal).
any data from it.
* incomplete-call.trace: trace with an incomplete call, with missing arguments
+
+* glxsimple.trace: trace from a simple program showing drawing with
+ glClear, with GLSL shader, and with texture. See ../cli/src
\ No newline at end of file
--- /dev/null
+trim --frames=0-5/draw,0-5/frame glxsimple.trace
+dump --verbose glxsimple-trim.trace
+0 glClear(mask = GL_COLOR_BUFFER_BIT)
+1 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
+2 glEnd()
+3 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
+4 glEnd()
+5 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
+6 glClear(mask = GL_COLOR_BUFFER_BIT)
+7 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
+8 glEnd()
+9 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
+10 glEnd()
+11 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
--- /dev/null
+trim -o trim-head-by-frame.src.trace --auto --frames=0 glxsimple.trace
+dump --verbose trim-head-by-frame.src.trace
+0 glXChooseVisual(dpy = 0x236a280, screen = 0, attribList = {GLX_RGBA, GLX_RED_SIZE, GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, GLX_BLUE_SIZE, GLX_RED_SIZE, GLX_ALPHA_SIZE, GLX_RED_SIZE, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, GLX_RED_SIZE, GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR, 0}) = &{visual = 0x2374ef8, visualid = 34, screen = 0, depth = 24, c_class = 5, red_mask = 16711680, green_mask = 65280, blue_mask = 255, colormap_size = 256, bits_per_rgb = 8}
+1 glXCreateContext(dpy = 0x236a280, vis = &{visual = 0x2374ef8, visualid = 34, screen = 0, depth = 24, c_class = 5, red_mask = 16711680, green_mask = 65280, blue_mask = 255, colormap_size = 256, bits_per_rgb = 8}, shareList = NULL, direct = True) = 0x2384330
+2 glXMakeCurrent(dpy = 0x236a280, drawable = 41943041, ctx = 0x2384330) = True
+3 glViewport(x = 0, y = 0, width = 64, height = 64)
+4 glMatrixMode(mode = GL_PROJECTION)
+5 glLoadIdentity()
+6 glOrtho(left = 0, right = 64, bottom = 64, top = 0, zNear = 0, zFar = 1)
+7 glMatrixMode(mode = GL_MODELVIEW)
+8 glClearColor(red = 0, green = 0, blue = 1, alpha = 1)
+9 glClear(mask = GL_COLOR_BUFFER_BIT)
+10 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
--- /dev/null
+trim -o trim-head.src.trace --auto --calls=0-843 glxsimple.trace
+dump --verbose trim-head.src.trace
+0 glXChooseVisual(dpy = 0x236a280, screen = 0, attribList = {GLX_RGBA, GLX_RED_SIZE, GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, GLX_BLUE_SIZE, GLX_RED_SIZE, GLX_ALPHA_SIZE, GLX_RED_SIZE, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, GLX_RED_SIZE, GLX_X_VISUAL_TYPE, GLX_DIRECT_COLOR, 0}) = &{visual = 0x2374ef8, visualid = 34, screen = 0, depth = 24, c_class = 5, red_mask = 16711680, green_mask = 65280, blue_mask = 255, colormap_size = 256, bits_per_rgb = 8}
+1 glXCreateContext(dpy = 0x236a280, vis = &{visual = 0x2374ef8, visualid = 34, screen = 0, depth = 24, c_class = 5, red_mask = 16711680, green_mask = 65280, blue_mask = 255, colormap_size = 256, bits_per_rgb = 8}, shareList = NULL, direct = True) = 0x2384330
+2 glXMakeCurrent(dpy = 0x236a280, drawable = 41943041, ctx = 0x2384330) = True
+3 glViewport(x = 0, y = 0, width = 64, height = 64)
+4 glMatrixMode(mode = GL_PROJECTION)
+5 glLoadIdentity()
+6 glOrtho(left = 0, right = 64, bottom = 64, top = 0, zNear = 0, zFar = 1)
+7 glMatrixMode(mode = GL_MODELVIEW)
+8 glClearColor(red = 0, green = 0, blue = 1, alpha = 1)
+9 glClear(mask = GL_COLOR_BUFFER_BIT)
+10 glXSwapBuffers(dpy = 0x236a280, drawable = 41943041)
+
--- /dev/null
+!*.trace
+*-ref/
+*-out
+*-index.html
+*.trace.trim
--- /dev/null
+file (GLOB traces RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.trace)
+
+list (SORT traces)
+
+foreach (trace ${traces})
+ if (APITRACE_EXECUTABLE AND APITRACE_SOURCE_DIR)
+ add_test(
+ NAME trim-stress-${trace}
+ COMMAND
+ python ${CMAKE_SOURCE_DIR}/trim_stress_driver.py
+ --apitrace ${APITRACE_EXECUTABLE}
+ --apitrace-source ${APITRACE_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${trace}
+ )
+ endif ()
+endforeach (trace)
--- /dev/null
+This directory performs stress testing of "apitrace trim".
+
+For each trace file in this directory the trim_stress.py test driver
+will perform the following operations:
+
+Given <program>.trace:
+
+ 1. Generate snapshots of original trace in ./<program>-ref/
+
+ 2. For each frame of the trace:
+
+ 1. Use "apitrace trim" to trim <program>.trace to a
+ single-frame trace in <program>-trim.trace
+
+ 2. Generate a snapshot of the trimmed trace to
+ ./<program>-out/<frame>.png
+
+ 3. Use "apitrace diff-images" to compare all snapshots in
+ ./<program>-out with those in ./<program>-ref
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+'''Stress test driver for apitrace trim.'''
+
+import os, errno, shutil, subprocess
+
+from base_driver import *
+
+def rm_and_mkdir(dir):
+
+ # Operate only on local directories
+ dir = './' + dir
+
+ # Failing to delete a directory that doesn't exist is no failure
+ def rmtree_onerror(function, path, excinfo):
+ if excinfo[0] == OSError and excinfo[1].errno != errno.ENOENT:
+ raise
+
+ shutil.rmtree(dir, onerror = rmtree_onerror)
+ os.makedirs(dir)
+
+class TrimStressDriver(Driver):
+
+ def trim_stress(self, trace_file):
+ "Execute an apitrace-trim stress test for the given trace."
+
+ (dir, file_name) = os.path.split(trace_file)
+ (name, extension) = file_name.rsplit('.', 1)
+
+ ref_dir = name + '-ref/'
+ out_dir = name + '-out/'
+ trim_file = name + '.trace.trim'
+
+ rm_and_mkdir(ref_dir)
+ rm_and_mkdir(out_dir)
+
+ subprocess.check_call([self.options.apitrace, "dump-images", "--call-nos=no", "--output=" + ref_dir, trace_file]);
+
+ # Count the number of frame snapshots generated
+ frames = 0
+ for dirpath, dirs, files in os.walk(ref_dir):
+ # Don't descend into any sub-directories (not that there
+ # should be any)
+ del dirs[:]
+ frames = len(files)
+
+ for frame in range(frames):
+ try:
+ subprocess.check_call([self.options.apitrace, "trim", "--auto", "--frame=%d" % (frame), "--output=" + trim_file, trace_file])
+ except:
+ print "An error occurred while trimming frame %d from %s" % (frame, trace_file)
+ fail()
+ try:
+ subprocess.check_call([self.options.apitrace, "dump-images", "--call-nos=no", "--output=" + out_dir + "frame", trim_file])
+ except:
+ print "An error occurred replaying %s to generate a frame snapshot" % (trim_file)
+ fail()
+ os.rename("%s/frame0000000000.png" % (out_dir), "%s/%010d.png" % (out_dir, frame))
+
+ try:
+ subprocess.check_call([self.options.apitrace, "diff-images", "-v", ref_dir, out_dir])
+ except:
+ print "Trimmed frames did not match reference images. See " + name + "-index.html"
+ fail()
+ finally:
+ os.rename("index.html", name + "-index.html")
+
+ def run(self):
+ self.parseOptions()
+
+ self.trim_stress(self.args[0])
+
+ pass_()
+
+if __name__ == '__main__':
+ TrimStressDriver().run()