]> git.cworth.org Git - apitrace/commitdiff
Merge branch 'master' into d3d10
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 23 Sep 2011 07:33:13 +0000 (08:33 +0100)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 23 Sep 2011 07:33:13 +0000 (08:33 +0100)
Conflicts:
CMakeLists.txt

101 files changed:
.gitignore
BUGS.markdown [new file with mode: 0644]
CMakeLists.txt
INSTALL.markdown [new file with mode: 0644]
NEWS.markdown [new file with mode: 0644]
README.markdown
TODO.markdown
common/formatter.hpp [new file with mode: 0644]
common/image.cpp [new file with mode: 0644]
common/image.hpp [new file with mode: 0644]
common/image_bmp.cpp [new file with mode: 0644]
common/image_png.cpp [new file with mode: 0644]
common/image_pnm.cpp [new file with mode: 0644]
common/json.hpp [new file with mode: 0644]
common/os.hpp [new file with mode: 0644]
common/os_posix.cpp [new file with mode: 0644]
common/os_win32.cpp [new file with mode: 0644]
common/trace_file.cpp [new file with mode: 0644]
common/trace_file.hpp [new file with mode: 0644]
common/trace_format.hpp [new file with mode: 0644]
common/trace_loader.cpp [new file with mode: 0644]
common/trace_loader.hpp [new file with mode: 0644]
common/trace_local_writer.cpp [new file with mode: 0644]
common/trace_model.cpp [new file with mode: 0644]
common/trace_model.hpp [new file with mode: 0644]
common/trace_model_writer.cpp [new file with mode: 0644]
common/trace_parser.cpp [new file with mode: 0644]
common/trace_parser.hpp [new file with mode: 0644]
common/trace_snappyfile.cpp [new file with mode: 0644]
common/trace_snappyfile.hpp [new file with mode: 0644]
common/trace_writer.cpp [new file with mode: 0644]
common/trace_writer.hpp [new file with mode: 0644]
d3d.py
d3d8.py
d3d8trace.py [new file with mode: 0644]
d3d9.py
d3d9trace.py [new file with mode: 0644]
ddraw.py
ddrawtrace.py [new file with mode: 0644]
formatter.hpp [deleted file]
glapi.py
glparams.py
glretrace.hpp
glretrace.py
glretrace_main.cpp
glsize.hpp
glstate.cpp
glstate.py
gltypes.py
glxapi.py
gui/CMakeLists.txt
gui/apicalldelegate.cpp
gui/apisurface.cpp
gui/apitrace.cpp
gui/apitrace.h
gui/apitracecall.cpp
gui/apitracecall.h
gui/apitracefilter.cpp
gui/apitracefilter.h
gui/apitracemodel.cpp
gui/apitracemodel.h
gui/argumentseditor.cpp
gui/argumentseditor.h
gui/loaderthread.cpp [deleted file]
gui/loaderthread.h [deleted file]
gui/main.cpp
gui/mainwindow.cpp
gui/mainwindow.h
gui/retracer.cpp
gui/retracer.h
gui/saverthread.cpp
gui/saverthread.h
gui/traceloader.cpp [new file with mode: 0644]
gui/traceloader.h [new file with mode: 0644]
image.cpp [deleted file]
image.hpp [deleted file]
image_bmp.cpp [deleted file]
image_png.cpp [deleted file]
image_pnm.cpp [deleted file]
json.hpp [deleted file]
os.hpp [deleted file]
os_posix.cpp [deleted file]
os_win32.cpp [deleted file]
scripts/README [deleted file]
scripts/highlight.py [new file with mode: 0644]
scripts/retracediff.py
scripts/snapdiff.py
thirdparty/glext/glext.h
trace_file.cpp [deleted file]
trace_file.hpp [deleted file]
trace_format.hpp [deleted file]
trace_local_writer.cpp [deleted file]
trace_model.cpp [deleted file]
trace_model.hpp [deleted file]
trace_model_writer.cpp [deleted file]
trace_parser.cpp [deleted file]
trace_parser.hpp [deleted file]
trace_snappyfile.cpp [deleted file]
trace_snappyfile.hpp [deleted file]
trace_writer.cpp [deleted file]
trace_writer.hpp [deleted file]

index b2dda4247a2e4acd178f8d4ca7967f30fdb07549..ed1ea5a05b227f50e72f0e5c3d1df78a280c7a04 100644 (file)
@@ -27,11 +27,10 @@ CMakeCache.txt
 CMakeFiles
 Makefile
 build
-d3d10.cpp
-d3d10_1.cpp
-d3d8.cpp
-d3d9.cpp
-ddraw.cpp
+d3d10trace.cpp
+d3d8trace.cpp
+d3d9trace.cpp
+ddrawtrace.cpp
 dxsdk
 glproc.hpp
 glretrace
diff --git a/BUGS.markdown b/BUGS.markdown
new file mode 100644 (file)
index 0000000..2b8483d
--- /dev/null
@@ -0,0 +1,115 @@
+Reporting bugs
+==============
+
+Please report any issues on
+[github](https://github.com/apitrace/apitrace/issues).
+
+Always include the following information:
+
+* operating system name and version
+
+* OpenGL/D3D driver name and version
+
+
+Proprietary/confidential applications
+=====================================
+
+Issues should be preferably filed on github to facilitate collaborative
+development and for future reference.
+
+Access to applications source code is not required -- binaries are sufficient.
+
+If the bug happens with a proprietary application, and you don't want to
+publicly release the application and/or any data collected from it, then
+alternatively you can provide the necessary application and/or data via e-mail,
+to *jose dot r dot fonseca at gmail dot com*.
+
+If it is not technically/legally feasible for you to provide application and/or
+data at all, then you must be either:
+
+* develop and provide a test application, stripped-down of all
+  proprietary/confidential data, but that can reproduce the issue;
+
+* be willing/able to do the investigation of the issue, namely to identify the
+  root cause of the issue (e.g., which OpenGL call is not properly handled and
+  why), using all necessary tools (such as debuggers).
+
+Failure to do so will render the apitrace authors powerless to address the
+issue.
+
+
+Attachments
+===========
+
+github issue tracker doesn't support attachments.
+
+Please attach long logs to https://gist.github.com/ and paste the URL into the
+issue description.
+
+For big attachments, such as traces, please upload it temporarily to a web
+server you control, or use a file upload service such as
+http://www.megaupload.com/ or http://dropbox.com/ and paste the URL into the
+issue description.
+
+Trace files are only slightly compressed (for performance reasons).  You can
+further reduce their size when attaching/uploading by compressing with
+[XZ](http://tukaani.org/xz/) or [7-Zip](http://www.7-zip.org/).
+
+
+Bugs on tracing
+===============
+
+For bugs that happen while tracing (e.g., crashes while tracing the
+application, or incorrect traces) please:
+
+* provide information on how to obtain the application;
+
+* describe how you were using it when the issue happened.
+
+
+Bugs on retracing/GUI
+=====================
+
+For bugs on retracing (e.g. crashes when retracing the application,
+incorrect inconsistent rendering, or viewing with the GUI) please:
+
+* provide the trace file;
+
+* describe the results you got, and what results you were expecting.
+
+
+Obtaining stack back-traces
+===========================
+
+
+Linux/MacOSX
+------------
+
+Please rebuild apitrace with debugging information, by passing
+`-DCMAKE_BUILD_TYPE=Debug` to cmake.
+
+To obtain a stack back-trace, run the application with gdb from a terminal:
+
+    $ gdb --args application arg1 arg2 ...
+    (gdb) run
+    ...
+    (gdb) bt
+
+
+See also more detailed and Distro specific instructions:
+
+* http://wiki.debian.org/HowToGetABacktrace
+
+* https://wiki.ubuntu.com/Backtrace
+
+* http://fedoraproject.org/wiki/StackTraces
+
+* http://live.gnome.org/GettingTraces
+
+
+Windows
+-------
+
+WRITEME
+
+
index 82a4a31377e410a5e7f8600744ec98c21c3dc3d1..c9b740ccac465767ad1aeaded0b200a8e29ea0cf 100755 (executable)
@@ -163,7 +163,10 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty)
 ##############################################################################
 # Common libraries / utilities
 
-include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+include_directories (
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/common
+)
 
 add_custom_command (
     OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
@@ -180,18 +183,19 @@ else (WIN32)
 endif (WIN32)
 
 add_library (common
-    trace_file.cpp
-    trace_snappyfile.cpp
-    trace_model.cpp
-    trace_parser.cpp
-    trace_writer.cpp
-    trace_local_writer.cpp
-    trace_model_writer.cpp
-    image.cpp
-    image_bmp.cpp
-    image_pnm.cpp
-    image_png.cpp
-    ${os}
+    common/trace_file.cpp
+    common/trace_snappyfile.cpp
+    common/trace_model.cpp
+    common/trace_parser.cpp
+    common/trace_writer.cpp
+    common/trace_local_writer.cpp
+    common/trace_model_writer.cpp
+    common/trace_loader.cpp
+    common/image.cpp
+    common/image_bmp.cpp
+    common/image_pnm.cpp
+    common/image_png.cpp
+    common/${os}
 )
 
 set_target_properties (common PROPERTIES
@@ -213,11 +217,11 @@ if (WIN32)
     if (DirectX_D3D_INCLUDE_DIR)
         include_directories (SYSTEM ${DirectX_D3D_INCLUDE_DIR})
         add_custom_command (
-            OUTPUT ddraw.cpp
-            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d.py > ${CMAKE_CURRENT_BINARY_DIR}/ddraw.cpp
-            DEPENDS d3d.py d3dtypes.py d3dcaps.py ddraw.py trace.py winapi.py stdapi.py
+            OUTPUT ddrawtrace.cpp
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/ddrawtrace.py > ${CMAKE_CURRENT_BINARY_DIR}/ddrawtrace.cpp
+            DEPENDS ddrawtrace.py d3d.py d3dtypes.py d3dcaps.py ddraw.py trace.py winapi.py stdapi.py
         )
-        add_library (ddraw MODULE ddraw.def ddraw.cpp)
+        add_library (ddraw MODULE ddraw.def ddrawtrace.cpp)
         set_target_properties (ddraw
             PROPERTIES PREFIX ""
             RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -230,11 +234,11 @@ if (WIN32)
     if (DirectX_D3D8_INCLUDE_DIR AND DirectX_D3DX9_INCLUDE_DIR)
         include_directories (SYSTEM ${DirectX_D3D8_INCLUDE_DIR} ${DirectX_D3DX9_INCLUDE_DIR})
         add_custom_command (
-            OUTPUT d3d8.cpp
-            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d8.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d8.cpp
-            DEPENDS d3d8.py trace.py d3d8types.py d3d8caps.py winapi.py stdapi.py
+            OUTPUT d3d8trace.cpp
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d8trace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d8trace.cpp
+            DEPENDS d3d8trace.py d3d8.py trace.py d3d8types.py d3d8caps.py winapi.py stdapi.py
         )
-        add_library (d3d8 MODULE d3d8.def d3d8.cpp d3dshader.cpp)
+        add_library (d3d8 MODULE d3d8.def d3d8trace.cpp d3dshader.cpp)
         set_target_properties (d3d8
             PROPERTIES PREFIX ""
             RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -247,11 +251,11 @@ if (WIN32)
     if (DirectX_D3DX9_INCLUDE_DIR)
         include_directories (SYSTEM ${DirectX_D3DX9_INCLUDE_DIR})
         add_custom_command (
-            OUTPUT d3d9.cpp
-            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d9.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d9.cpp
-            DEPENDS d3d9.py trace.py d3d9types.py d3d9caps.py winapi.py stdapi.py
+            OUTPUT d3d9trace.cpp
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d9trace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d9trace.cpp
+            DEPENDS d3d9trace.py d3d9.py trace.py d3d9types.py d3d9caps.py winapi.py stdapi.py
         )
-        add_library (d3d9 MODULE d3d9.def d3d9.cpp d3dshader.cpp)
+        add_library (d3d9 MODULE d3d9.def d3d9trace.cpp d3dshader.cpp)
         set_target_properties (d3d9
             PROPERTIES PREFIX ""
             RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -264,11 +268,11 @@ if (WIN32)
     if (DirectX_D3D10_INCLUDE_DIR)
         include_directories (SYSTEM ${DirectX_D3D10_INCLUDE_DIR})
         add_custom_command (
-            OUTPUT d3d10.cpp
-            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d10misc.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d10.cpp
+            OUTPUT d3d10trace.cpp
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d10misc.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d10trace.cpp
             DEPENDS d3d10misc.py d3d10.py winapi.py stdapi.py
         )
-        add_library (d3d10 MODULE d3d10.def d3d10.cpp)
+        add_library (d3d10 MODULE d3d10.def d3d10trace.cpp)
         set_target_properties (d3d10 PROPERTIES PREFIX "")
         install (TARGETS d3d10 LIBRARY DESTINATION wrappers)
     endif (DirectX_D3D10_INCLUDE_DIR)
@@ -383,7 +387,6 @@ add_executable (glretrace
     glstate_params.cpp
     retrace.cpp
     ${glws}
-    image.cpp 
     ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
 )
 
@@ -425,7 +428,14 @@ endif ()
 ##############################################################################
 # Packaging
 
-install (FILES LICENSE README.markdown TODO.markdown DESTINATION doc)
+install (
+    FILES
+        BUGS.markdown
+        LICENSE
+        NEWS.markdown
+        README.markdown
+        TODO.markdown
+    DESTINATION doc)
 
 set (CPACK_PACKAGE_VERSION_MAJOR "1")
 set (CPACK_PACKAGE_VERSION_MINOR "0")
diff --git a/INSTALL.markdown b/INSTALL.markdown
new file mode 100644 (file)
index 0000000..b50fb78
--- /dev/null
@@ -0,0 +1,69 @@
+Building from source
+====================
+
+
+Requirements common for all platforms:
+
+* Python (requires version 2.6)
+
+* CMake (tested with version 2.8)
+
+Requirements to build the GUI (optional):
+
+* Qt (tested with version 4.7)
+
+* QJSON (tested with version 0.7.1)
+
+
+Linux / Mac OS X
+----------------
+
+Build as:
+
+    cmake -H. -Bbuild
+    make -C build
+
+You can also build the 32bit GL wrapper on 64bit distro with a multilib gcc by
+doing:
+
+    cmake -H. -Bbuild32 -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_EXE_LINKER_FLAGS=-m32
+    make -C build32 glxtrace
+
+
+Windows
+-------
+
+Additional requirements:
+
+* Microsoft Visual Studio (tested with 2008 version) or MinGW (tested with gcc version 4.4)
+
+* Microsoft DirectX SDK (tested with August 2007 release)
+
+To build with Visual Studio first invoke CMake GUI as:
+
+    cmake-gui -H. -B%cd%\build
+
+and press the _Configure_ button.
+
+It will try to detect most required/optional dependencies automatically.  When
+not found automatically, you can manually specify the location of the
+dependencies from the GUI.
+
+If you are building with GUI support (i.e, with QT and QJSON), it should detect
+the official QT sdk automatically, but you will need to build QJSON yourself
+and also set the `QJSON_INCLUDE_DIR` and `QJSON_LIBRARIES` variables in the
+generated `CMakeCache.txt` when building apitrace and repeat the above
+sequence.
+
+After you've succesfully configured, you can start the build by opening the
+generated `build\apitrace.sln` solution file, or invoking `cmake` as:
+
+    cmake --build build --config MinSizeRel
+
+The steps to build 64bit version are similar, but choosing _Visual Studio 9
+2008 Win64_ instead of _Visual Studio 9 2008_.
+
+It's also possible to instruct `cmake` build Windows binaries on Linux with
+[MinGW cross compilers](http://www.cmake.org/Wiki/CmakeMingw).
+
+
diff --git a/NEWS.markdown b/NEWS.markdown
new file mode 100644 (file)
index 0000000..7cf9e38
--- /dev/null
@@ -0,0 +1,34 @@
+This file lists the major user visible improvments.  For a full list of changes
+and their authors see the git history.
+
+
+Recent developments
+===================
+
+* Flush/sync trace file only when there is an uncaught signal/exception,
+  yielding a 5x speed up while tracing.
+
+* Employ [snappy compression library](http://code.google.com/p/snappy/) instead
+  of zlib, yielding a 2x speed up while tracing.
+
+* Implement and advertise `GL_GREMEDY_string_marker` and
+  `GL_GREMEDY_frame_terminator` extensions.
+
+* Mac OS X support.
+
+* Support up-to OpenGL 4.2 calls.
+
+* Better GUI performance with very large traces, by loading frames from disk on
+  demand.
+
+
+Version 1.0
+===========
+
+* Qt GUI, capable of visualizing the calls, the state, and editing the state.
+
+
+Pre-history
+===========
+
+* OpenGL retrace support.
index 5b34dec786cb67c10a104e7435f37963977d2519..c38804276664853db5256e8a87eee2ef044451b1 100644 (file)
@@ -7,80 +7,13 @@ About **apitrace**
 
 * retrace OpenGL calls from a file;
 
-* visualize trace files, and inspect state.
+* inspect OpenGL state at any call while retracing;
 
+* visualize and edit trace files.
 
-Building from source
-====================
 
-
-Requirements common for all platforms:
-
-* Python (requires version 2.6)
-
-* CMake (tested with version 2.8)
-
-Requirements to build the GUI (optional):
-
-* Qt (tested with version 4.7)
-
-* QJSON (tested with version 0.7.1)
-
-
-Linux / Mac OS X
-----------------
-
-Build as:
-
-    cmake -H. -Bbuild
-    make -C build
-
-You can also build the 32bit GL wrapper on 64bit distro with a multilib gcc by
-doing:
-
-    cmake -H. -Bbuild32 -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_EXE_LINKER_FLAGS=-m32
-    make -C build32 glxtrace
-
-
-Windows
--------
-
-Additional requirements:
-
-* Microsoft Visual Studio (tested with 2008 version) or MinGW (tested with gcc version 4.4)
-
-* Microsoft DirectX SDK (tested with August 2007 release)
-
-To build with Visual Studio first invoke CMake GUI as:
-
-    cmake-gui -H. -B%cd%\build
-
-and press the _Configure_ button.
-
-It will try to detect most required/optional dependencies automatically.  When
-not found automatically, you can manually specify the location of the
-dependencies from the GUI.
-
-If you are building with GUI support (i.e, with QT and QJSON), it should detect
-the official QT sdk automatically, but you will need to build QJSON yourself
-and also set the `QJSON_INCLUDE_DIR` and `QJSON_LIBRARIES` variables in the
-generated `CMakeCache.txt` when building apitrace and repeat the above
-sequence.
-
-After you've succesfully configured, you can start the build by opening the
-generated `build\apitrace.sln` solution file, or invoking `cmake` as:
-
-    cmake --build build --config MinSizeRel
-
-The steps to build 64bit version are similar, but choosing _Visual Studio 9
-2008 Win64_ instead of _Visual Studio 9 2008_.
-
-It's also possible to instruct `cmake` build Windows binaries on Linux with
-[MinGW cross compilers](http://www.cmake.org/Wiki/CmakeMingw).
-
-
-Usage
-=====
+Basic usage
+===========
 
 
 Linux
@@ -129,11 +62,6 @@ to trace by using `glxtrace.so` as an ordinary `libGL.so` and injecting into
 See the `ld.so` man page for more information about `LD_PRELOAD` and
 `LD_LIBRARY_PATH` environment flags.
 
-You can make a video of the output by doing
-
-    /path/to/glretrace -s - application.trace \
-    | ffmpeg -r 30 -f image2pipe -vcodec ppm -i pipe: -vcodec mpeg4 -y output.mp4
-
 
 
 Mac OS X
@@ -167,6 +95,184 @@ Windows
         \path\to\glretrace application.trace
 
 
+Advanced command line usage
+===========================
+
+
+Emitting annotations to the trace from GL applications
+------------------------------------------------------
+
+You can emit string and frame annotations through the
+[`GL_GREMEDY_string_marker`](http://www.opengl.org/registry/specs/GREMEDY/string_marker.txt)
+and
+[`GL_GREMEDY_frame_terminator`](http://www.opengl.org/registry/specs/GREMEDY/frame_terminator.txt)
+GL extensions.
+
+**apitrace** will advertise and intercept these GL extensions independently of
+the GL implementation.  So all you have to do is to use these extensions when
+available.
+
+For example, if you use [GLEW](http://glew.sourceforge.net/) to dynamically
+detect and use GL extensions, you could easily accomplish this by doing:
+
+    void foo() {
+    
+      if (GLEW_GREMEDY_string_marker) {
+        glStringMarkerGREMEDY(0, __FUNCTION__ ": enter");
+      }
+      
+      ...
+      
+      if (GLEW_GREMEDY_string_marker) {
+        glStringMarkerGREMEDY(0, __FUNCTION__ ": leave");
+      }
+      
+    }
+
+This has the added advantage of working equally well with gDEBugger.
+
+
+Dump GL state at a particular call
+----------------------------------
+
+You can get a dump of the bound GL state at call 12345 by doing:
+
+    /path/to/glretrace -D 12345 application.trace > 12345.json
+
+This is precisely the mechanism the GUI obtains its own state.
+
+You can compare two state dumps with the jsondiff.py script:
+
+    ./scripts/jsondiff.py 12345.json 67890.json
+
+
+Comparing two traces side by side
+---------------------------------
+
+    ./scripts/tracediff.sh trace1.trace trace2.trace
+
+This works only on Unices, and it will truncate the traces due to performance
+limitations.
+
+
+Recording a video with FFmpeg
+-----------------------------
+
+You can make a video of the output by doing
+
+    /path/to/glretrace -s - application.trace \
+    | ffmpeg -r 30 -f image2pipe -vcodec ppm -i pipe: -vcodec mpeg4 -y output.mp4
+
+
+Advanced usage for OpenGL implementors
+======================================
+
+There are several advanced usage examples meant for OpenGL implementors.
+
+
+Regression testing
+------------------
+
+These are the steps to create a regression test-suite around **apitrace**:
+
+* obtain a trace
+
+* obtain reference snapshots, by doing:
+
+        mkdir /path/to/snapshots/
+        /path/to/glretrace -s /path/to/reference/snapshots/ application.trace
+
+  on reference system.
+
+* prune the snapshots which are not interesting
+
+* to do a regression test, do:
+
+        /path/to/glretrace -c /path/to/reference/snapshots/ application.trace
+
+  Alternatively, for a HTML summary, use the snapdiff script:
+
+        /path/to/glretrace -s /path/to/current/snapshots/ application.trace
+        ./scripts/snapdiff.py --output summary.html /path/to/reference/snapshots/ /path/to/current/snapshots/
+
+
+Automated git-bisection
+-----------------------
+
+With tracecheck.py it is possible to automate git bisect and pinpoint the
+commit responsible for a regression.
+
+Below is an example of using tracecheck.py to bisect a regression in the
+Mesa-based Intel 965 driver.  But the procedure could be applied to any GL
+driver hosted on a git repository.
+
+First, create a build script, named build-script.sh, containing:
+
+    #!/bin/sh
+    set -e
+    export PATH=/usr/lib/ccache:$PATH
+    export CFLAGS='-g'
+    export CXXFLAGS='-g'
+    ./autogen.sh --disable-egl --disable-gallium --disable-glut --disable-glu --disable-glw --with-dri-drivers=i965
+    make clean
+    make "$@"
+
+It is important that builds are both robust, and efficient.  Due to broken
+dependency discovery in Mesa's makefile system, it was necessary invoke `make
+clean` in every iteration step.  `ccache` should be installed to avoid
+recompiling unchanged source files.
+
+Then do:
+
+    cd /path/to/mesa
+    export LIBGL_DEBUG=verbose
+    export LD_LIBRARY_PATH=$PWD/lib
+    export LIBGL_DRIVERS_DIR=$PWD/lib
+    git bisect start \
+        6491e9593d5cbc5644eb02593a2f562447efdcbb 71acbb54f49089b03d3498b6f88c1681d3f649ac \
+        -- src/mesa/drivers/dri/intel src/mesa/drivers/dri/i965/
+    git bisect run /path/to/tracecheck.py \
+        --precision-threshold 8.0 \
+        --build /path/to/build-script.sh \
+        --gl-renderer '.*Mesa.*Intel.*' \
+        --retrace=/path/to/glretrace \
+        -c /path/to/reference/snapshots/ \
+        topogun-1.06-orc-84k.trace
+
+The trace-check.py script will skip automatically when there are build
+failures.
+
+The `--gl-renderer` option will also cause a commit to be skipped if the
+`GL_RENDERER` is unexpected (e.g., when a software renderer or another GL
+driver is unintentionally loaded due to missing symbol in the DRI driver, or
+another runtime fault).
+
+
+Side by side retracing
+----------------------
+
+In order to determine which draw call a regression first manifests one could
+generate snapshots for every draw call, using the `-S` option.  That is, however,
+very inefficient for big traces with many draw calls.
+
+A faster approach is to run both the bad and a good GL driver side-by-side.
+The latter can be either a previously known good build of the GL driver, or a
+reference software renderer.
+
+This can be achieved with retracediff.py script, which invokes glretrace with
+different environments, allowing to choose the desired GL driver by
+manipulating variables such as `LD_LIBRARY_PATH` or `LIBGL_DRIVERS_DIR`.
+
+For example:
+
+    ./scripts/retracediff.py \
+        --ref-env LD_LIBRARY_PATH=/path/to/reference/GL/implementation \
+        -r ./glretrace \
+        --diff-prefix=/path/to/output/diffs \
+        application.trace
+
+
+
 Links
 =====
 
index fb447668722225fe1afffc198f44f47c32e3bb9d..b54cf65bd7e6085eb12cdd2f94c88568c0e975ac 100644 (file)
@@ -50,9 +50,6 @@ Retracing
 
 * Plug memory leaks.
 
-* Allow to retrace with two libGL.so in parallel, and output differences in
-  rendered frames / draw calls.
-
 * D3D support.
 
 
@@ -64,12 +61,11 @@ GUI
 * Visualize meshes in draw commands.
 
 
-Other:
+Other
+-----
 
 * Side-by-side trace diffing; either as a separate tool on or the GUI.
 
-* Side-by-side state diffing.
-
 * Ability to extract just a single frame from a trace, and all previous calls
   that contributed to it:
 
diff --git a/common/formatter.hpp b/common/formatter.hpp
new file mode 100644 (file)
index 0000000..181e2d1
--- /dev/null
@@ -0,0 +1,174 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Helpers for coloring output.
+ */
+
+#ifndef _FORMATTER_HPP_
+#define _FORMATTER_HPP_
+
+
+#include <iostream>
+
+
+namespace Formatter {
+
+/*
+ * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas
+ */
+
+class Attribute {
+public:
+    virtual ~Attribute() {}
+
+    virtual void apply(std::ostream &) const {}
+};
+
+
+enum Color {
+    RED,
+    GREEN,
+    BLUE,
+};
+
+
+class Formatter {
+public:
+    virtual ~Formatter() {}
+
+    virtual Attribute *normal(void) const { return new Attribute; }
+    virtual Attribute *bold(void) const { return new Attribute; }
+    virtual Attribute *italic(void) const { return new Attribute; }
+    virtual Attribute *color(Color) const { return new Attribute; }
+};
+
+
+class AnsiAttribute : public Attribute {
+protected:
+    const char *escape;
+public:
+    AnsiAttribute(const char *_escape) : escape(_escape) {}
+    void apply(std::ostream& os) const {
+        os << "\33[" << escape;
+    }
+};
+
+
+/**
+ * Formatter for plain-text files which outputs ANSI escape codes. See
+ * http://en.wikipedia.org/wiki/ANSI_escape_code for more information
+ * concerning ANSI escape codes.
+ */
+class AnsiFormatter : public Formatter {
+protected:
+public:
+    virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); }
+    virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); }
+    virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); }
+    virtual Attribute *color(Color c) const { 
+        static const char *color_escapes[] = {
+            "31m", /* red */
+            "32m", /* green */
+            "34m", /* blue */
+        };
+        return new AnsiAttribute(color_escapes[c]); 
+    }
+};
+
+
+inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) {
+    attr->apply(os);
+    return os;
+}
+
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+class WindowsAttribute : public Attribute {
+protected:
+    WORD wAttributes;
+public:
+    WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {}
+    void apply(std::ostream& os) const {
+        DWORD nStdHandleOutput;
+        if (os == std::cout) {
+            nStdHandleOutput = STD_OUTPUT_HANDLE;
+        } else if (os == std::cerr) {
+            nStdHandleOutput = STD_ERROR_HANDLE;
+        } else {
+            return;
+        }
+        HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput);
+        if (hConsoleOutput == INVALID_HANDLE_VALUE) {
+            return;
+        }
+
+        SetConsoleTextAttribute(hConsoleOutput, wAttributes);
+    }
+};
+
+
+/**
+ * Formatter for the Windows Console.
+ */
+class WindowsFormatter : public Formatter {
+protected:
+public:
+    virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
+    virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); }
+    virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
+    virtual Attribute *color(Color c) const { 
+        static const WORD color_escapes[] = {
+            FOREGROUND_RED | FOREGROUND_INTENSITY,
+            FOREGROUND_GREEN | FOREGROUND_INTENSITY,
+            FOREGROUND_BLUE | FOREGROUND_INTENSITY, 
+        };
+        return new WindowsAttribute(color_escapes[c]); 
+    }
+};
+
+#endif
+
+
+inline Formatter *defaultFormatter(bool color = true) {
+    if (color) {
+#ifdef _WIN32
+        return new WindowsFormatter;
+#else
+        return new AnsiFormatter;
+#endif
+    } else {
+        return new Formatter;
+    }
+}
+
+
+} /* namespace Formatter */
+
+
+#endif /* _FORMATTER_HPP_ */
diff --git a/common/image.cpp b/common/image.cpp
new file mode 100644 (file)
index 0000000..4da9c13
--- /dev/null
@@ -0,0 +1,76 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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 <assert.h>
+#include <math.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+double Image::compare(Image &ref)
+{
+    if (width != ref.width ||
+        height != ref.height ||
+        channels != ref.channels) {
+        return 0.0;
+    }
+
+    const unsigned char *pSrc = start();
+    const unsigned char *pRef = ref.start();
+
+    assert(channels >= 3);
+
+    unsigned long long error = 0;
+    for (unsigned y = 0; y < height; ++y) {
+        for (unsigned  x = 0; x < width; ++x) {
+            // FIXME: Ignore alpha channel until we are able to pick a visual
+            // that matches the traces
+            for (unsigned  c = 0; c < 3; ++c) {
+                int delta = pSrc[x*channels + c] - pRef[x*channels + c];
+                error += delta*delta;
+            }
+        }
+
+        pSrc += stride();
+        pRef += ref.stride();
+    }
+
+    double numerator = error*2 + 1;
+    double denominator = height*width*3ULL*255ULL*255ULL*2;
+    double quotient = numerator/denominator;
+
+    // Precision in bits
+    double precision = -log(quotient)/log(2.0);
+
+    return precision;
+}
+
+
+} /* namespace Image */
diff --git a/common/image.hpp b/common/image.hpp
new file mode 100644 (file)
index 0000000..dc53ec9
--- /dev/null
@@ -0,0 +1,115 @@
+/**************************************************************************
+ *
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Image I/O.
+ */
+
+#ifndef _IMAGE_HPP_
+#define _IMAGE_HPP_
+
+
+#include <fstream>
+
+
+namespace Image {
+
+
+class Image {
+public:
+    unsigned width;
+    unsigned height;
+    unsigned channels;
+
+    // Flipped vertically or not
+    bool flipped;
+
+    // Pixels in RGBA format
+    unsigned char *pixels;
+
+    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
+        width(w),
+        height(h),
+        channels(c),
+        flipped(f),
+        pixels(new unsigned char[h*w*c])
+    {}
+
+    inline ~Image() {
+        delete [] pixels;
+    }
+
+    inline unsigned char *start(void) {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline const unsigned char *start(void) const {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline unsigned char *end(void) {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline const unsigned char *end(void) const {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline signed stride(void) const {
+        return flipped ? -width*channels : width*channels;
+    }
+
+    bool writeBMP(const char *filename) const;
+
+    void writePNM(std::ostream &os, const char *comment = NULL) const;
+
+    inline bool writePNM(const char *filename, const char *comment = NULL) const {
+        std::ofstream os(filename, std::ofstream::binary);
+        if (!os) {
+            return false;
+        }
+        writePNM(os, comment);
+        return true;
+    }
+
+    bool writePNG(const char *filename) const;
+
+    double compare(Image &ref);
+};
+
+bool writePixelsToBuffer(unsigned char *pixels,
+                         unsigned w, unsigned h, unsigned numChannels,
+                         bool flipped,
+                         char **buffer,
+                         int *size);
+
+Image *
+readPNG(const char *filename);
+
+
+} /* namespace Image */
+
+
+#endif /* _IMAGE_HPP_ */
diff --git a/common/image_bmp.cpp b/common/image_bmp.cpp
new file mode 100644 (file)
index 0000000..346f39a
--- /dev/null
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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 <assert.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+#pragma pack(push,2)
+struct FileHeader {
+    uint16_t bfType;
+    uint32_t bfSize;
+    uint16_t bfReserved1;
+    uint16_t bfReserved2;
+    uint32_t bfOffBits;
+};
+#pragma pack(pop)
+
+struct InfoHeader {
+    uint32_t biSize;
+    int32_t biWidth;
+    int32_t biHeight;
+    uint16_t biPlanes;
+    uint16_t biBitCount;
+    uint32_t biCompression;
+    uint32_t biSizeImage;
+    int32_t biXPelsPerMeter;
+    int32_t biYPelsPerMeter;
+    uint32_t biClrUsed;
+    uint32_t biClrImportant;
+};
+
+struct Pixel {
+    uint8_t rgbBlue;
+    uint8_t rgbGreen;
+    uint8_t rgbRed;
+    uint8_t rgbAlpha;
+};
+
+
+bool
+Image::writeBMP(const char *filename) const {
+    assert(channels == 4);
+
+    struct FileHeader bmfh;
+    struct InfoHeader bmih;
+    unsigned x, y;
+
+    bmfh.bfType = 0x4d42;
+    bmfh.bfSize = 14 + 40 + height*width*4;
+    bmfh.bfReserved1 = 0;
+    bmfh.bfReserved2 = 0;
+    bmfh.bfOffBits = 14 + 40;
+
+    bmih.biSize = 40;
+    bmih.biWidth = width;
+    bmih.biHeight = height;
+    bmih.biPlanes = 1;
+    bmih.biBitCount = 32;
+    bmih.biCompression = 0;
+    bmih.biSizeImage = height*width*4;
+    bmih.biXPelsPerMeter = 0;
+    bmih.biYPelsPerMeter = 0;
+    bmih.biClrUsed = 0;
+    bmih.biClrImportant = 0;
+
+    std::ofstream stream(filename, std::ofstream::binary);
+
+    if (!stream) {
+        return false;
+    }
+
+    stream.write((const char *)&bmfh, 14);
+    stream.write((const char *)&bmih, 40);
+
+    unsigned stride = width*4;
+
+    if (flipped) {
+        for (y = 0; y < height; ++y) {
+            const unsigned char *ptr = pixels + y * stride;
+            for (x = 0; x < width; ++x) {
+                struct Pixel pixel;
+                pixel.rgbRed   = ptr[x*4 + 0];
+                pixel.rgbGreen = ptr[x*4 + 1];
+                pixel.rgbBlue  = ptr[x*4 + 2];
+                pixel.rgbAlpha = ptr[x*4 + 3];
+                stream.write((const char *)&pixel, 4);
+            }
+        }
+    } else {
+        y = height;
+        while (y--) {
+            const unsigned char *ptr = pixels + y * stride;
+            for (x = 0; x < width; ++x) {
+                struct Pixel pixel;
+                pixel.rgbRed   = ptr[x*4 + 0];
+                pixel.rgbGreen = ptr[x*4 + 1];
+                pixel.rgbBlue  = ptr[x*4 + 2];
+                pixel.rgbAlpha = ptr[x*4 + 3];
+                stream.write((const char *)&pixel, 4);
+            }
+        }
+    }
+
+    stream.close();
+
+    return true;
+}
+
+
+} /* namespace Image */
diff --git a/common/image_png.cpp b/common/image_png.cpp
new file mode 100644 (file)
index 0000000..fd22213
--- /dev/null
@@ -0,0 +1,312 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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 <zlib.h>
+#include <png.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <fstream>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+bool
+Image::writePNG(const char *filename) const {
+    FILE *fp;
+    png_structp png_ptr;
+    png_infop info_ptr;
+
+    fp = fopen(filename, "wb");
+    if (!fp)
+        goto no_fp;
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_write_struct(&png_ptr,  NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        goto no_png;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    int color_type;
+    switch (channels) {
+    case 4:
+        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+        break;
+    case 3:
+        color_type = PNG_COLOR_TYPE_RGB;
+        break;
+    case 2:
+        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+        break;
+    case 1:
+        color_type = PNG_COLOR_TYPE_GRAY;
+        break;
+    default:
+        assert(0);
+        return false;
+    }
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
+        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+    png_write_info(png_ptr, info_ptr);
+
+    if (!flipped) {
+        for (unsigned y = 0; y < height; ++y) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    } else {
+        unsigned y = height;
+        while (y--) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    }
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    fclose(fp);
+    return true;
+
+no_png:
+    fclose(fp);
+no_fp:
+    return false;
+}
+
+
+Image *
+readPNG(const char *filename)
+{
+    FILE *fp;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_infop end_info;
+    Image *image;
+
+    fp = fopen(filename, "rb");
+    if (!fp)
+        goto no_fp;
+
+    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        goto no_png;
+    }
+
+    end_info = png_create_info_struct(png_ptr);
+    if (!end_info) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+        goto no_png;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    png_read_info(png_ptr, info_ptr);
+
+    png_uint_32 width, height;
+    int bit_depth, color_type, interlace_type, compression_type, filter_method;
+
+    png_get_IHDR(png_ptr, info_ptr,
+                 &width, &height,
+                 &bit_depth, &color_type, &interlace_type,
+                 &compression_type, &filter_method);
+
+    image = new Image(width, height);
+    if (!image)
+        goto no_image;
+
+    /* Convert to RGBA8 */
+    if (color_type == PNG_COLOR_TYPE_PALETTE)
+        png_set_palette_to_rgb(png_ptr);
+    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+        png_set_expand_gray_1_2_4_to_8(png_ptr);
+    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+        png_set_tRNS_to_alpha(png_ptr);
+    if (bit_depth == 16)
+        png_set_strip_16(png_ptr);
+
+    for (unsigned y = 0; y < height; ++y) {
+        png_bytep row = (png_bytep)(image->pixels + y*width*4);
+        png_read_row(png_ptr, row, NULL);
+    }
+
+    png_read_end(png_ptr, info_ptr);
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+    fclose(fp);
+    return image;
+
+no_image:
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+no_png:
+    fclose(fp);
+no_fp:
+    return NULL;
+}
+
+
+struct png_tmp_buffer
+{
+    char *buffer;
+    size_t size;
+};
+
+static void
+pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
+    size_t nsize = buf->size + length;
+
+    /* allocate or grow buffer */
+    if (buf->buffer)
+        buf->buffer = (char*)realloc(buf->buffer, nsize);
+    else
+        buf->buffer = (char*)malloc(nsize);
+
+    if (!buf->buffer)
+        png_error(png_ptr, "Buffer allocation error");
+
+    memcpy(buf->buffer + buf->size, data, length);
+    buf->size += length;
+}
+
+bool writePixelsToBuffer(unsigned char *pixels,
+                         unsigned width, unsigned height, unsigned numChannels,
+                         bool flipped,
+                         char **buffer,
+                         int *size)
+{
+    struct png_tmp_buffer png_mem;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int type;
+
+    png_mem.buffer = NULL;
+    png_mem.size = 0;
+
+    switch (numChannels) {
+    case 4:
+        type = PNG_COLOR_TYPE_RGB_ALPHA;
+        break;
+    case 3:
+        type = PNG_COLOR_TYPE_RGB;
+        break;
+    case 2:
+        type = PNG_COLOR_TYPE_GRAY_ALPHA;
+        break;
+    case 1:
+        type = PNG_COLOR_TYPE_GRAY;
+        break;
+    default:
+        goto no_png;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_write_struct(&png_ptr,  NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        goto no_png;
+    }
+
+    png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+                 type, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+    png_write_info(png_ptr, info_ptr);
+
+    if (!flipped) {
+        for (unsigned y = 0; y < height; ++y) {
+            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    } else {
+        unsigned y = height;
+        while (y--) {
+            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    }
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    *buffer = png_mem.buffer;
+    *size = png_mem.size;
+
+    return true;
+
+no_png:
+    *buffer = NULL;
+    *size = 0;
+
+    if (png_mem.buffer)
+        free(png_mem.buffer);
+    return false;
+}
+
+} /* namespace Image */
diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp
new file mode 100644 (file)
index 0000000..5397a1a
--- /dev/null
@@ -0,0 +1,112 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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 <assert.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+/**
+ * http://en.wikipedia.org/wiki/Netpbm_format
+ * http://netpbm.sourceforge.net/doc/ppm.html
+ */
+void
+Image::writePNM(std::ostream &os, const char *comment) const {
+    assert(channels == 1 || channels >= 3);
+
+    os << (channels == 1 ? "P5" : "P6") << "\n";
+    if (comment) {
+        os << "#" << comment << "\n";
+    }
+    os << width << " " << height << "\n";
+    os << "255" << "\n";
+
+    const unsigned char *row;
+
+    if (channels == 1 || channels == 3) {
+        for (row = start(); row != end(); row += stride()) {
+            os.write((const char *)row, width*channels);
+        }
+    } else {
+        unsigned char *tmp = new unsigned char[width*3];
+        if (channels == 4) {
+            for (row = start(); row != end(); row += stride()) {
+                const uint32_t *src = (const uint32_t *)row;
+                uint32_t *dst = (uint32_t *)tmp;
+                unsigned x;
+                for (x = 0; x + 4 <= width; x += 4) {
+                    /*
+                     * It's much faster to access dwords than bytes.
+                     *
+                     * FIXME: Big-endian version.
+                     */
+
+                    uint32_t rgba0 = *src++ & 0xffffff;
+                    uint32_t rgba1 = *src++ & 0xffffff;
+                    uint32_t rgba2 = *src++ & 0xffffff;
+                    uint32_t rgba3 = *src++ & 0xffffff;
+                    uint32_t rgb0 = rgba0
+                                  | (rgba1 << 24);
+                    uint32_t rgb1 = (rgba1 >> 8)
+                                  | (rgba2 << 16);
+                    uint32_t rgb2 = (rgba2 >> 16)
+                                  | (rgba3 << 8);
+                    *dst++ = rgb0;
+                    *dst++ = rgb1;
+                    *dst++ = rgb2;
+                }
+                for (; x < width; ++x) {
+                    tmp[x*3 + 0] = row[x*4 + 0];
+                    tmp[x*3 + 1] = row[x*4 + 1];
+                    tmp[x*3 + 2] = row[x*4 + 2];
+                }
+                os.write((const char *)tmp, width*3);
+            }
+        } else if (channels == 2) {
+            for (row = start(); row != end(); row += stride()) {
+                const unsigned char *src = row;
+                unsigned char *dst = tmp;
+                for (unsigned x = 0; x < width; ++x) {
+                    *dst++ = *src++;
+                    *dst++ = *src++;
+                    *dst++ = 0;
+                }
+                os.write((const char *)tmp, width*3);
+            }
+        } else {
+            assert(0);
+        }
+        delete [] tmp;
+    }
+}
+
+
+} /* namespace Image */
diff --git a/common/json.hpp b/common/json.hpp
new file mode 100644 (file)
index 0000000..9e6b960
--- /dev/null
@@ -0,0 +1,337 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace writing functions.
+ */
+
+#ifndef _JSON_HPP_
+#define _JSON_HPP_
+
+#include <assert.h>
+#include <stddef.h>
+#include <wchar.h>
+
+#include <iomanip>
+#include <ostream>
+#include <string>
+
+
+class JSONWriter
+{
+private:
+    std::ostream &os;
+
+    int level;
+    bool value;
+    char space;
+
+    void newline(void) {
+        os << "\n";
+        for (int i = 0; i < level; ++i) 
+            os << "  ";
+    }
+
+    void separator(void) {
+        if (value) {
+            os << ",";
+            switch (space) {
+            case '\0':
+                break;
+            case '\n':
+                newline();
+                break;
+            default:
+                os << space;
+                break;
+            }
+        } else {
+            if (space == '\n') {
+                newline();
+            }
+        }
+    }
+
+    void escapeAsciiString(const char *str) {
+        os << "\"";
+
+        const unsigned char *src = (const unsigned char *)str;
+        unsigned char c;
+        while ((c = *src++)) {
+            if ((c == '\"') ||
+                (c == '\\')) {
+                // escape character
+                os << '\\' << (unsigned char)c;
+            } else if ((c >= 0x20 && c <= 0x7e) ||
+                        c == '\t' ||
+                        c == '\r' ||
+                        c == '\n') {
+                // pass-through character
+                os << (unsigned char)c;
+            } else {
+                assert(0);
+                os << "?";
+            }
+        }
+
+        os << "\"";
+    }
+
+    void escapeUnicodeString(const char *str) {
+        os << "\"";
+
+        const char *locale = setlocale(LC_CTYPE, "");
+        const char *src = str;
+        mbstate_t state;
+
+        memset(&state, 0, sizeof state);
+
+        do {
+            // Convert characters one at a time in order to recover from
+            // conversion errors
+            wchar_t c;
+            size_t written = mbsrtowcs(&c, &src, 1, &state);
+            if (written == 0) {
+                // completed
+                break;
+            } if (written == (size_t)-1) {
+                // conversion error -- skip 
+                os << "?";
+                do {
+                    ++src;
+                } while (*src & 0x80);
+            } else if ((c == '\"') ||
+                       (c == '\\')) {
+                // escape character
+                os << '\\' << (unsigned char)c;
+            } else if ((c >= 0x20 && c <= 0x7e) ||
+                        c == '\t' ||
+                        c == '\r' ||
+                        c == '\n') {
+                // pass-through character
+                os << (unsigned char)c;
+            } else {
+                // unicode
+                os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
+                os << std::dec;
+            }
+        } while (src);
+
+        setlocale(LC_CTYPE, locale);
+
+        os << "\"";
+    }
+
+    void encodeBase64String(const unsigned char *bytes, size_t size) {
+        const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        unsigned char c0, c1, c2, c3;
+        char buf[4];
+        unsigned written;
+
+        os << "\"";
+
+        written = 0;
+        while (size >= 3) {
+            c0 = bytes[0] >> 2;
+            c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
+            c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
+            c3 = bytes[2] & 0x3f;
+
+            buf[0] = table64[c0];
+            buf[1] = table64[c1];
+            buf[2] = table64[c2];
+            buf[3] = table64[c3];
+
+            os.write(buf, 4);
+
+            bytes += 3;
+            size -= 3;
+            ++written;
+
+            if (written >= 76/4 && size) {
+                os << "\n";
+                written = 0;
+            }
+        }
+
+        if (size > 0) {
+            c0 = bytes[0] >> 2;
+            c1 = ((bytes[0] & 0x03) << 4);
+            buf[2] = '=';
+            buf[3] = '=';
+            
+            if (size > 1) {
+                c1 |= ((bytes[1] & 0xf0) >> 4);
+                c2 = ((bytes[1] & 0x0f) << 2);
+                if (size > 2) {
+                    c2 |= ((bytes[2] & 0xc0) >> 6);
+                    c3 = bytes[2] & 0x3f;
+                    buf[3] = table64[c3];
+                }
+                buf[2] = table64[c2];
+            }
+            buf[1] = table64[c1];
+            buf[0] = table64[c0];
+
+            os.write(buf, 4);
+        }
+
+        os << "\"";
+    }
+
+public:
+    JSONWriter(std::ostream &_os) : 
+        os(_os), 
+        level(0),
+        value(false),
+        space(0)
+    {
+        beginObject();
+    }
+
+    ~JSONWriter() {
+        endObject();
+        newline();
+    }
+
+    inline void beginObject() {
+        separator();
+        os << "{";
+        ++level;
+        value = false;
+    }
+
+    inline void endObject() {
+        --level;
+        if (value)
+            newline();
+        os << "}";
+        value = true;
+        space = '\n';
+    }
+
+    inline void beginMember(const char * name) {
+        space = 0;
+        separator();
+        newline();
+        escapeAsciiString(name);
+        os << ": ";
+        value = false;
+    }
+
+    inline void beginMember(const std::string &name) {
+        beginMember(name.c_str());
+    }
+
+    inline void endMember(void) {
+        assert(value);
+        value = true;
+        space = 0;
+    }
+
+    inline void beginArray() {
+        separator();
+        os << "[";
+        ++level;
+        value = false;
+        space = 0;
+    }
+
+    inline void endArray(void) {
+        --level;
+        if (space == '\n') {
+            newline();
+        }
+        os << "]";
+        value = true;
+        space = '\n';
+    }
+
+    inline void writeString(const char *s) {
+        separator();
+        escapeUnicodeString(s);
+        value = true;
+        space = ' ';
+    }
+
+    inline void writeString(const std::string &s) {
+        writeString(s.c_str());
+    }
+
+    inline void writeBase64(const void *bytes, size_t size) {
+        separator();
+        encodeBase64String((const unsigned char *)bytes, size);
+        value = true;
+        space = ' ';
+    }
+
+    inline void writeNull(void) {
+        separator();
+        os << "null";
+        value = true;
+        space = ' ';
+    }
+
+    inline void writeBool(bool b) {
+        separator();
+        os << (b ? "true" : "false");
+        value = true;
+        space = ' ';
+    }
+
+    template<class T>
+    inline void writeNumber(T n) {
+        if (n != n) {
+            // NaN
+            writeNull();
+        } else {
+            separator();
+            os << std::dec << std::setprecision(9) << n;
+            value = true;
+            space = ' ';
+        }
+    }
+    
+    inline void writeStringMember(const char *name, const char *s) {
+        beginMember(name);
+        writeString(s);
+        endMember();
+    }
+
+    inline void writeBoolMember(const char *name, bool b) {
+        beginMember(name);
+        writeBool(b);
+        endMember();
+    }
+
+    template<class T>
+    inline void writeNumberMember(const char *name, T n) {
+        beginMember(name);
+        writeNumber(n);
+        endMember();
+    }
+};
+
+#endif /* _JSON_HPP_ */
diff --git a/common/os.hpp b/common/os.hpp
new file mode 100644 (file)
index 0000000..8e487b5
--- /dev/null
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Simple OS abstraction layer.
+ */
+
+#ifndef _OS_HPP_
+#define _OS_HPP_
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+#define PATH_SEP '\\'
+#else /* !_WIN32 */
+#define PATH_SEP '/'
+#endif /* !_WIN32 */
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+namespace OS {
+
+void AcquireMutex(void);
+
+void ReleaseMutex(void);
+
+bool GetProcessName(char *str, size_t size);
+bool GetCurrentDir(char *str, size_t size);
+
+void DebugMessage(const char *format, ...)
+#ifdef __GNUC__
+    __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+
+#if defined _WIN32 || defined __CYGWIN__
+  /* We always use .def files on windows for now */
+  #if 0
+  #define PUBLIC __declspec(dllexport)
+  #else
+  #define PUBLIC
+  #endif
+  #define PRIVATE
+#else
+  #if __GNUC__ >= 4
+    #define PUBLIC __attribute__ ((visibility("default")))
+    #define PRIVATE __attribute__ ((visibility("hidden")))
+  #else
+    #define PUBLIC
+    #define PRIVATE
+  #endif
+#endif
+
+/**
+ * Get the current time in microseconds from an unknown base.
+ */
+long long GetTime(void);
+
+void Abort(void);
+
+void SetExceptionCallback(void (*callback)(void));
+void ResetExceptionCallback(void);
+
+} /* namespace OS */
+
+#endif /* _OS_HPP_ */
diff --git a/common/os_posix.cpp b/common/os_posix.cpp
new file mode 100644 (file)
index 0000000..98a790b
--- /dev/null
@@ -0,0 +1,236 @@
+/**************************************************************************
+ *
+ * Copyright 2010-2011 VMware, Inc.
+ * 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 <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
+
+#include "os.hpp"
+
+
+namespace OS {
+
+
+static pthread_mutex_t 
+mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+void
+AcquireMutex(void)
+{
+    pthread_mutex_lock(&mutex);
+}
+
+
+void
+ReleaseMutex(void)
+{
+    pthread_mutex_unlock(&mutex);
+}
+
+
+bool
+GetProcessName(char *str, size_t size)
+{
+    char szProcessPath[PATH_MAX + 1];
+    char *lpProcessName;
+
+    // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
+#ifdef __APPLE__
+    uint32_t len = sizeof szProcessPath;
+    if (_NSGetExecutablePath(szProcessPath, &len) != 0) {
+        *str = 0;
+        return false;
+    }
+#else
+    ssize_t len;
+    len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1);
+    if (len == -1) {
+        // /proc/self/exe is not available on setuid processes, so fallback to
+        // /proc/self/cmdline.
+        int fd = open("/proc/self/cmdline", O_RDONLY);
+        if (fd >= 0) {
+            len = read(fd, szProcessPath, sizeof(szProcessPath) - 1);
+            close(fd);
+        }
+    }
+    if (len <= 0) {
+        snprintf(str, size, "%i", (int)getpid());
+        return true;
+    }
+#endif
+    szProcessPath[len] = 0;
+
+    lpProcessName = strrchr(szProcessPath, '/');
+    lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+
+    strncpy(str, lpProcessName, size);
+    if (size)
+        str[size - 1] = 0;
+
+    return true;
+}
+
+bool
+GetCurrentDir(char *str, size_t size)
+{
+    char *ret;
+    ret = getcwd(str, size);
+    str[size - 1] = 0;
+    return ret ? true : false;
+}
+
+void
+DebugMessage(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    fflush(stdout);
+    vfprintf(stderr, format, ap);
+    va_end(ap);
+}
+
+long long GetTime(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return tv.tv_usec + tv.tv_sec*1000000LL;
+}
+
+void
+Abort(void)
+{
+    exit(0);
+}
+
+
+static void (*gCallback)(void) = NULL;
+
+#define NUM_SIGNALS 16
+
+struct sigaction old_actions[NUM_SIGNALS];
+
+
+/*
+ * See also:
+ * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c
+ * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup
+ */
+static void signal_handler(int sig, siginfo_t *info, void *context)
+{
+    static int recursion_count = 0;
+
+    fprintf(stderr, "signal_handler: sig = %i\n", sig);
+
+    if (recursion_count) {
+        fprintf(stderr, "recursion with sig %i\n", sig);
+    } else {
+        if (gCallback) {
+            ++recursion_count;
+            gCallback();
+            --recursion_count;
+        }
+    }
+
+    struct sigaction *old_action;
+    if (sig >= NUM_SIGNALS) {
+        /* This should never happen */
+        fprintf(stderr, "Unexpected signal %i\n", sig);
+        raise(SIGKILL);
+    }
+    old_action = &old_actions[sig];
+
+    if (old_action->sa_flags & SA_SIGINFO) {
+        // Handler is in sa_sigaction
+        old_action->sa_sigaction(sig, info, context);
+    } else {
+        if (old_action->sa_handler == SIG_DFL) {
+            fprintf(stderr, "taking default action for signal %i\n", sig);
+
+#if 1
+            struct sigaction dfl_action;
+            dfl_action.sa_handler = SIG_DFL;
+            sigemptyset (&dfl_action.sa_mask);
+            dfl_action.sa_flags = 0;
+            sigaction(sig, &dfl_action, NULL);
+
+            raise(sig);
+#else
+            raise(SIGKILL);
+#endif
+        } else if (old_action->sa_handler == SIG_IGN) {
+            /* ignore */
+        } else {
+            /* dispatch to handler */
+            old_action->sa_handler(sig);
+        }
+    }
+}
+
+void
+SetExceptionCallback(void (*callback)(void))
+{
+    assert(!gCallback);
+    if (!gCallback) {
+        gCallback = callback;
+
+        struct sigaction new_action;
+        new_action.sa_sigaction = signal_handler;
+        sigemptyset(&new_action.sa_mask);
+        new_action.sa_flags = SA_SIGINFO | SA_RESTART;
+
+
+        for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
+            // SIGKILL and SIGSTOP can't be handled
+            if (sig != SIGKILL && sig != SIGSTOP) {
+                if (sigaction(sig,  NULL, &old_actions[sig]) >= 0) {
+                    sigaction(sig,  &new_action, NULL);
+                }
+            }
+        }
+    }
+}
+
+void
+ResetExceptionCallback(void)
+{
+    gCallback = NULL;
+}
+
+} /* namespace OS */
+
diff --git a/common/os_win32.cpp b/common/os_win32.cpp
new file mode 100644 (file)
index 0000000..587503c
--- /dev/null
@@ -0,0 +1,175 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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 <windows.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "os.hpp"
+
+
+namespace OS {
+
+
+/* 
+ * Trick from http://locklessinc.com/articles/pthreads_on_windows/
+ */
+static CRITICAL_SECTION
+CriticalSection = {
+    (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
+};
+
+
+void
+AcquireMutex(void)
+{
+    EnterCriticalSection(&CriticalSection); 
+}
+
+
+void
+ReleaseMutex(void)
+{
+    LeaveCriticalSection(&CriticalSection); 
+}
+
+
+bool
+GetProcessName(char *str, size_t size)
+{
+    char szProcessPath[PATH_MAX];
+    char *lpProcessName;
+    char *lpProcessExt;
+
+    GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
+
+    lpProcessName = strrchr(szProcessPath, '\\');
+    lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+
+    lpProcessExt = strrchr(lpProcessName, '.');
+    if (lpProcessExt) {
+        *lpProcessExt = '\0';
+    }
+
+    strncpy(str, lpProcessName, size);
+
+    return true;
+}
+
+bool
+GetCurrentDir(char *str, size_t size)
+{
+    DWORD ret;
+    ret = GetCurrentDirectoryA(size, str);
+    str[size - 1] = 0;
+    return ret == 0 ? false : true;
+}
+
+void
+DebugMessage(const char *format, ...)
+{
+    char buf[4096];
+
+    va_list ap;
+    va_start(ap, format);
+    fflush(stdout);
+    vsnprintf(buf, sizeof buf, format, ap);
+    va_end(ap);
+
+    OutputDebugStringA(buf);
+
+    /*
+     * Also write the message to stderr, when a debugger is not present (to
+     * avoid duplicate messages in command line debuggers).
+     */
+#if _WIN32_WINNT > 0x0400
+    if (!IsDebuggerPresent()) {
+        fflush(stdout);
+        fputs(buf, stderr);
+        fflush(stderr);
+    }
+#endif
+}
+
+long long GetTime(void)
+{
+    static LARGE_INTEGER frequency;
+    LARGE_INTEGER counter;
+    if (!frequency.QuadPart)
+        QueryPerformanceFrequency(&frequency);
+    QueryPerformanceCounter(&counter);
+    return counter.QuadPart*1000000LL/frequency.QuadPart;
+}
+
+void
+Abort(void)
+{
+#ifndef NDEBUG
+    DebugBreak();
+#else
+    ExitProcess(0);
+#endif
+}
+
+
+static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
+static void (*gCallback)(void) = NULL;
+
+static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
+{
+    if (gCallback) {
+        gCallback();
+    }
+
+       if (prevExceptionFilter) {
+               return prevExceptionFilter(pExceptionInfo);
+    } else {
+               return EXCEPTION_CONTINUE_SEARCH;
+    }
+}
+
+void
+SetExceptionCallback(void (*callback)(void))
+{
+    assert(!gCallback);
+
+    if (!gCallback) {
+        gCallback = callback;
+
+        assert(!prevExceptionFilter);
+        prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
+    }
+}
+
+void
+ResetExceptionCallback(void)
+{
+    gCallback = NULL;
+}
+
+
+} /* namespace OS */
diff --git a/common/trace_file.cpp b/common/trace_file.cpp
new file mode 100644 (file)
index 0000000..f48c1aa
--- /dev/null
@@ -0,0 +1,180 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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 "trace_file.hpp"
+
+#include "trace_snappyfile.hpp"
+
+#include <assert.h>
+#include <string.h>
+
+#include <zlib.h>
+
+#include "os.hpp"
+
+#include <iostream>
+
+using namespace Trace;
+
+
+File::File(const std::string &filename,
+           File::Mode mode)
+    : m_mode(mode),
+      m_isOpened(false)
+{
+    if (!filename.empty()) {
+        open(filename, m_mode);
+    }
+}
+
+File::~File()
+{
+    close();
+}
+
+
+void File::setCurrentOffset(const File::Offset &offset)
+{
+    assert(0);
+}
+
+bool File::isZLibCompressed(const std::string &filename)
+{
+    std::fstream stream(filename.c_str(),
+                        std::fstream::binary | std::fstream::in);
+    if (!stream.is_open())
+        return false;
+
+    unsigned char byte1, byte2;
+    stream >> byte1;
+    stream >> byte2;
+    stream.close();
+
+    return (byte1 == 0x1f && byte2 == 0x8b);
+}
+
+
+bool File::isSnappyCompressed(const std::string &filename)
+{
+    std::fstream stream(filename.c_str(),
+                        std::fstream::binary | std::fstream::in);
+    if (!stream.is_open())
+        return false;
+
+    unsigned char byte1, byte2;
+    stream >> byte1;
+    stream >> byte2;
+    stream.close();
+
+    return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
+}
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+} gz_dummy_stream;
+
+ZLibFile::ZLibFile(const std::string &filename,
+                   File::Mode mode)
+    : File(filename, mode),
+      m_gzFile(NULL)
+{
+}
+
+ZLibFile::~ZLibFile()
+{
+}
+
+bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
+{
+    m_gzFile = gzopen(filename.c_str(),
+                      (mode == File::Write) ? "wb" : "rb");
+
+    if (mode == File::Read && m_gzFile) {
+        //XXX: unfortunately zlib doesn't support
+        //     SEEK_END or we could've done:
+        //m_endOffset = gzseek(m_gzFile, 0, SEEK_END);
+        //gzrewind(m_gzFile);
+        gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+        long loc = ftell(stream->file);
+        fseek(stream->file,0,SEEK_END);
+        m_endOffset = ftell(stream->file);
+        fseek(stream->file, loc, SEEK_SET);
+    }
+
+    return m_gzFile != NULL;
+}
+
+bool ZLibFile::rawWrite(const void *buffer, size_t length)
+{
+    return gzwrite(m_gzFile, buffer, length) != -1;
+}
+
+bool ZLibFile::rawRead(void *buffer, size_t length)
+{
+    return gzread(m_gzFile, buffer, length) != -1;
+}
+
+int ZLibFile::rawGetc()
+{
+    return gzgetc(m_gzFile);
+}
+
+void ZLibFile::rawClose()
+{
+    if (m_gzFile) {
+        gzclose(m_gzFile);
+        m_gzFile = NULL;
+    }
+}
+
+void ZLibFile::rawFlush()
+{
+    gzflush(m_gzFile, Z_SYNC_FLUSH);
+}
+
+File::Offset ZLibFile::currentOffset()
+{
+    return File::Offset(gztell(m_gzFile));
+}
+
+bool ZLibFile::supportsOffsets() const
+{
+    return false;
+}
+
+bool ZLibFile::rawSkip(size_t)
+{
+    return false;
+}
+
+int ZLibFile::rawPercentRead()
+{
+    gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+    return 100 * (ftell(stream->file) / m_endOffset);
+}
diff --git a/common/trace_file.hpp b/common/trace_file.hpp
new file mode 100644 (file)
index 0000000..4b1b70d
--- /dev/null
@@ -0,0 +1,224 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#ifndef TRACE_FILE_HPP
+#define TRACE_FILE_HPP
+
+#include <string>
+#include <fstream>
+#include <stdint.h>
+
+namespace Trace {
+
+class File {
+public:
+    enum Mode {
+        Read,
+        Write
+    };
+    struct Offset {
+        Offset(uint64_t _chunk = 0, uint32_t _offsetInChunk = 0)
+            : chunk(_chunk),
+              offsetInChunk(_offsetInChunk)
+        {}
+        uint64_t chunk;
+        uint32_t offsetInChunk;
+    };
+
+public:
+    static bool isZLibCompressed(const std::string &filename);
+    static bool isSnappyCompressed(const std::string &filename);
+public:
+    File(const std::string &filename = std::string(),
+         File::Mode mode = File::Read);
+    virtual ~File();
+
+    bool isOpened() const;
+    File::Mode mode() const;
+
+    bool open(const std::string &filename, File::Mode mode);
+    bool write(const void *buffer, size_t length);
+    bool read(void *buffer, size_t length);
+    void close();
+    void flush(void);
+    int getc();
+    bool skip(size_t length);
+    int percentRead();
+
+    virtual bool supportsOffsets() const = 0;
+    virtual File::Offset currentOffset() = 0;
+    virtual void setCurrentOffset(const File::Offset &offset);
+protected:
+    virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0;
+    virtual bool rawWrite(const void *buffer, size_t length) = 0;
+    virtual bool rawRead(void *buffer, size_t length) = 0;
+    virtual int rawGetc() = 0;
+    virtual void rawClose() = 0;
+    virtual void rawFlush() = 0;
+    virtual bool rawSkip(size_t length) = 0;
+    virtual int rawPercentRead() = 0;
+
+protected:
+    File::Mode m_mode;
+    bool m_isOpened;
+};
+
+inline bool File::isOpened() const
+{
+    return m_isOpened;
+}
+
+inline File::Mode File::mode() const
+{
+    return m_mode;
+}
+
+inline bool File::open(const std::string &filename, File::Mode mode)
+{
+    if (m_isOpened) {
+        close();
+    }
+    m_isOpened = rawOpen(filename, mode);
+    m_mode = mode;
+
+    return m_isOpened;
+}
+
+inline bool File::write(const void *buffer, size_t length)
+{
+    if (!m_isOpened || m_mode != File::Write) {
+        return false;
+    }
+    return rawWrite(buffer, length);
+}
+
+inline bool File::read(void *buffer, size_t length)
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return false;
+    }
+    return rawRead(buffer, length);
+}
+
+inline int File::percentRead()
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return 0;
+    }
+    return rawPercentRead();
+}
+
+inline void File::close()
+{
+    if (m_isOpened) {
+        rawClose();
+        m_isOpened = false;
+    }
+}
+
+inline void File::flush(void)
+{
+    if (m_mode == File::Write) {
+        rawFlush();
+    }
+}
+
+inline int File::getc()
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return -1;
+    }
+    return rawGetc();
+}
+
+inline bool File::skip(size_t length)
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return false;
+    }
+    return rawSkip(length);
+}
+
+class ZLibFile : public File {
+public:
+    ZLibFile(const std::string &filename = std::string(),
+             File::Mode mode = File::Read);
+    virtual ~ZLibFile();
+
+
+    virtual bool supportsOffsets() const;
+    virtual File::Offset currentOffset();
+protected:
+    virtual bool rawOpen(const std::string &filename, File::Mode mode);
+    virtual bool rawWrite(const void *buffer, size_t length);
+    virtual bool rawRead(void *buffer, size_t length);
+    virtual int rawGetc();
+    virtual void rawClose();
+    virtual void rawFlush();
+    virtual bool rawSkip(size_t length);
+    virtual int  rawPercentRead();
+private:
+    void *m_gzFile;
+    double m_endOffset;
+};
+
+inline bool
+operator<(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk < two.chunk ||
+            (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk);
+}
+
+inline bool
+operator==(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk == two.chunk &&
+            one.offsetInChunk == two.offsetInChunk;
+}
+
+inline bool
+operator>=(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk > two.chunk ||
+            (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk);
+}
+
+inline bool
+operator>(const File::Offset &one, const File::Offset &two)
+{
+    return two < one;
+}
+
+inline bool
+operator<=(const File::Offset &one, const File::Offset &two)
+{
+    return two >= one;
+}
+
+
+}
+
+#endif
diff --git a/common/trace_format.hpp b/common/trace_format.hpp
new file mode 100644 (file)
index 0000000..a8ee5eb
--- /dev/null
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace binary format.
+ *
+ * Grammar:
+ *
+ *   trace = event* EOF
+ *
+ *   event = EVENT_ENTER call_sig call_detail+
+ *         | EVENT_LEAVE call_no call_detail+
+ *
+ *   call_sig = sig_id ( name arg_names )?
+ *
+ *   call_detail = ARG index value
+ *               | RET value
+ *               | END
+ *
+ *   value = NULL
+ *         | FALSE
+ *         | TRUE
+ *         | SINT int
+ *         | UINT int
+ *         | FLOAT float
+ *         | DOUBLE double
+ *         | STRING string
+ *         | BLOB string
+ *         | ENUM enum_sig
+ *         | BITMASK bitmask_sig value
+ *         | ARRAY length value+
+ *         | STRUCT struct_sig value+
+ *         | OPAQUE int
+ *
+ *   call_sig = id name arg_name*
+ *            | id
+ *
+ *   enum_sig = id name value
+ *            | id
+ *
+ *   bitmask_sig = id count (name value)+
+ *               | id
+ *
+ *   string = length (BYTE)*
+ *
+ */
+
+#ifndef _TRACE_FORMAT_HPP_
+#define _TRACE_FORMAT_HPP_
+
+namespace Trace {
+
+#define TRACE_VERSION 1
+
+enum Event {
+    EVENT_ENTER = 0,
+    EVENT_LEAVE,
+};
+
+enum CallDetail {
+    CALL_END = 0,
+    CALL_ARG,
+    CALL_RET,
+    CALL_THREAD,
+};
+
+enum Type {
+    TYPE_NULL = 0,
+    TYPE_FALSE,
+    TYPE_TRUE,
+    TYPE_SINT,
+    TYPE_UINT,
+    TYPE_FLOAT,
+    TYPE_DOUBLE,
+    TYPE_STRING, // Null terminated, human readible string
+    TYPE_BLOB, // Block of bytes
+    TYPE_ENUM,
+    TYPE_BITMASK,
+    TYPE_ARRAY,
+    TYPE_STRUCT,
+    TYPE_OPAQUE,
+};
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_FORMAT_HPP_ */
diff --git a/common/trace_loader.cpp b/common/trace_loader.cpp
new file mode 100644 (file)
index 0000000..c14d815
--- /dev/null
@@ -0,0 +1,139 @@
+#include "trace_loader.hpp"
+
+
+using namespace Trace;
+
+Loader::Loader()
+    : m_frameMarker(FrameMarker_SwapBuffers)
+{
+}
+
+Loader::~Loader()
+{
+    close();
+}
+
+Loader::FrameMarker Loader::frameMarker() const
+{
+    return m_frameMarker;
+}
+
+void Loader::setFrameMarker(Loader::FrameMarker marker)
+{
+    m_frameMarker = marker;
+}
+
+int Loader::numberOfFrames() const
+{
+    return m_frameBookmarks.size();
+}
+
+int Loader::numberOfCallsInFrame(int frameIdx) const
+{
+    if (frameIdx > m_frameBookmarks.size()) {
+        return 0;
+    }
+    FrameBookmarks::const_iterator itr =
+        m_frameBookmarks.find(frameIdx);
+    return itr->second.numberOfCalls;
+}
+
+bool Loader::open(const char *filename)
+{
+    if (!m_parser.open(filename)) {
+        std::cerr << "error: failed to open " << filename << "\n";
+        return false;
+    }
+    if (!m_parser.supportsOffsets()) {
+        std::cerr << "error: " <<filename<< " doesn't support seeking "
+                  << "\n";
+        return false;
+    }
+
+    Trace::Call *call;
+    ParseBookmark startBookmark;
+    int numOfFrames = 0;
+    int numOfCalls = 0;
+    int lastPercentReport = 0;
+
+    m_parser.getBookmark(startBookmark);
+
+    while ((call = m_parser.scan_call())) {
+        ++numOfCalls;
+
+        if (isCallAFrameMarker(call)) {
+            FrameBookmark frameBookmark(startBookmark);
+            frameBookmark.numberOfCalls = numOfCalls;
+
+            m_frameBookmarks[numOfFrames] = frameBookmark;
+            ++numOfFrames;
+
+            if (m_parser.percentRead() - lastPercentReport >= 5) {
+                std::cerr << "\tPercent scanned = "
+                          << m_parser.percentRead()
+                          << "..."<<std::endl;
+                lastPercentReport = m_parser.percentRead();
+            }
+            
+            m_parser.getBookmark(startBookmark);
+            numOfCalls = 0;
+        }
+        //call->dump(std::cout, color);
+        delete call;
+    }
+    return true;
+}
+
+void Loader::close()
+{
+    m_parser.close();
+}
+
+bool Loader::isCallAFrameMarker(const Trace::Call *call) const
+{
+    std::string name = call->name();
+
+    switch (m_frameMarker) {
+    case FrameMarker_SwapBuffers:
+        return  name.find("SwapBuffers") != std::string::npos ||
+                name == "CGLFlushDrawable" ||
+                name == "glFrameTerminatorGREMEDY";
+        break;
+    case FrameMarker_Flush:
+        return name == "glFlush";
+        break;
+    case FrameMarker_Finish:
+        return name == "glFinish";
+        break;
+    case FrameMarker_Clear:
+        return name == "glClear";
+        break;
+    }
+    return false;
+}
+
+std::vector<Trace::Call *> Loader::frame(int idx)
+{
+    int numOfCalls = numberOfCallsInFrame(idx);
+    if (numOfCalls) {
+        const FrameBookmark &frameBookmark = m_frameBookmarks[idx];
+        std::vector<Trace::Call*> calls(numOfCalls);
+        m_parser.setBookmark(frameBookmark.start);
+
+        Trace::Call *call;
+        int parsedCalls = 0;
+        while ((call = m_parser.parse_call())) {
+
+            calls[parsedCalls] = call;
+            ++parsedCalls;
+
+            if (isCallAFrameMarker(call)) {
+                break;
+            }
+
+        }
+        assert(parsedCalls == numOfCalls);
+        return calls;
+    }
+    return std::vector<Trace::Call*>();
+}
diff --git a/common/trace_loader.hpp b/common/trace_loader.hpp
new file mode 100644 (file)
index 0000000..9f74a9b
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef TRACE_LOADER_HPP
+#define TRACE_LOADER_HPP
+
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <string>
+#include <map>
+#include <queue>
+#include <vector>
+
+namespace Trace  {
+
+class Frame;
+
+class Loader
+{
+public:
+    enum FrameMarker {
+        FrameMarker_SwapBuffers,
+        FrameMarker_Flush,
+        FrameMarker_Finish,
+        FrameMarker_Clear
+    };
+public:
+    Loader();
+    ~Loader();
+
+    Loader::FrameMarker frameMarker() const;
+    void setFrameMarker(Loader::FrameMarker marker);
+
+    int numberOfFrames() const;
+    int numberOfCallsInFrame(int frameIdx) const;
+
+    bool open(const char *filename);
+    void close();
+
+    std::vector<Trace::Call*> frame(int idx);
+
+private:
+    struct FrameBookmark {
+        FrameBookmark()
+            : numberOfCalls(0)
+        {}
+        FrameBookmark(const ParseBookmark &s)
+            : start(s),
+              numberOfCalls(0)
+        {}
+
+        ParseBookmark start;
+        int numberOfCalls;
+    };
+    bool isCallAFrameMarker(const Trace::Call *call) const;
+
+private:
+    Trace::Parser m_parser;
+    FrameMarker m_frameMarker;
+
+    typedef std::map<int, FrameBookmark> FrameBookmarks;
+    FrameBookmarks m_frameBookmarks;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
diff --git a/common/trace_local_writer.cpp b/common/trace_local_writer.cpp
new file mode 100644 (file)
index 0000000..e625f2e
--- /dev/null
@@ -0,0 +1,158 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2011 VMware, Inc.
+ * 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "os.hpp"
+#include "trace_file.hpp"
+#include "trace_writer.hpp"
+#include "trace_format.hpp"
+
+
+namespace Trace {
+
+
+static void exceptionCallback(void)
+{
+    localWriter.flush();
+}
+
+
+LocalWriter::LocalWriter() :
+    acquired(0)
+{
+    // Install the signal handlers as early as possible, to prevent
+    // interfering with the application's signal handling.
+    OS::SetExceptionCallback(exceptionCallback);
+}
+
+LocalWriter::~LocalWriter()
+{
+    OS::ResetExceptionCallback();
+}
+
+void
+LocalWriter::open(void) {
+
+    static unsigned dwCounter = 0;
+
+    const char *szExtension = "trace";
+    char szFileName[PATH_MAX];
+    const char *lpFileName;
+
+    lpFileName = getenv("TRACE_FILE");
+    if (lpFileName) {
+        strncpy(szFileName, lpFileName, PATH_MAX);
+    }
+    else {
+        char szProcessName[PATH_MAX];
+        char szCurrentDir[PATH_MAX];
+        OS::GetProcessName(szProcessName, PATH_MAX);
+        OS::GetCurrentDir(szCurrentDir, PATH_MAX);
+
+        for (;;) {
+            FILE *file;
+
+            if (dwCounter)
+                snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
+            else
+                snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
+
+            file = fopen(szFileName, "rb");
+            if (file == NULL)
+                break;
+
+            fclose(file);
+
+            ++dwCounter;
+        }
+    }
+
+    OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
+
+    Writer::open(szFileName);
+
+#if 0
+    // For debugging the exception handler
+    *((int *)0) = 0;
+#endif
+}
+
+unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
+    OS::AcquireMutex();
+    ++acquired;
+
+    if (!m_file->isOpened()) {
+        open();
+    }
+
+    return Writer::beginEnter(sig);
+}
+
+void LocalWriter::endEnter(void) {
+    Writer::endEnter();
+    --acquired;
+    OS::ReleaseMutex();
+}
+
+void LocalWriter::beginLeave(unsigned call) {
+    OS::AcquireMutex();
+    ++acquired;
+    Writer::beginLeave(call);
+}
+
+void LocalWriter::endLeave(void) {
+    Writer::endLeave();
+    --acquired;
+    OS::ReleaseMutex();
+}
+
+void LocalWriter::flush(void) {
+    /*
+     * Do nothing if the mutex is already acquired (e.g., if a segfault happen
+     * while writing the file) to prevent dead-lock.
+     */
+
+    if (!acquired) {
+        OS::AcquireMutex();
+        if (m_file->isOpened()) {
+            OS::DebugMessage("apitrace: flushing trace due to an exception\n");
+            m_file->flush();
+        }
+        OS::ReleaseMutex();
+    }
+}
+
+
+LocalWriter localWriter;
+
+
+} /* namespace Trace */
+
diff --git a/common/trace_model.cpp b/common/trace_model.cpp
new file mode 100644 (file)
index 0000000..306b9e7
--- /dev/null
@@ -0,0 +1,379 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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 "formatter.hpp"
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+Call::~Call() {
+    for (unsigned i = 0; i < args.size(); ++i) {
+        delete args[i];
+    }
+
+    if (ret) {
+        delete ret;
+    }
+}
+
+
+String::~String() {
+    delete [] value;
+}
+
+
+Struct::~Struct() {
+    for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
+        delete *it;
+    }
+}
+
+
+Array::~Array() {
+    for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
+        delete *it;
+    }
+}
+
+Blob::~Blob() {
+    // Blobs are often bound and referred during many calls, so we can't delete
+    // them here in that case.
+    //
+    // Once bound there is no way to know when they were unbound, which
+    // effectively means we have to leak them.  A better solution would be to
+    // keep a list of bound pointers, and defer the destruction to when the
+    // trace in question has been fully processed.
+    if (!bound) {
+        delete [] buf;
+    }
+}
+
+
+// bool cast
+bool Null   ::toBool(void) const { return false; }
+bool Bool   ::toBool(void) const { return value; }
+bool SInt   ::toBool(void) const { return value != 0; }
+bool UInt   ::toBool(void) const { return value != 0; }
+bool Float  ::toBool(void) const { return value != 0; }
+bool String ::toBool(void) const { return true; }
+bool Enum   ::toBool(void) const { return sig->value != 0; }
+bool Struct ::toBool(void) const { return true; }
+bool Array  ::toBool(void) const { return true; }
+bool Blob   ::toBool(void) const { return true; }
+bool Pointer::toBool(void) const { return value != 0; }
+
+
+// signed integer cast
+signed long long Value  ::toSInt(void) const { assert(0); return 0; }
+signed long long Null   ::toSInt(void) const { return 0; }
+signed long long Bool   ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long SInt   ::toSInt(void) const { return value; }
+signed long long UInt   ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
+signed long long Float  ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long Enum   ::toSInt(void) const { return sig->value; }
+
+
+// unsigned integer cast
+unsigned long long Value  ::toUInt(void) const { assert(0); return 0; }
+unsigned long long Null   ::toUInt(void) const { return 0; }
+unsigned long long Bool   ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long SInt   ::toUInt(void) const { assert(value >= 0); return static_cast<signed long long>(value); }
+unsigned long long UInt   ::toUInt(void) const { return value; }
+unsigned long long Float  ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long Enum   ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
+
+
+// floating point cast
+float Value  ::toFloat(void) const { assert(0); return 0; }
+float Null   ::toFloat(void) const { return 0; }
+float Bool   ::toFloat(void) const { return static_cast<float>(value); }
+float SInt   ::toFloat(void) const { return static_cast<float>(value); }
+float UInt   ::toFloat(void) const { return static_cast<float>(value); }
+float Float  ::toFloat(void) const { return value; }
+float Enum   ::toFloat(void) const { return static_cast<float>(sig->value); }
+
+
+// floating point cast
+double Value  ::toDouble(void) const { assert(0); return 0; }
+double Null   ::toDouble(void) const { return 0; }
+double Bool   ::toDouble(void) const { return static_cast<double>(value); }
+double SInt   ::toDouble(void) const { return static_cast<double>(value); }
+double UInt   ::toDouble(void) const { return static_cast<double>(value); }
+double Float  ::toDouble(void) const { return value; }
+double Enum   ::toDouble(void) const { return static_cast<double>(sig->value); }
+
+
+// pointer cast
+void * Value  ::toPointer(void) const { assert(0); return NULL; }
+void * Null   ::toPointer(void) const { return NULL; }
+void * Blob   ::toPointer(void) const { return buf; }
+void * Pointer::toPointer(void) const { return (void *)value; }
+
+void * Value  ::toPointer(bool bind) { assert(0); return NULL; }
+void * Null   ::toPointer(bool bind) { return NULL; }
+void * Blob   ::toPointer(bool bind) { if (bind) bound = true; return buf; }
+void * Pointer::toPointer(bool bind) { return (void *)value; }
+
+
+// pointer cast
+unsigned long long Value  ::toUIntPtr(void) const { assert(0); return 0; }
+unsigned long long Null   ::toUIntPtr(void) const { return 0; }
+unsigned long long Pointer::toUIntPtr(void) const { return value; }
+
+
+// string cast
+const char * Value ::toString(void) const { assert(0); return NULL; }
+const char * Null  ::toString(void) const { return NULL; }
+const char * String::toString(void) const { return value; }
+
+
+// virtual Value::visit()
+void Null   ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bool   ::visit(Visitor &visitor) { visitor.visit(this); }
+void SInt   ::visit(Visitor &visitor) { visitor.visit(this); }
+void UInt   ::visit(Visitor &visitor) { visitor.visit(this); }
+void Float  ::visit(Visitor &visitor) { visitor.visit(this); }
+void String ::visit(Visitor &visitor) { visitor.visit(this); }
+void Enum   ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
+void Struct ::visit(Visitor &visitor) { visitor.visit(this); }
+void Array  ::visit(Visitor &visitor) { visitor.visit(this); }
+void Blob   ::visit(Visitor &visitor) { visitor.visit(this); }
+void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
+
+
+void Visitor::visit(Null *) { assert(0); }
+void Visitor::visit(Bool *) { assert(0); }
+void Visitor::visit(SInt *) { assert(0); }
+void Visitor::visit(UInt *) { assert(0); }
+void Visitor::visit(Float *) { assert(0); }
+void Visitor::visit(String *) { assert(0); }
+void Visitor::visit(Enum *node) { assert(0); }
+void Visitor::visit(Bitmask *node) { visit(static_cast<UInt *>(node)); }
+void Visitor::visit(Struct *) { assert(0); }
+void Visitor::visit(Array *) { assert(0); }
+void Visitor::visit(Blob *) { assert(0); }
+void Visitor::visit(Pointer *) { assert(0); }
+
+
+class Dumper : public Visitor
+{
+protected:
+    std::ostream &os;
+    Formatter::Formatter *formatter;
+    Formatter::Attribute *normal;
+    Formatter::Attribute *bold;
+    Formatter::Attribute *italic;
+    Formatter::Attribute *red;
+    Formatter::Attribute *pointer;
+    Formatter::Attribute *literal;
+
+public:
+    Dumper(std::ostream &_os, bool color) : os(_os) {
+        formatter = Formatter::defaultFormatter(color);
+        normal = formatter->normal();
+        bold = formatter->bold();
+        italic = formatter->italic();
+        red = formatter->color(Formatter::RED);
+        pointer = formatter->color(Formatter::GREEN);
+        literal = formatter->color(Formatter::BLUE);
+    }
+
+    ~Dumper() {
+        delete normal;
+        delete bold;
+        delete italic;
+        delete red;
+        delete pointer;
+        delete literal;
+        delete formatter;
+    }
+
+    void visit(Null *) {
+        os << "NULL";
+    }
+
+    void visit(Bool *node) {
+        os << literal << (node->value ? "true" : "false") << normal;
+    }
+
+    void visit(SInt *node) {
+        os << literal << node->value << normal;
+    }
+
+    void visit(UInt *node) {
+        os << literal << node->value << normal;
+    }
+
+    void visit(Float *node) {
+        os << literal << node->value << normal;
+    }
+
+    void visit(String *node) {
+        os << literal << "\"";
+        for (const char *it = node->value; *it; ++it) {
+            unsigned char c = (unsigned char) *it;
+            if (c == '\"')
+                os << "\\\"";
+            else if (c == '\\')
+                os << "\\\\";
+            else if (c >= 0x20 && c <= 0x7e)
+                os << c;
+            else if (c == '\t') {
+                os << "\t";
+            } else if (c == '\r') {
+                // Ignore carriage-return
+            } else if (c == '\n') {
+                // Reset formatting so that it looks correct with 'less -R'
+                os << normal << '\n' << literal;
+            } else {
+                unsigned octal0 = c & 0x7;
+                unsigned octal1 = (c >> 3) & 0x7;
+                unsigned octal2 = (c >> 3) & 0x7;
+                os << "\\";
+                if (octal2)
+                    os << octal2;
+                if (octal1)
+                    os << octal1;
+                os << octal0;
+            }
+        }
+        os << "\"" << normal;
+    }
+
+    void visit(Enum *node) {
+        os << literal << node->sig->name << normal;
+    }
+
+    void visit(Bitmask *bitmask) {
+        unsigned long long value = bitmask->value;
+        const BitmaskSig *sig = bitmask->sig;
+        bool first = true;
+        for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) {
+            if ((it->value && (value & it->value) == it->value) ||
+                (!it->value && value == 0)) {
+                if (!first) {
+                    os << " | ";
+                }
+                os << literal << it->name << normal;
+                value &= ~it->value;
+                first = false;
+            }
+        }
+        if (value || first) {
+            if (!first) {
+                os << " | ";
+            }
+            os << literal << "0x" << std::hex << value << std::dec << normal;
+        }
+    }
+
+    void visit(Struct *s) {
+        const char *sep = "";
+        os << "{";
+        for (unsigned i = 0; i < s->members.size(); ++i) {
+            os << sep << italic << s->sig->member_names[i] << normal << " = ";
+            _visit(s->members[i]);
+            sep = ", ";
+        }
+        os << "}";
+    }
+
+    void visit(Array *array) {
+        if (array->values.size() == 1) {
+            os << "&";
+            _visit(array->values[0]);
+        }
+        else {
+            const char *sep = "";
+            os << "{";
+            for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
+                os << sep;
+                _visit(*it);
+                sep = ", ";
+            }
+            os << "}";
+        }
+    }
+
+    void visit(Blob *blob) {
+        os << pointer << "blob(" << blob->size << ")" << normal;
+    }
+
+    void visit(Pointer *p) {
+        os << pointer << "0x" << std::hex << p->value << std::dec << normal;
+    }
+
+    void visit(Call *call) {
+        const char *sep = "";
+        os << bold << call->sig->name << normal << "(";
+        for (unsigned i = 0; i < call->args.size(); ++i) {
+            os << sep << italic << call->sig->arg_names[i] << normal << " = ";
+            if (call->args[i]) {
+                _visit(call->args[i]);
+            } else {
+               os << "?";
+            }
+            sep = ", ";
+        }
+        os << ")";
+        if (call->ret) {
+            os << " = ";
+            _visit(call->ret);
+        }
+        os << "\n";
+    }
+};
+
+
+void Value::dump(std::ostream &os, bool color) {
+    Dumper d(os, color);
+    visit(d);
+}
+
+
+static Null null;
+
+const Value & Value::operator[](size_t index) const {
+    const Array *array = dynamic_cast<const Array *>(this);
+    if (array) {
+        if (index < array->values.size()) {
+            return *array->values[index];
+        }
+    }
+    return null;
+}
+
+void Call::dump(std::ostream &os, bool color) {
+    Dumper d(os, color);
+    os << no << " ";
+    d.visit(this);
+}
+
+
+} /* namespace Trace */
diff --git a/common/trace_model.hpp b/common/trace_model.hpp
new file mode 100644 (file)
index 0000000..a74508e
--- /dev/null
@@ -0,0 +1,357 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Object hierarchy for describing the traces in memory.
+ */
+
+#ifndef _TRACE_MODEL_HPP_
+#define _TRACE_MODEL_HPP_
+
+
+#include <assert.h>
+
+#include <map>
+#include <vector>
+#include <iostream>
+
+
+namespace Trace {
+
+
+typedef unsigned Id;
+
+
+struct FunctionSig {
+    Id id;
+    const char *name;
+    unsigned num_args;
+    const char **arg_names;
+};
+
+
+struct StructSig {
+    Id id;
+    const char *name;
+    unsigned num_members;
+    const char **member_names;
+};
+
+
+struct EnumSig {
+    Id id;
+    const char *name;
+    signed long long value;
+};
+
+
+struct BitmaskFlag {
+    const char *name;
+    unsigned long long value;
+};
+
+
+struct BitmaskSig {
+    Id id;
+    unsigned num_flags;
+    const BitmaskFlag *flags;
+};
+
+
+class Visitor;
+
+
+class Value
+{
+public:
+    virtual ~Value() {}
+    virtual void visit(Visitor &visitor) = 0;
+
+    virtual bool toBool(void) const = 0;
+    virtual signed long long toSInt(void) const;
+    virtual unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+
+    virtual void *toPointer(void) const;
+    virtual void *toPointer(bool bind);
+    virtual unsigned long long toUIntPtr(void) const;
+    virtual const char *toString(void) const;
+
+    const Value & operator[](size_t index) const;
+
+    void dump(std::ostream &os, bool color=true);
+};
+
+
+class Null : public Value
+{
+public:
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void *toPointer(void) const;
+    void *toPointer(bool bind);
+    unsigned long long toUIntPtr(void) const;
+    const char *toString(void) const;
+    void visit(Visitor &visitor);
+};
+
+
+class Bool : public Value
+{
+public:
+    Bool(bool _value) : value(_value) {}
+
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void visit(Visitor &visitor);
+
+    bool value;
+};
+
+
+class SInt : public Value
+{
+public:
+    SInt(signed long long _value) : value(_value) {}
+
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void visit(Visitor &visitor);
+
+    signed long long value;
+};
+
+
+class UInt : public Value
+{
+public:
+    UInt(unsigned long long _value) : value(_value) {}
+
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void visit(Visitor &visitor);
+
+    unsigned long long value;
+};
+
+
+class Float : public Value
+{
+public:
+    Float(double _value) : value(_value) {}
+
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void visit(Visitor &visitor);
+
+    double value;
+};
+
+
+class String : public Value
+{
+public:
+    String(const char * _value) : value(_value) {}
+    ~String();
+
+    bool toBool(void) const;
+    const char *toString(void) const;
+    void visit(Visitor &visitor);
+
+    const char * value;
+};
+
+
+class Enum : public Value
+{
+public:
+    Enum(const EnumSig *_sig) : sig(_sig) {}
+
+    bool toBool(void) const;
+    signed long long toSInt(void) const;
+    unsigned long long toUInt(void) const;
+    virtual float toFloat(void) const;
+    virtual double toDouble(void) const;
+    void visit(Visitor &visitor);
+
+    const EnumSig *sig;
+};
+
+
+class Bitmask : public UInt
+{
+public:
+    Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}
+
+    void visit(Visitor &visitor);
+
+    const BitmaskSig *sig;
+};
+
+
+class Struct : public Value
+{
+public:
+    Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { }
+    ~Struct();
+
+    bool toBool(void) const;
+    void visit(Visitor &visitor);
+
+    const StructSig *sig;
+    std::vector<Value *> members;
+};
+
+
+class Array : public Value
+{
+public:
+    Array(size_t len) : values(len) {}
+    ~Array();
+
+    bool toBool(void) const;
+    void visit(Visitor &visitor);
+
+    std::vector<Value *> values;
+};
+
+
+class Blob : public Value
+{
+public:
+    Blob(size_t _size) {
+        size = _size;
+        buf = new char[_size];
+        bound = false;
+    }
+
+    ~Blob();
+
+    bool toBool(void) const;
+    void *toPointer(void) const;
+    void *toPointer(bool bind);
+    void visit(Visitor &visitor);
+
+    size_t size;
+    char *buf;
+    bool bound;
+};
+
+
+class Pointer : public UInt
+{
+public:
+    Pointer(unsigned long long value) : UInt(value) {}
+
+    bool toBool(void) const;
+    void *toPointer(void) const;
+    void *toPointer(bool bind);
+    unsigned long long toUIntPtr(void) const;
+    void visit(Visitor &visitor);
+};
+
+
+class Visitor
+{
+public:
+    virtual void visit(Null *);
+    virtual void visit(Bool *);
+    virtual void visit(SInt *);
+    virtual void visit(UInt *);
+    virtual void visit(Float *);
+    virtual void visit(String *);
+    virtual void visit(Enum *);
+    virtual void visit(Bitmask *);
+    virtual void visit(Struct *);
+    virtual void visit(Array *);
+    virtual void visit(Blob *);
+    virtual void visit(Pointer *);
+
+protected:
+    inline void _visit(Value *value) {
+        if (value) { 
+            value->visit(*this); 
+        }
+    }
+};
+
+
+inline std::ostream & operator <<(std::ostream &os, Value *value) {
+    if (value) {
+        value->dump(os);
+    }
+    return os;
+}
+
+
+class Call
+{
+public:
+    unsigned no;
+    const FunctionSig *sig;
+    std::vector<Value *> args;
+    Value *ret;
+
+    Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
+    ~Call();
+
+    inline const char * name(void) const {
+        return sig->name;
+    }
+
+    inline Value & arg(unsigned index) {
+        assert(index < args.size());
+        return *(args[index]);
+    }
+
+    void dump(std::ostream &os, bool color=true);
+};
+
+
+inline std::ostream & operator <<(std::ostream &os, Call &call) {
+    call.dump(os);
+    return os;
+}
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_MODEL_HPP_ */
diff --git a/common/trace_model_writer.cpp b/common/trace_model_writer.cpp
new file mode 100644 (file)
index 0000000..dcfcf86
--- /dev/null
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * 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 "trace_writer.hpp"
+
+
+namespace Trace {
+
+
+class ModelWriter : public Visitor
+{
+protected:
+    Writer &writer;
+
+public:
+    ModelWriter(Writer &_writer) :
+        writer(_writer) {
+    }
+
+    void visit(Null *) {
+        writer.writeNull();
+    }
+
+    void visit(Bool *node) {
+        writer.writeBool(node->value);
+    }
+
+    void visit(SInt *node) {
+        writer.writeSInt(node->value);
+    }
+
+    void visit(UInt *node) {
+        writer.writeUInt(node->value);
+    }
+
+    void visit(Float *node) {
+        writer.writeFloat(node->value);
+    }
+
+    void visit(String *node) {
+        writer.writeString(node->value);
+    }
+
+    void visit(Enum *node) {
+        writer.writeEnum(node->sig);
+    }
+
+    void visit(Bitmask *node) {
+        writer.writeBitmask(node->sig, node->value);
+    }
+
+    void visit(Struct *node) {
+        writer.beginStruct(node->sig);
+        for (unsigned i = 0; i < node->sig->num_members; ++i) {
+            _visit(node->members[i]);
+        }
+        writer.endStruct();
+    }
+
+    void visit(Array *node) {
+        writer.beginArray(node->values.size());
+        for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
+            _visit(*it);
+        }
+        writer.endArray();
+    }
+
+    void visit(Blob *node) {
+        writer.writeBlob(node->buf, node->size);
+    }
+
+    void visit(Pointer *node) {
+        writer.writeOpaque((const void *) (size_t) node->value);
+    }
+
+    void visit(Call *call) {
+        unsigned call_no = writer.beginEnter(call->sig);
+        for (unsigned i = 0; i < call->args.size(); ++i) {
+            if (call->args[i]) {
+                writer.beginArg(i);
+                _visit(call->args[i]);
+                writer.endArg();
+            }
+        }
+        writer.endEnter();
+        writer.beginLeave(call_no);
+        if (call->ret) {
+            writer.beginReturn();
+            _visit(call->ret);
+            writer.endReturn();
+        }
+        writer.endLeave();
+    }
+};
+
+
+void Writer::writeCall(Call *call) {
+    ModelWriter visitor(*this);
+    visitor.visit(call);
+}
+
+
+} /* namespace Trace */
+
diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp
new file mode 100644 (file)
index 0000000..d7b20d2
--- /dev/null
@@ -0,0 +1,731 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2010 VMware, Inc.
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include "trace_file.hpp"
+#include "trace_snappyfile.hpp"
+#include "trace_parser.hpp"
+
+
+#define TRACE_VERBOSE 0
+
+
+namespace Trace {
+
+
+Parser::Parser() {
+    file = NULL;
+    next_call_no = 0;
+    version = 0;
+}
+
+
+Parser::~Parser() {
+    close();
+}
+
+
+bool Parser::open(const char *filename) {
+    assert(!file);
+    if (File::isZLibCompressed(filename)) {
+        file = new ZLibFile;
+    } else {
+        file = new SnappyFile;
+    }
+
+    if (!file->open(filename, File::Read)) {
+        return false;
+    }
+
+    version = read_uint();
+    if (version > TRACE_VERSION) {
+        std::cerr << "error: unsupported trace format version " << version << "\n";
+        return false;
+    }
+
+    return true;
+}
+
+template <typename Iter>
+inline void
+deleteAll(Iter begin, Iter end)
+{
+    while (begin != end) {
+        delete *begin;
+        ++begin;
+    }
+}
+
+template <typename Container>
+inline void
+deleteAll(Container &c)
+{
+    deleteAll(c.begin(), c.end());
+    c.clear();
+}
+
+void Parser::close(void) {
+    if (file) {
+        file->close();
+        delete file;
+        file = NULL;
+    }
+
+    deleteAll(calls);
+
+    // Delete all signature data.  Signatures are mere structures which don't
+    // own their own memory, so we need to destroy all data we created here.
+
+    for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) {
+        FunctionSigState *sig = *it;
+        if (sig) {
+            delete [] sig->name;
+            for (unsigned arg = 0; arg < sig->num_args; ++arg) {
+                delete [] sig->arg_names[arg];
+            }
+            delete [] sig->arg_names;
+            delete sig;
+        }
+    }
+    functions.clear();
+
+    for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) {
+        StructSigState *sig = *it;
+        if (sig) {
+            delete [] sig->name;
+            for (unsigned member = 0; member < sig->num_members; ++member) {
+                delete [] sig->member_names[member];
+            }
+            delete [] sig->member_names;
+            delete sig;
+        }
+    }
+    structs.clear();
+
+    for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) {
+        EnumSigState *sig = *it;
+        if (sig) {
+            delete [] sig->name;
+            delete sig;
+        }
+    }
+    enums.clear();
+    
+    for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) {
+        BitmaskSigState *sig = *it;
+        if (sig) {
+            for (unsigned flag = 0; flag < sig->num_flags; ++flag) {
+                delete [] sig->flags[flag].name;
+            }
+            delete [] sig->flags;
+            delete sig;
+        }
+    }
+    bitmasks.clear();
+}
+
+
+void Parser::getBookmark(ParseBookmark &bookmark) {
+    bookmark.offset = file->currentOffset();
+    bookmark.next_call_no = next_call_no;
+}
+
+
+void Parser::setBookmark(const ParseBookmark &bookmark) {
+    file->setCurrentOffset(bookmark.offset);
+    next_call_no = bookmark.next_call_no;
+    
+    // Simply ignore all pending calls
+    deleteAll(calls);
+}
+
+
+Call *Parser::parse_call(Mode mode) {
+    do {
+        int c = read_byte();
+        switch(c) {
+        case Trace::EVENT_ENTER:
+            parse_enter(mode);
+            break;
+        case Trace::EVENT_LEAVE:
+            return parse_leave(mode);
+        default:
+            std::cerr << "error: unknown event " << c << "\n";
+            exit(1);
+        case -1:
+            for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+                std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
+                std::cerr << **it << "\n";
+            }
+            return NULL;
+        }
+    } while(true);
+}
+
+
+/**
+ * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
+ */
+template<class T>
+T *lookup(std::vector<T *> &map, size_t index) {
+    if (index >= map.size()) {
+        map.resize(index + 1);
+        return NULL;
+    } else {
+        return map[index];
+    }
+}
+
+
+FunctionSig *Parser::parse_function_sig(void) {
+    size_t id = read_uint();
+
+    FunctionSigState *sig = lookup(functions, id);
+
+    if (!sig) {
+        /* parse the signature */
+        sig = new FunctionSigState;
+        sig->id = id;
+        sig->name = read_string();
+        sig->num_args = read_uint();
+        const char **arg_names = new const char *[sig->num_args];
+        for (unsigned i = 0; i < sig->num_args; ++i) {
+            arg_names[i] = read_string();
+        }
+        sig->arg_names = arg_names;
+        sig->offset = file->currentOffset();
+        functions[id] = sig;
+    } else if (file->currentOffset() < sig->offset) {
+        /* skip over the signature */
+        skip_string(); /* name */
+        int num_args = read_uint();
+        for (unsigned i = 0; i < num_args; ++i) {
+             skip_string(); /*arg_name*/
+        }
+    }
+
+    assert(sig);
+    return sig;
+}
+
+
+StructSig *Parser::parse_struct_sig() {
+    size_t id = read_uint();
+
+    StructSigState *sig = lookup(structs, id);
+
+    if (!sig) {
+        /* parse the signature */
+        sig = new StructSigState;
+        sig->id = id;
+        sig->name = read_string();
+        sig->num_members = read_uint();
+        const char **member_names = new const char *[sig->num_members];
+        for (unsigned i = 0; i < sig->num_members; ++i) {
+            member_names[i] = read_string();
+        }
+        sig->member_names = member_names;
+        sig->offset = file->currentOffset();
+        structs[id] = sig;
+    } else if (file->currentOffset() < sig->offset) {
+        /* skip over the signature */
+        skip_string(); /* name */
+        unsigned num_members = read_uint();
+        for (unsigned i = 0; i < num_members; ++i) {
+            skip_string(); /* member_name */
+        }
+    }
+
+    assert(sig);
+    return sig;
+}
+
+
+EnumSig *Parser::parse_enum_sig() {
+    size_t id = read_uint();
+
+    EnumSigState *sig = lookup(enums, id);
+
+    if (!sig) {
+        /* parse the signature */
+        sig = new EnumSigState;
+        sig->id = id;
+        sig->name = read_string();
+        Value *value = parse_value();
+        sig->value = value->toSInt();
+        delete value;
+        sig->offset = file->currentOffset();
+        enums[id] = sig;
+    } else if (file->currentOffset() < sig->offset) {
+        /* skip over the signature */
+        skip_string(); /*name*/
+        scan_value();
+    }
+
+    assert(sig);
+    return sig;
+}
+
+
+BitmaskSig *Parser::parse_bitmask_sig() {
+    size_t id = read_uint();
+
+    BitmaskSigState *sig = lookup(bitmasks, id);
+
+    if (!sig) {
+        /* parse the signature */
+        sig = new BitmaskSigState;
+        sig->id = id;
+        sig->num_flags = read_uint();
+        BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
+        for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
+            it->name = read_string();
+            it->value = read_uint();
+            if (it->value == 0 && it != flags) {
+                std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
+            }
+        }
+        sig->flags = flags;
+        sig->offset = file->currentOffset();
+        bitmasks[id] = sig;
+    } else if (file->currentOffset() < sig->offset) {
+        /* skip over the signature */
+        int num_flags = read_uint();
+        for (int i = 0; i < num_flags; ++i) {
+            skip_string(); /*name */
+            skip_uint(); /* value */
+        }
+    }
+
+    assert(sig);
+    return sig;
+}
+
+
+void Parser::parse_enter(Mode mode) {
+    FunctionSig *sig = parse_function_sig();
+
+    Call *call = new Call(sig);
+
+    call->no = next_call_no++;
+
+    if (parse_call_details(call, mode)) {
+        calls.push_back(call);
+    } else {
+        delete call;
+    }
+}
+
+
+Call *Parser::parse_leave(Mode mode) {
+    unsigned call_no = read_uint();
+    Call *call = NULL;
+    for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+        if ((*it)->no == call_no) {
+            call = *it;
+            calls.erase(it);
+            break;
+        }
+    }
+    if (!call) {
+        return NULL;
+    }
+
+    if (parse_call_details(call, mode)) {
+        return call;
+    } else {
+        delete call;
+        return NULL;
+    }
+}
+
+
+bool Parser::parse_call_details(Call *call, Mode mode) {
+    do {
+        int c = read_byte();
+        switch(c) {
+        case Trace::CALL_END:
+            return true;
+        case Trace::CALL_ARG:
+            parse_arg(call, mode);
+            break;
+        case Trace::CALL_RET:
+            call->ret = parse_value(mode);
+            break;
+        default:
+            std::cerr << "error: ("<<call->name()<< ") unknown call detail "
+                      << c << "\n";
+            exit(1);
+        case -1:
+            return false;
+        }
+    } while(true);
+}
+
+
+void Parser::parse_arg(Call *call, Mode mode) {
+    unsigned index = read_uint();
+    Value *value = parse_value(mode);
+    if (value) {
+        if (index >= call->args.size()) {
+            call->args.resize(index + 1);
+        }
+        call->args[index] = value;
+    }
+}
+
+
+Value *Parser::parse_value(void) {
+    int c;
+    Value *value;
+    c = read_byte();
+    switch(c) {
+    case Trace::TYPE_NULL:
+        value = new Null;
+        break;
+    case Trace::TYPE_FALSE:
+        value = new Bool(false);
+        break;
+    case Trace::TYPE_TRUE:
+        value = new Bool(true);
+        break;
+    case Trace::TYPE_SINT:
+        value = parse_sint();
+        break;
+    case Trace::TYPE_UINT:
+        value = parse_uint();
+        break;
+    case Trace::TYPE_FLOAT:
+        value = parse_float();
+        break;
+    case Trace::TYPE_DOUBLE:
+        value = parse_double();
+        break;
+    case Trace::TYPE_STRING:
+        value = parse_string();
+        break;
+    case Trace::TYPE_ENUM:
+        value = parse_enum();
+        break;
+    case Trace::TYPE_BITMASK:
+        value = parse_bitmask();
+        break;
+    case Trace::TYPE_ARRAY:
+        value = parse_array();
+        break;
+    case Trace::TYPE_STRUCT:
+        value = parse_struct();
+        break;
+    case Trace::TYPE_BLOB:
+        value = parse_blob();
+        break;
+    case Trace::TYPE_OPAQUE:
+        value = parse_opaque();
+        break;
+    default:
+        std::cerr << "error: unknown type " << c << "\n";
+        exit(1);
+    case -1:
+        value = NULL;
+        break;
+    }
+#if TRACE_VERBOSE
+    if (value) {
+        std::cerr << "\tVALUE " << value << "\n";
+    }
+#endif
+    return value;
+}
+
+
+void Parser::scan_value(void) {
+    int c = read_byte();
+    switch(c) {
+    case Trace::TYPE_NULL:
+    case Trace::TYPE_FALSE:
+    case Trace::TYPE_TRUE:
+        break;
+    case Trace::TYPE_SINT:
+        scan_sint();
+        break;
+    case Trace::TYPE_UINT:
+        scan_uint();
+        break;
+    case Trace::TYPE_FLOAT:
+        scan_float();
+        break;
+    case Trace::TYPE_DOUBLE:
+        scan_double();
+        break;
+    case Trace::TYPE_STRING:
+        scan_string();
+        break;
+    case Trace::TYPE_ENUM:
+        scan_enum();
+        break;
+    case Trace::TYPE_BITMASK:
+        scan_bitmask();
+        break;
+    case Trace::TYPE_ARRAY:
+        scan_array();
+        break;
+    case Trace::TYPE_STRUCT:
+        scan_struct();
+        break;
+    case Trace::TYPE_BLOB:
+        scan_blob();
+        break;
+    case Trace::TYPE_OPAQUE:
+        scan_opaque();
+        break;
+    default:
+        std::cerr << "error: unknown type " << c << "\n";
+        exit(1);
+    case -1:
+        break;
+    }
+}
+
+
+Value *Parser::parse_sint() {
+    return new SInt(-(signed long long)read_uint());
+}
+
+
+void Parser::scan_sint() {
+    skip_uint();
+}
+
+
+Value *Parser::parse_uint() {
+    return new UInt(read_uint());
+}
+
+
+void Parser::scan_uint() {
+    skip_uint();
+}
+
+
+Value *Parser::parse_float() {
+    float value;
+    file->read(&value, sizeof value);
+    return new Float(value);
+}
+
+
+void Parser::scan_float() {
+    file->skip(sizeof(float));
+}
+
+
+Value *Parser::parse_double() {
+    double value;
+    file->read(&value, sizeof value);
+    return new Float(value);
+}
+
+
+void Parser::scan_double() {
+    file->skip(sizeof(double));
+}
+
+
+Value *Parser::parse_string() {
+    return new String(read_string());
+}
+
+
+void Parser::scan_string() {
+    skip_string();
+}
+
+
+Value *Parser::parse_enum() {
+    EnumSig *sig = parse_enum_sig();
+    return new Enum(sig);
+}
+
+
+void Parser::scan_enum() {
+    parse_enum_sig();
+}
+
+
+Value *Parser::parse_bitmask() {
+    BitmaskSig *sig = parse_bitmask_sig();
+
+    unsigned long long value = read_uint();
+
+    return new Bitmask(sig, value);
+}
+
+
+void Parser::scan_bitmask() {
+    parse_bitmask_sig();
+    skip_uint(); /* value */
+}
+
+
+Value *Parser::parse_array(void) {
+    size_t len = read_uint();
+    Array *array = new Array(len);
+    for (size_t i = 0; i < len; ++i) {
+        array->values[i] = parse_value();
+    }
+    return array;
+}
+
+
+void Parser::scan_array(void) {
+    size_t len = read_uint();
+    for (size_t i = 0; i < len; ++i) {
+        scan_value();
+    }
+}
+
+
+Value *Parser::parse_blob(void) {
+    size_t size = read_uint();
+    Blob *blob = new Blob(size);
+    if (size) {
+        file->read(blob->buf, (unsigned)size);
+    }
+    return blob;
+}
+
+
+void Parser::scan_blob(void) {
+    size_t size = read_uint();
+    if (size) {
+        file->skip(size);
+    }
+}
+
+
+Value *Parser::parse_struct() {
+    StructSig *sig = parse_struct_sig();
+    Struct *value = new Struct(sig);
+
+    for (size_t i = 0; i < sig->num_members; ++i) {
+        value->members[i] = parse_value();
+    }
+
+    return value;
+}
+
+
+void Parser::scan_struct() {
+    StructSig *sig = parse_struct_sig();
+    for (size_t i = 0; i < sig->num_members; ++i) {
+        scan_value();
+    }
+}
+
+
+Value *Parser::parse_opaque() {
+    unsigned long long addr;
+    addr = read_uint();
+    return new Pointer(addr);
+}
+
+
+void Parser::scan_opaque() {
+    skip_uint();
+}
+
+
+const char * Parser::read_string(void) {
+    size_t len = read_uint();
+    char * value = new char[len + 1];
+    if (len) {
+        file->read(value, (unsigned)len);
+    }
+    value[len] = 0;
+#if TRACE_VERBOSE
+    std::cerr << "\tSTRING \"" << value << "\"\n";
+#endif
+    return value;
+}
+
+
+void Parser::skip_string(void) {
+    size_t len = read_uint();
+    file->skip(len);
+}
+
+
+unsigned long long Parser::read_uint(void) {
+    unsigned long long value = 0;
+    int c;
+    unsigned shift = 0;
+    do {
+        c = file->getc();
+        if (c == -1) {
+            break;
+        }
+        value |= (unsigned long long)(c & 0x7f) << shift;
+        shift += 7;
+    } while(c & 0x80);
+#if TRACE_VERBOSE
+    std::cerr << "\tUINT " << value << "\n";
+#endif
+    return value;
+}
+
+
+void Parser::skip_uint(void) {
+    int c;
+    do {
+        c = file->getc();
+        if (c == -1) {
+            break;
+        }
+    } while(c & 0x80);
+}
+
+
+inline int Parser::read_byte(void) {
+    int c = file->getc();
+#if TRACE_VERBOSE
+    if (c < 0)
+        std::cerr << "\tEOF" << "\n";
+    else
+        std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
+#endif
+    return c;
+}
+
+
+inline void Parser::skip_byte(void) {
+    file->skip(1);
+}
+
+
+} /* namespace Trace */
diff --git a/common/trace_parser.hpp b/common/trace_parser.hpp
new file mode 100644 (file)
index 0000000..3aaa6d3
--- /dev/null
@@ -0,0 +1,197 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef _TRACE_PARSER_HPP_
+#define _TRACE_PARSER_HPP_
+
+
+#include <iostream>
+#include <list>
+
+#include "trace_file.hpp"
+#include "trace_format.hpp"
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+struct ParseBookmark
+{
+    File::Offset offset;
+    unsigned next_call_no;
+};
+
+
+class Parser
+{
+protected:
+    File *file;
+
+    enum Mode {
+        FULL = 0,
+        SCAN,
+        SKIP
+    };
+
+    typedef std::list<Call *> CallList;
+    CallList calls;
+
+    // Helper template that extends a base signature structure, with additional
+    // parsing information.
+    template< class T >
+    struct SigState : public T {
+        // Offset in the file of where signature was defined.  It is used when
+        // reparsing to determine whether the signature definition is to be
+        // expected next or not.
+        File::Offset offset;
+    };
+
+    typedef SigState<FunctionSig> FunctionSigState;
+    typedef SigState<StructSig> StructSigState;
+    typedef SigState<EnumSig> EnumSigState;
+    typedef SigState<BitmaskSig> BitmaskSigState;
+
+    typedef std::vector<FunctionSigState *> FunctionMap;
+    typedef std::vector<StructSigState *> StructMap;
+    typedef std::vector<EnumSigState *> EnumMap;
+    typedef std::vector<BitmaskSigState *> BitmaskMap;
+
+    FunctionMap functions;
+    StructMap structs;
+    EnumMap enums;
+    BitmaskMap bitmasks;
+
+    unsigned next_call_no;
+
+public:
+    unsigned long long version;
+
+    Parser();
+
+    ~Parser();
+
+    bool open(const char *filename);
+
+    void close(void);
+
+    Call *parse_call(void) {
+        return parse_call(FULL);
+    }
+
+    bool supportsOffsets() const
+    {
+        return file->supportsOffsets();
+    }
+
+    void getBookmark(ParseBookmark &bookmark);
+
+    void setBookmark(const ParseBookmark &bookmark);
+
+    int percentRead()
+    {
+        return file->percentRead();
+    }
+
+    Call *scan_call() {
+        return parse_call(SCAN);
+    }
+
+protected:
+    Call *parse_call(Mode mode);
+
+    FunctionSig *parse_function_sig(void);
+    StructSig *parse_struct_sig();
+    EnumSig *parse_enum_sig();
+    BitmaskSig *parse_bitmask_sig();
+    
+    Call *parse_Call(Mode mode);
+
+    void parse_enter(Mode mode);
+
+    Call *parse_leave(Mode mode);
+
+    bool parse_call_details(Call *call, Mode mode);
+
+    void parse_arg(Call *call, Mode mode);
+
+    Value *parse_value(void);
+    void scan_value(void);
+    inline Value *parse_value(Mode mode) {
+        if (mode == FULL) {
+            return parse_value();
+        } else {
+            scan_value();
+            return NULL;
+        }
+    }
+
+    Value *parse_sint();
+    void scan_sint();
+
+    Value *parse_uint();
+    void scan_uint();
+
+    Value *parse_float();
+    void scan_float();
+
+    Value *parse_double();
+    void scan_double();
+
+    Value *parse_string();
+    void scan_string();
+
+    Value *parse_enum();
+    void scan_enum();
+
+    Value *parse_bitmask();
+    void scan_bitmask();
+
+    Value *parse_array(void);
+    void scan_array(void);
+
+    Value *parse_blob(void);
+    void scan_blob(void);
+
+    Value *parse_struct();
+    void scan_struct();
+
+    Value *parse_opaque();
+    void scan_opaque();
+
+    const char * read_string(void);
+    void skip_string(void);
+
+    unsigned long long read_uint(void);
+    void skip_uint(void);
+
+    inline int read_byte(void);
+    inline void skip_byte(void);
+};
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_PARSER_HPP_ */
diff --git a/common/trace_snappyfile.cpp b/common/trace_snappyfile.cpp
new file mode 100644 (file)
index 0000000..4dbe42d
--- /dev/null
@@ -0,0 +1,338 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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 "trace_snappyfile.hpp"
+
+#include <snappy.h>
+
+#include <iostream>
+
+#include <assert.h>
+#include <string.h>
+
+using namespace Trace;
+
+/*
+ * Snappy file format.
+ * -------------------
+ *
+ * Snappy at its core is just a compressoin algorithm so we're
+ * creating a new file format which uses snappy compression
+ * to hold the trace data.
+ *
+ * The file is composed of a number of chunks, they are:
+ * chunk {
+ *     uint32 - specifying the length of the compressed data
+ *     compressed data, in little endian
+ * }
+ * File can contain any number of such chunks.
+ * The default size of an uncompressed chunk is specified in
+ * SNAPPY_CHUNK_SIZE.
+ *
+ * Note:
+ * Currently the default size for a a to-be-compressed data is
+ * 1mb, meaning that the compressed data will be <= 1mb.
+ * The reason it's 1mb is because it seems
+ * to offer a pretty good compression/disk io speed ratio
+ * but that might change.
+ *
+ */
+
+SnappyFile::SnappyFile(const std::string &filename,
+                              File::Mode mode)
+    : File(),
+      m_cache(0),
+      m_cachePtr(0),
+      m_cacheSize(0)
+{
+    size_t maxCompressedLength =
+        snappy::MaxCompressedLength(SNAPPY_CHUNK_SIZE);
+    m_compressedCache = new char[maxCompressedLength];
+}
+
+SnappyFile::~SnappyFile()
+{
+    delete [] m_compressedCache;
+    delete [] m_cache;
+}
+
+bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
+{
+    std::ios_base::openmode fmode = std::fstream::binary;
+    if (mode == File::Write) {
+        fmode |= (std::fstream::out | std::fstream::trunc);
+        createCache(SNAPPY_CHUNK_SIZE);
+    } else if (mode == File::Read) {
+        fmode |= std::fstream::in;
+    }
+
+    m_stream.open(filename.c_str(), fmode);
+
+    //read in the initial buffer if we're reading
+    if (m_stream.is_open() && mode == File::Read) {
+        m_stream.seekg(0, std::ios::end);
+        m_endPos = m_stream.tellg();
+        m_stream.seekg(0, std::ios::beg);
+
+        // read the snappy file identifier
+        unsigned char byte1, byte2;
+        m_stream >> byte1;
+        m_stream >> byte2;
+        assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
+
+        flushReadCache();
+    } else if (m_stream.is_open() && mode == File::Write) {
+        // write the snappy file identifier
+        m_stream << SNAPPY_BYTE1;
+        m_stream << SNAPPY_BYTE2;
+    }
+    return m_stream.is_open();
+}
+
+bool SnappyFile::rawWrite(const void *buffer, size_t length)
+{
+    if (freeCacheSize() > length) {
+        memcpy(m_cachePtr, buffer, length);
+        m_cachePtr += length;
+    } else if (freeCacheSize() == length) {
+        memcpy(m_cachePtr, buffer, length);
+        m_cachePtr += length;
+        flushWriteCache();
+    } else {
+        int sizeToWrite = length;
+
+        while (sizeToWrite >= freeCacheSize()) {
+            int endSize = freeCacheSize();
+            int offset = length - sizeToWrite;
+            memcpy(m_cachePtr, (const char*)buffer + offset, endSize);
+            sizeToWrite -= endSize;
+            m_cachePtr += endSize;
+            flushWriteCache();
+        }
+        if (sizeToWrite) {
+            int offset = length - sizeToWrite;
+            memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite);
+            m_cachePtr += sizeToWrite;
+        }
+    }
+
+    return true;
+}
+
+bool SnappyFile::rawRead(void *buffer, size_t length)
+{
+    if (endOfData()) {
+        return false;
+    }
+
+    if (freeCacheSize() >= length) {
+        memcpy(buffer, m_cachePtr, length);
+        m_cachePtr += length;
+    } else {
+        size_t sizeToRead = length;
+        size_t offset = 0;
+        while (sizeToRead) {
+            size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
+            offset = length - sizeToRead;
+            memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
+            m_cachePtr += chunkSize;
+            sizeToRead -= chunkSize;
+            if (sizeToRead > 0) {
+                flushReadCache();
+            }
+            if (!m_cacheSize) {
+                break;
+            }
+        }
+    }
+
+    return true;
+}
+
+int SnappyFile::rawGetc()
+{
+    int c = 0;
+    if (!rawRead(&c, 1))
+        return -1;
+    return c;
+}
+
+void SnappyFile::rawClose()
+{
+    if (m_mode == File::Write) {
+        flushWriteCache();
+    }
+    m_stream.close();
+    delete [] m_cache;
+    m_cache = NULL;
+    m_cachePtr = NULL;
+}
+
+void SnappyFile::rawFlush()
+{
+    assert(m_mode == File::Write);
+    flushWriteCache();
+    m_stream.flush();
+}
+
+void SnappyFile::flushWriteCache()
+{
+    size_t inputLength = usedCacheSize();
+
+    if (inputLength) {
+        size_t compressedLength;
+
+        ::snappy::RawCompress(m_cache, inputLength,
+                              m_compressedCache, &compressedLength);
+
+        writeCompressedLength(compressedLength);
+        m_stream.write(m_compressedCache, compressedLength);
+        m_cachePtr = m_cache;
+    }
+    assert(m_cachePtr == m_cache);
+}
+
+void SnappyFile::flushReadCache(size_t skipLength)
+{
+    //assert(m_cachePtr == m_cache + m_cacheSize);
+    m_currentOffset.chunk = m_stream.tellg();
+    size_t compressedLength;
+    compressedLength = readCompressedLength();
+
+    if (compressedLength) {
+        m_stream.read((char*)m_compressedCache, compressedLength);
+        ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
+                                        &m_cacheSize);
+        createCache(m_cacheSize);
+        if (skipLength < m_cacheSize) {
+            ::snappy::RawUncompress(m_compressedCache, compressedLength,
+                                    m_cache);
+        }
+    } else {
+        createCache(0);
+    }
+}
+
+void SnappyFile::createCache(size_t size)
+{
+    // TODO: only re-allocate if the current buffer is not big enough
+
+    if (m_cache) {
+        delete [] m_cache;
+    }
+
+    if (size) {
+        m_cache = new char[size];
+    } else {
+        m_cache = NULL;
+    }
+
+    m_cachePtr = m_cache;
+    m_cacheSize = size;
+}
+
+void SnappyFile::writeCompressedLength(size_t length)
+{
+    unsigned char buf[4];
+    buf[0] = length & 0xff; length >>= 8;
+    buf[1] = length & 0xff; length >>= 8;
+    buf[2] = length & 0xff; length >>= 8;
+    buf[3] = length & 0xff; length >>= 8;
+    assert(length == 0);
+    m_stream.write((const char *)buf, sizeof buf);
+}
+
+size_t SnappyFile::readCompressedLength()
+{
+    unsigned char buf[4];
+    size_t length;
+    m_stream.read((char *)buf, sizeof buf);
+    if (m_stream.fail()) {
+        length = 0;
+    } else {
+        length  =  (size_t)buf[0];
+        length |= ((size_t)buf[1] <<  8);
+        length |= ((size_t)buf[2] << 16);
+        length |= ((size_t)buf[3] << 24);
+    }
+    return length;
+}
+
+bool SnappyFile::supportsOffsets() const
+{
+    return true;
+}
+
+File::Offset SnappyFile::currentOffset()
+{
+    m_currentOffset.offsetInChunk = m_cachePtr - m_cache;
+    return m_currentOffset;
+}
+
+void SnappyFile::setCurrentOffset(const File::Offset &offset)
+{
+    // to remove eof bit
+    m_stream.clear();
+    // seek to the start of a chunk
+    m_stream.seekg(offset.chunk, std::ios::beg);
+    // load the chunk
+    flushReadCache();
+    assert(m_cacheSize >= offset.offsetInChunk);
+    // seek within our cache to the correct location within the chunk
+    m_cachePtr = m_cache + offset.offsetInChunk;
+
+}
+
+bool SnappyFile::rawSkip(size_t length)
+{
+    if (endOfData()) {
+        return false;
+    }
+
+    if (freeCacheSize() >= length) {
+        m_cachePtr += length;
+    } else {
+        size_t sizeToRead = length;
+        while (sizeToRead) {
+            size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
+            m_cachePtr += chunkSize;
+            sizeToRead -= chunkSize;
+            if (sizeToRead > 0) {
+                flushReadCache(sizeToRead);
+            }
+            if (!m_cacheSize) {
+                break;
+            }
+        }
+    }
+
+    return true;
+}
+
+int SnappyFile::rawPercentRead()
+{
+    return 100 * (double(m_stream.tellg()) / double(m_endPos));
+}
diff --git a/common/trace_snappyfile.hpp b/common/trace_snappyfile.hpp
new file mode 100644 (file)
index 0000000..33159ec
--- /dev/null
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#ifndef TRACE_SNAPPYFILE_HPP
+#define TRACE_SNAPPYFILE_HPP
+
+#include <assert.h>
+
+#include "trace_file.hpp"
+
+#include <string>
+#include <fstream>
+
+namespace snappy {
+    class File;
+}
+
+namespace Trace {
+
+#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024)
+
+#define SNAPPY_BYTE1 'a'
+#define SNAPPY_BYTE2 't'
+
+
+class SnappyFile : public File {
+public:
+    SnappyFile(const std::string &filename = std::string(),
+               File::Mode mode = File::Read);
+    virtual ~SnappyFile();
+
+    virtual bool supportsOffsets() const;
+    virtual File::Offset currentOffset();
+    virtual void setCurrentOffset(const File::Offset &offset);
+protected:
+    virtual bool rawOpen(const std::string &filename, File::Mode mode);
+    virtual bool rawWrite(const void *buffer, size_t length);
+    virtual bool rawRead(void *buffer, size_t length);
+    virtual int rawGetc();
+    virtual void rawClose();
+    virtual void rawFlush();
+    virtual bool rawSkip(size_t length);
+    virtual int rawPercentRead();
+
+private:
+    inline size_t usedCacheSize() const
+    {
+        assert(m_cachePtr >= m_cache);
+        return m_cachePtr - m_cache;
+    }
+    inline size_t freeCacheSize() const
+    {
+        assert(m_cacheSize >= usedCacheSize());
+        if (m_cacheSize > 0) {
+            return m_cacheSize - usedCacheSize();
+        } else {
+            return 0;
+        }
+    }
+    inline bool endOfData() const
+    {
+        return m_stream.eof() && freeCacheSize() == 0;
+    }
+    void flushWriteCache();
+    void flushReadCache(size_t skipLength = 0);
+    void createCache(size_t size);
+    void writeCompressedLength(size_t length);
+    size_t readCompressedLength();
+private:
+    std::fstream m_stream;
+    char *m_cache;
+    char *m_cachePtr;
+    size_t m_cacheSize;
+
+    char *m_compressedCache;
+
+    File::Offset m_currentOffset;
+    std::streampos m_endPos;
+};
+
+}
+
+#endif // TRACE_SNAPPYFILE_HPP
diff --git a/common/trace_writer.cpp b/common/trace_writer.cpp
new file mode 100644 (file)
index 0000000..5a5f1f7
--- /dev/null
@@ -0,0 +1,303 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2009 VMware, Inc.
+ * 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "os.hpp"
+#include "trace_writer.hpp"
+#include "trace_snappyfile.hpp"
+#include "trace_format.hpp"
+
+
+namespace Trace {
+
+
+Writer::Writer() :
+    call_no(0)
+{
+    m_file = new Trace::SnappyFile;
+    close();
+}
+
+Writer::~Writer()
+{
+    close();
+    delete m_file;
+    m_file = NULL;
+}
+
+void
+Writer::close(void) {
+    m_file->close();
+}
+
+bool
+Writer::open(const char *filename) {
+    close();
+
+    if (!m_file->open(filename, File::Write)) {
+        return false;
+    }
+
+    call_no = 0;
+    functions.clear();
+    structs.clear();
+    enums.clear();
+    bitmasks.clear();
+
+    _writeUInt(TRACE_VERSION);
+
+    return true;
+}
+
+void inline
+Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
+    m_file->write(sBuffer, dwBytesToWrite);
+}
+
+void inline
+Writer::_writeByte(char c) {
+    _write(&c, 1);
+}
+
+void inline
+Writer::_writeUInt(unsigned long long value) {
+    char buf[2 * sizeof value];
+    unsigned len;
+
+    len = 0;
+    do {
+        assert(len < sizeof buf);
+        buf[len] = 0x80 | (value & 0x7f);
+        value >>= 7;
+        ++len;
+    } while (value);
+
+    assert(len);
+    buf[len - 1] &= 0x7f;
+
+    _write(buf, len);
+}
+
+void inline
+Writer::_writeFloat(float value) {
+    assert(sizeof value == 4);
+    _write((const char *)&value, sizeof value);
+}
+
+void inline
+Writer::_writeDouble(double value) {
+    assert(sizeof value == 8);
+    _write((const char *)&value, sizeof value);
+}
+
+void inline
+Writer::_writeString(const char *str) {
+    size_t len = strlen(str);
+    _writeUInt(len);
+    _write(str, len);
+}
+
+inline bool lookup(std::vector<bool> &map, size_t index) {
+    if (index >= map.size()) {
+        map.resize(index + 1);
+        return false;
+    } else {
+        return map[index];
+    }
+}
+
+unsigned Writer::beginEnter(const FunctionSig *sig) {
+    _writeByte(Trace::EVENT_ENTER);
+    _writeUInt(sig->id);
+    if (!lookup(functions, sig->id)) {
+        _writeString(sig->name);
+        _writeUInt(sig->num_args);
+        for (unsigned i = 0; i < sig->num_args; ++i) {
+            _writeString(sig->arg_names[i]);
+        }
+        functions[sig->id] = true;
+    }
+
+    return call_no++;
+}
+
+void Writer::endEnter(void) {
+    _writeByte(Trace::CALL_END);
+}
+
+void Writer::beginLeave(unsigned call) {
+    _writeByte(Trace::EVENT_LEAVE);
+    _writeUInt(call);
+}
+
+void Writer::endLeave(void) {
+    _writeByte(Trace::CALL_END);
+}
+
+void Writer::beginArg(unsigned index) {
+    _writeByte(Trace::CALL_ARG);
+    _writeUInt(index);
+}
+
+void Writer::beginReturn(void) {
+    _writeByte(Trace::CALL_RET);
+}
+
+void Writer::beginArray(size_t length) {
+    _writeByte(Trace::TYPE_ARRAY);
+    _writeUInt(length);
+}
+
+void Writer::beginStruct(const StructSig *sig) {
+    _writeByte(Trace::TYPE_STRUCT);
+    _writeUInt(sig->id);
+    if (!lookup(structs, sig->id)) {
+        _writeString(sig->name);
+        _writeUInt(sig->num_members);
+        for (unsigned i = 0; i < sig->num_members; ++i) {
+            _writeString(sig->member_names[i]);
+        }
+        structs[sig->id] = true;
+    }
+}
+
+void Writer::writeBool(bool value) {
+    _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
+}
+
+void Writer::writeSInt(signed long long value) {
+    if (value < 0) {
+        _writeByte(Trace::TYPE_SINT);
+        _writeUInt(-value);
+    } else {
+        _writeByte(Trace::TYPE_UINT);
+        _writeUInt(value);
+    }
+}
+
+void Writer::writeUInt(unsigned long long value) {
+    _writeByte(Trace::TYPE_UINT);
+    _writeUInt(value);
+}
+
+void Writer::writeFloat(float value) {
+    _writeByte(Trace::TYPE_FLOAT);
+    _writeFloat(value);
+}
+
+void Writer::writeDouble(double value) {
+    _writeByte(Trace::TYPE_DOUBLE);
+    _writeDouble(value);
+}
+
+void Writer::writeString(const char *str) {
+    if (!str) {
+        Writer::writeNull();
+        return;
+    }
+    _writeByte(Trace::TYPE_STRING);
+    _writeString(str);
+}
+
+void Writer::writeString(const char *str, size_t len) {
+    if (!str) {
+        Writer::writeNull();
+        return;
+    }
+    _writeByte(Trace::TYPE_STRING);
+    _writeUInt(len);
+    _write(str, len);
+}
+
+void Writer::writeWString(const wchar_t *str) {
+    if (!str) {
+        Writer::writeNull();
+        return;
+    }
+    _writeByte(Trace::TYPE_STRING);
+    _writeString("<wide-string>");
+}
+
+void Writer::writeBlob(const void *data, size_t size) {
+    if (!data) {
+        Writer::writeNull();
+        return;
+    }
+    _writeByte(Trace::TYPE_BLOB);
+    _writeUInt(size);
+    if (size) {
+        _write(data, size);
+    }
+}
+
+void Writer::writeEnum(const EnumSig *sig) {
+    _writeByte(Trace::TYPE_ENUM);
+    _writeUInt(sig->id);
+    if (!lookup(enums, sig->id)) {
+        _writeString(sig->name);
+        Writer::writeSInt(sig->value);
+        enums[sig->id] = true;
+    }
+}
+
+void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
+    _writeByte(Trace::TYPE_BITMASK);
+    _writeUInt(sig->id);
+    if (!lookup(bitmasks, sig->id)) {
+        _writeUInt(sig->num_flags);
+        for (unsigned i = 0; i < sig->num_flags; ++i) {
+            if (i != 0 && sig->flags[i].value == 0) {
+                OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
+            }
+            _writeString(sig->flags[i].name);
+            _writeUInt(sig->flags[i].value);
+        }
+        bitmasks[sig->id] = true;
+    }
+    _writeUInt(value);
+}
+
+void Writer::writeNull(void) {
+    _writeByte(Trace::TYPE_NULL);
+}
+
+void Writer::writeOpaque(const void *addr) {
+    if (!addr) {
+        Writer::writeNull();
+        return;
+    }
+    _writeByte(Trace::TYPE_OPAQUE);
+    _writeUInt((size_t)addr);
+}
+
+
+} /* namespace Trace */
+
diff --git a/common/trace_writer.hpp b/common/trace_writer.hpp
new file mode 100644 (file)
index 0000000..dfb76b2
--- /dev/null
@@ -0,0 +1,145 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace writing functions.
+ */
+
+#ifndef _TRACE_WRITER_HPP_
+#define _TRACE_WRITER_HPP_
+
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "trace_model.hpp"
+
+
+namespace Trace {
+    class File;
+
+    class Writer {
+    protected:
+        File *m_file;
+        unsigned call_no;
+
+        std::vector<bool> functions;
+        std::vector<bool> structs;
+        std::vector<bool> enums;
+        std::vector<bool> bitmasks;
+
+    public:
+        Writer();
+        ~Writer();
+
+        bool open(const char *filename);
+        void close(void);
+
+        unsigned beginEnter(const FunctionSig *sig);
+        void endEnter(void);
+
+        void beginLeave(unsigned call);
+        void endLeave(void);
+
+        void beginArg(unsigned index);
+        inline void endArg(void) {}
+
+        void beginReturn(void);
+        inline void endReturn(void) {}
+
+        void beginArray(size_t length);
+        inline void endArray(void) {}
+
+        inline void beginElement(void) {}
+        inline void endElement(void) {}
+
+        void beginStruct(const StructSig *sig);
+        inline void endStruct(void) {}
+
+        void writeBool(bool value);
+        void writeSInt(signed long long value);
+        void writeUInt(unsigned long long value);
+        void writeFloat(float value);
+        void writeDouble(double value);
+        void writeString(const char *str);
+        void writeString(const char *str, size_t size);
+        void writeWString(const wchar_t *str);
+        void writeBlob(const void *data, size_t size);
+        void writeEnum(const EnumSig *sig);
+        void writeBitmask(const BitmaskSig *sig, unsigned long long value);
+        void writeNull(void);
+        void writeOpaque(const void *ptr);
+
+        void writeCall(Call *call);
+
+    protected:
+        void inline _write(const void *sBuffer, size_t dwBytesToWrite);
+        void inline _writeByte(char c);
+        void inline _writeUInt(unsigned long long value);
+        void inline _writeFloat(float value);
+        void inline _writeDouble(double value);
+        void inline _writeString(const char *str);
+
+    };
+
+    /**
+     * A specialized Writer class, mean to trace the current process.
+     *
+     * In particular:
+     * - it creates a trace file based on the current process name
+     * - uses mutexes to allow tracing from multiple threades
+     * - flushes the output to ensure the last call is traced in event of
+     *   abnormal termination
+     */
+    class LocalWriter : public Writer {
+    protected:
+        int acquired;
+
+    public:
+        /**
+         * Should never called directly -- use localWriter singleton below instead.
+         */
+        LocalWriter();
+        ~LocalWriter();
+
+        void open(void);
+
+        unsigned beginEnter(const FunctionSig *sig);
+        void endEnter(void);
+
+        void beginLeave(unsigned call);
+        void endLeave(void);
+
+        void flush(void);
+    };
+
+    /**
+     * Singleton.
+     */
+    extern LocalWriter localWriter;
+}
+
+#endif /* _TRACE_WRITER_HPP_ */
diff --git a/d3d.py b/d3d.py
index f587fc532dd3203a8c58747609f8ab934851d763..857e5b3f49bffa3a2ea54e96415ee6de13963919 100644 (file)
--- a/d3d.py
+++ b/d3d.py
@@ -473,55 +473,3 @@ interfaces = [
 
 ddraw.add_interfaces(interfaces)
 
-
-class DDrawTracer(DllTracer):
-
-    def trace_function_impl_body(self, function):
-        if function.name in ('AcquireDDThreadLock', 'ReleaseDDThreadLock'):
-            self.dispatch_function(function)
-            return
-
-        DllTracer.trace_function_impl_body(self, function)
-
-    def wrap_arg(self, function, arg):
-        if function.name == 'DirectDrawCreateEx' and arg.name == 'lplpDD':
-            print '    if (*lplpDD) {'
-            for iface in interfaces:
-                print '        if (iid == IID_%s) {' % iface.name
-                print '            *lplpDD = (LPVOID) new Wrap%s((%s *)*lplpDD);' % (iface.name, iface.name)
-                print '        }'
-            print '    }'
-
-        DllTracer.wrap_arg(self, function, arg)
-
-
-if __name__ == '__main__':
-    print '#define INITGUID'
-    print '#include <windows.h>'
-    print '#include <ddraw.h>'
-    print '#include <d3d.h>'
-    print
-    print '''
-
-#ifndef DDBLT_EXTENDED_FLAGS
-#define DDBLT_EXTENDED_FLAGS 0x40000000l
-#endif
-
-#ifndef DDBLT_EXTENDED_LINEAR_CONTENT
-#define DDBLT_EXTENDED_LINEAR_CONTENT 0x00000004l
-#endif
-
-#ifndef D3DLIGHT_PARALLELPOINT
-#define D3DLIGHT_PARALLELPOINT (D3DLIGHTTYPE)4
-#endif
-
-#ifndef D3DLIGHT_GLSPOT
-#define D3DLIGHT_GLSPOT (D3DLIGHTTYPE)5
-#endif
-
-'''
-    print '#include "trace_writer.hpp"'
-    print '#include "os.hpp"'
-    print
-    tracer = DDrawTracer('ddraw.dll')
-    tracer.trace_api(ddraw)
diff --git a/d3d8.py b/d3d8.py
index f579a9b40617733f19d243d6532bc8e73a759cd0..0713696ecd9a65dd8eab9a007d3302f1fca067e9 100644 (file)
--- a/d3d8.py
+++ b/d3d8.py
@@ -28,7 +28,6 @@
 from winapi import *
 from d3d8types import *
 from d3d8caps import *
-from trace import DllTracer
 
 HRESULT = Enum("HRESULT", [
     "D3D_OK",
@@ -281,27 +280,3 @@ d3d8 = API("d3d8")
 d3d8.add_functions([
     StdFunction(PDIRECT3D8, "Direct3DCreate8", [(UINT, "SDKVersion")]),
 ])
-
-
-class D3D8Tracer(DllTracer):
-
-    def dump_arg_instance(self, function, arg):
-        # Dump shaders as strings
-        if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
-            print '    DumpShader(Trace::localWriter, %s);' % (arg.name)
-            return
-
-        DllTracer.dump_arg_instance(self, function, arg)
-
-
-if __name__ == '__main__':
-    print '#include <windows.h>'
-    print '#include <d3d8.h>'
-    print '#include "d3dshader.hpp"'
-    print
-    print '#include "trace_writer.hpp"'
-    print '#include "os.hpp"'
-    print
-    tracer = D3D8Tracer('d3d8.dll')
-    tracer.trace_api(d3d8)
-
diff --git a/d3d8trace.py b/d3d8trace.py
new file mode 100644 (file)
index 0000000..236f56c
--- /dev/null
@@ -0,0 +1,52 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# 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.
+#
+##########################################################################/
+
+
+from d3d8 import d3d8
+from trace import DllTracer
+
+
+class D3D8Tracer(DllTracer):
+
+    def dump_arg_instance(self, function, arg):
+        # Dump shaders as strings
+        if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
+            print '    DumpShader(Trace::localWriter, %s);' % (arg.name)
+            return
+
+        DllTracer.dump_arg_instance(self, function, arg)
+
+
+if __name__ == '__main__':
+    print '#include <windows.h>'
+    print '#include <d3d8.h>'
+    print '#include "d3dshader.hpp"'
+    print
+    print '#include "trace_writer.hpp"'
+    print '#include "os.hpp"'
+    print
+    tracer = D3D8Tracer('d3d8.dll')
+    tracer.trace_api(d3d8)
+
diff --git a/d3d9.py b/d3d9.py
index 640d218dc7a8c2b4726d142cd268e6ec92e128ca..251f2920fb90cf37110c369a326446c1503ac3a0 100644 (file)
--- a/d3d9.py
+++ b/d3d9.py
@@ -28,7 +28,7 @@
 from winapi import *
 from d3d9types import *
 from d3d9caps import *
-from trace import DllTracer
+
 
 D3DSHADER9 = Opaque("const DWORD *")
 
@@ -448,26 +448,3 @@ d3d9.add_functions([
     StdFunction(Void, "D3DPERF_SetOptions", [(DWORD, "dwOptions")]),
     StdFunction(DWORD, "D3DPERF_GetStatus", [], fail='0'),
 ])
-
-
-class D3D9Tracer(DllTracer):
-
-    def dump_arg_instance(self, function, arg):
-        # Dump shaders as strings
-        if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
-            print '    DumpShader(Trace::localWriter, %s);' % (arg.name)
-            return
-
-        DllTracer.dump_arg_instance(self, function, arg)
-
-
-if __name__ == '__main__':
-    print '#include "trace_writer.hpp"'
-    print '#include "os.hpp"'
-    print
-    print '#include "d3d9imports.hpp"'
-    print '#include "d3dshader.hpp"'
-    print
-    tracer = D3D9Tracer('d3d9.dll')
-    tracer.trace_api(d3d9)
-
diff --git a/d3d9trace.py b/d3d9trace.py
new file mode 100644 (file)
index 0000000..b83ebf6
--- /dev/null
@@ -0,0 +1,51 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# 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.
+#
+##########################################################################/
+
+
+from trace import DllTracer
+from d3d9 import d3d9
+
+
+class D3D9Tracer(DllTracer):
+
+    def dump_arg_instance(self, function, arg):
+        # Dump shaders as strings
+        if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
+            print '    DumpShader(Trace::localWriter, %s);' % (arg.name)
+            return
+
+        DllTracer.dump_arg_instance(self, function, arg)
+
+
+if __name__ == '__main__':
+    print '#include "trace_writer.hpp"'
+    print '#include "os.hpp"'
+    print
+    print '#include "d3d9imports.hpp"'
+    print '#include "d3dshader.hpp"'
+    print
+    tracer = D3D9Tracer('d3d9.dll')
+    tracer.trace_api(d3d9)
+
index 8ac08a85685e6e77f7623b45c849199c74ea98a1..eb5a07204b17235d3dd322403e8e664649dfce09 100644 (file)
--- a/ddraw.py
+++ b/ddraw.py
@@ -26,7 +26,6 @@
 """ddraw.h"""
 
 from winapi import *
-from trace import DllTracer
 
 DirectDrawOptSurfaceDescFlags = Flags(DWORD, [
     "DDOSD_GUID",
diff --git a/ddrawtrace.py b/ddrawtrace.py
new file mode 100644 (file)
index 0000000..0b53f0d
--- /dev/null
@@ -0,0 +1,81 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# 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.
+#
+##########################################################################/
+
+
+from d3d import ddraw, interfaces
+from trace import DllTracer
+
+
+class DDrawTracer(DllTracer):
+
+    def trace_function_impl_body(self, function):
+        if function.name in ('AcquireDDThreadLock', 'ReleaseDDThreadLock'):
+            self.dispatch_function(function)
+            return
+
+        DllTracer.trace_function_impl_body(self, function)
+
+    def wrap_arg(self, function, arg):
+        if function.name == 'DirectDrawCreateEx' and arg.name == 'lplpDD':
+            print '    if (*lplpDD) {'
+            for iface in interfaces:
+                print '        if (iid == IID_%s) {' % iface.name
+                print '            *lplpDD = (LPVOID) new Wrap%s((%s *)*lplpDD);' % (iface.name, iface.name)
+                print '        }'
+            print '    }'
+
+        DllTracer.wrap_arg(self, function, arg)
+
+
+if __name__ == '__main__':
+    print '#define INITGUID'
+    print '#include <windows.h>'
+    print '#include <ddraw.h>'
+    print '#include <d3d.h>'
+    print
+    print '''
+
+#ifndef DDBLT_EXTENDED_FLAGS
+#define DDBLT_EXTENDED_FLAGS 0x40000000l
+#endif
+
+#ifndef DDBLT_EXTENDED_LINEAR_CONTENT
+#define DDBLT_EXTENDED_LINEAR_CONTENT 0x00000004l
+#endif
+
+#ifndef D3DLIGHT_PARALLELPOINT
+#define D3DLIGHT_PARALLELPOINT (D3DLIGHTTYPE)4
+#endif
+
+#ifndef D3DLIGHT_GLSPOT
+#define D3DLIGHT_GLSPOT (D3DLIGHTTYPE)5
+#endif
+
+'''
+    print '#include "trace_writer.hpp"'
+    print '#include "os.hpp"'
+    print
+    tracer = DDrawTracer('ddraw.dll')
+    tracer.trace_api(ddraw)
diff --git a/formatter.hpp b/formatter.hpp
deleted file mode 100644 (file)
index 181e2d1..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Helpers for coloring output.
- */
-
-#ifndef _FORMATTER_HPP_
-#define _FORMATTER_HPP_
-
-
-#include <iostream>
-
-
-namespace Formatter {
-
-/*
- * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas
- */
-
-class Attribute {
-public:
-    virtual ~Attribute() {}
-
-    virtual void apply(std::ostream &) const {}
-};
-
-
-enum Color {
-    RED,
-    GREEN,
-    BLUE,
-};
-
-
-class Formatter {
-public:
-    virtual ~Formatter() {}
-
-    virtual Attribute *normal(void) const { return new Attribute; }
-    virtual Attribute *bold(void) const { return new Attribute; }
-    virtual Attribute *italic(void) const { return new Attribute; }
-    virtual Attribute *color(Color) const { return new Attribute; }
-};
-
-
-class AnsiAttribute : public Attribute {
-protected:
-    const char *escape;
-public:
-    AnsiAttribute(const char *_escape) : escape(_escape) {}
-    void apply(std::ostream& os) const {
-        os << "\33[" << escape;
-    }
-};
-
-
-/**
- * Formatter for plain-text files which outputs ANSI escape codes. See
- * http://en.wikipedia.org/wiki/ANSI_escape_code for more information
- * concerning ANSI escape codes.
- */
-class AnsiFormatter : public Formatter {
-protected:
-public:
-    virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); }
-    virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); }
-    virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); }
-    virtual Attribute *color(Color c) const { 
-        static const char *color_escapes[] = {
-            "31m", /* red */
-            "32m", /* green */
-            "34m", /* blue */
-        };
-        return new AnsiAttribute(color_escapes[c]); 
-    }
-};
-
-
-inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) {
-    attr->apply(os);
-    return os;
-}
-
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-class WindowsAttribute : public Attribute {
-protected:
-    WORD wAttributes;
-public:
-    WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {}
-    void apply(std::ostream& os) const {
-        DWORD nStdHandleOutput;
-        if (os == std::cout) {
-            nStdHandleOutput = STD_OUTPUT_HANDLE;
-        } else if (os == std::cerr) {
-            nStdHandleOutput = STD_ERROR_HANDLE;
-        } else {
-            return;
-        }
-        HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput);
-        if (hConsoleOutput == INVALID_HANDLE_VALUE) {
-            return;
-        }
-
-        SetConsoleTextAttribute(hConsoleOutput, wAttributes);
-    }
-};
-
-
-/**
- * Formatter for the Windows Console.
- */
-class WindowsFormatter : public Formatter {
-protected:
-public:
-    virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
-    virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); }
-    virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
-    virtual Attribute *color(Color c) const { 
-        static const WORD color_escapes[] = {
-            FOREGROUND_RED | FOREGROUND_INTENSITY,
-            FOREGROUND_GREEN | FOREGROUND_INTENSITY,
-            FOREGROUND_BLUE | FOREGROUND_INTENSITY, 
-        };
-        return new WindowsAttribute(color_escapes[c]); 
-    }
-};
-
-#endif
-
-
-inline Formatter *defaultFormatter(bool color = true) {
-    if (color) {
-#ifdef _WIN32
-        return new WindowsFormatter;
-#else
-        return new AnsiFormatter;
-#endif
-    } else {
-        return new Formatter;
-    }
-}
-
-
-} /* namespace Formatter */
-
-
-#endif /* _FORMATTER_HPP_ */
index cb903fad6af17e3261a27c48cb32d6d2e66c005c..a3a0b58d9487f2ab6a184f7d4e421437db6ca773 100644 (file)
--- a/glapi.py
+++ b/glapi.py
@@ -664,7 +664,7 @@ glapi.add_functions([
     GlFunction(Void, "glEnablei", [(GLenum, "target"), (GLuint, "index")]),
     GlFunction(Void, "glDisablei", [(GLenum, "target"), (GLuint, "index")]),
     GlFunction(GLboolean, "glIsEnabledi", [(GLenum, "target"), (GLuint, "index")], sideeffects=False),
-    GlFunction(Void, "glBeginTransformFeedback", [(GLenum, "primitiveMode")]),
+    GlFunction(Void, "glBeginTransformFeedback", [(GLenum_mode, "primitiveMode")]),
     GlFunction(Void, "glEndTransformFeedback", []),
     GlFunction(Void, "glBindBufferRange", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
     GlFunction(Void, "glBindBufferBase", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer")]),
@@ -1177,17 +1177,17 @@ glapi.add_functions([
     GlFunction(Void, "glPatchParameterfv", [(GLenum, "pname"), (Const(Array(GLfloat, "__gl_param_size(pname)")), "values")]),
 
     # GL_ARB_transform_feedback2
-    GlFunction(Void, "glBindTransformFeedback", [(GLenum, "target"), (GLuint, "id")]),
-    GlFunction(Void, "glDeleteTransformFeedbacks", [(GLsizei, "n"), (Const(Array(GLuint, "n")), "ids")]),
-    GlFunction(Void, "glGenTransformFeedbacks", [(GLsizei, "n"), Out(Array(GLuint, "n"), "ids")]),
-    GlFunction(GLboolean, "glIsTransformFeedback", [(GLuint, "id")], sideeffects=False),
+    GlFunction(Void, "glBindTransformFeedback", [(GLenum, "target"), (GLfeedback, "id")]),
+    GlFunction(Void, "glDeleteTransformFeedbacks", [(GLsizei, "n"), (Const(Array(GLfeedback, "n")), "ids")]),
+    GlFunction(Void, "glGenTransformFeedbacks", [(GLsizei, "n"), Out(Array(GLfeedback, "n"), "ids")]),
+    GlFunction(GLboolean, "glIsTransformFeedback", [(GLfeedback, "id")], sideeffects=False),
     GlFunction(Void, "glPauseTransformFeedback", []),
     GlFunction(Void, "glResumeTransformFeedback", []),
-    GlFunction(Void, "glDrawTransformFeedback", [(GLenum, "mode"), (GLuint, "id")]),
+    GlFunction(Void, "glDrawTransformFeedback", [(GLenum_mode, "mode"), (GLfeedback, "id")]),
 
     # GL_ARB_transform_feedback3
-    GlFunction(Void, "glDrawTransformFeedbackStream", [(GLenum, "mode"), (GLuint, "id"), (GLuint, "stream")]),
-    GlFunction(Void, "glBeginQueryIndexed", [(GLenum, "target"), (GLuint, "index"), (GLuint, "id")]),
+    GlFunction(Void, "glDrawTransformFeedbackStream", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLuint, "stream")]),
+    GlFunction(Void, "glBeginQueryIndexed", [(GLenum, "target"), (GLuint, "index"), (GLfeedback, "id")]),
     GlFunction(Void, "glEndQueryIndexed", [(GLenum, "target"), (GLuint, "index")]),
     GlFunction(Void, "glGetQueryIndexediv", [(GLenum, "target"), (GLuint, "index"), (GLenum, "pname"), Out(OpaqueArray(GLint, "__glGetQueryIndexediv_size(pname)"), "params")], sideeffects=False),
 
@@ -1317,6 +1317,33 @@ glapi.add_functions([
     GlFunction(Void, "glGetnUniformuivARB", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "bufSize"), Out(Array(GLuint, "bufSize"), "params")], sideeffects=False),
     GlFunction(Void, "glGetnUniformdvARB", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "bufSize"), Out(Array(GLdouble, "bufSize"), "params")], sideeffects=False),
 
+    # GL_ARB_base_instance
+    GlFunction(Void, "glDrawArraysInstancedBaseInstance", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "primcount"), (GLuint, "baseinstance")]),
+    GlFunction(Void, "glDrawElementsInstancedBaseInstance", [(GLenum_mode, "mode"), (GLsizei, "count"), (GLenum, "type"), (OpaquePointer(Const(GLvoid)), "indices"), (GLsizei, "primcount"), (GLuint, "baseinstance")]),
+    GlFunction(Void, "glDrawElementsInstancedBaseVertexBaseInstance", [(GLenum_mode, "mode"), (GLsizei, "count"), (GLenum, "type"), (OpaquePointer(Const(GLvoid)), "indices"), (GLsizei, "primcount"), (GLint, "basevertex"), (GLuint, "baseinstance")]),
+
+    # GL_ARB_transform_feedback_instanced
+    GlFunction(Void, "glDrawTransformFeedbackInstanced", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLsizei, "primcount")]),
+    GlFunction(Void, "glDrawTransformFeedbackStreamInstanced", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLuint, "stream"), (GLsizei, "primcount")]),
+
+    # GL_ARB_internalformat_query
+    GlFunction(Void, "glGetInternalformativ", [(GLenum, "target"), (GLenum, "internalformat"), (GLenum, "pname"), (GLsizei, "bufSize"), Out(Array(GLint, "bufSize"), "params")], sideeffects=False),
+
+    # GL_ARB_shader_atomic_counters
+    GlFunction(Void, "glGetActiveAtomicCounterBufferiv", [(GLprogram, "program"), (GLuint, "bufferIndex"), (GLenum, "pname"), Out(OpaqueArray(GLint, "__glGetActiveAtomicCounterBufferiv_size(pname)"), "params")], sideeffects=False),
+
+    # GL_ARB_shader_image_load_store
+    GlFunction(Void, "glBindImageTexture", [(GLuint, "unit"), (GLtexture, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLenum, "format")]),
+    GlFunction(Void, "glMemoryBarrier", [(GLbitfield_barrier, "barriers")]),
+
+    # GL_ARB_texture_storage
+    GlFunction(Void, "glTexStorage1D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width")]),
+    GlFunction(Void, "glTexStorage2D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height")]),
+    GlFunction(Void, "glTexStorage3D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
+    GlFunction(Void, "glTextureStorage1DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width")]),
+    GlFunction(Void, "glTextureStorage2DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height")]),
+    GlFunction(Void, "glTextureStorage3DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
+
     # GL_EXT_blend_color
     GlFunction(Void, "glBlendColorEXT", [(GLclampf, "red"), (GLclampf, "green"), (GLclampf, "blue"), (GLclampf, "alpha")]),
 
@@ -1992,11 +2019,11 @@ glapi.add_functions([
 
     # GL_ATI_element_array
     GlFunction(Void, "glElementPointerATI", [(GLenum, "type"), (Const(OpaquePointer(GLvoid)), "pointer")]),
-    GlFunction(Void, "glDrawElementArrayATI", [(GLenum, "mode"), (GLsizei, "count")]),
-    GlFunction(Void, "glDrawRangeElementArrayATI", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (GLsizei, "count")]),
+    GlFunction(Void, "glDrawElementArrayATI", [(GLenum_mode, "mode"), (GLsizei, "count")]),
+    GlFunction(Void, "glDrawRangeElementArrayATI", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (GLsizei, "count")]),
 
     # GL_SUN_mesh_array
-    GlFunction(Void, "glDrawMeshArraysSUN", [(GLenum, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "width")]),
+    GlFunction(Void, "glDrawMeshArraysSUN", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "width")]),
 
     # GL_NV_occlusion_query
     GlFunction(Void, "glGenOcclusionQueriesNV", [(GLsizei, "n"), Out(Array(GLquery, "n"), "ids")]),
@@ -2016,10 +2043,10 @@ glapi.add_functions([
 
     # GL_APPLE_element_array
     GlFunction(Void, "glElementPointerAPPLE", [(GLenum, "type"), (Const(Blob(GLvoid, "type")), "pointer")]),
-    GlFunction(Void, "glDrawElementArrayAPPLE", [(GLenum, "mode"), (GLint, "first"), (GLsizei, "count")]),
-    GlFunction(Void, "glDrawRangeElementArrayAPPLE", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (GLint, "first"), (GLsizei, "count")]),
-    GlFunction(Void, "glMultiDrawElementArrayAPPLE", [(GLenum, "mode"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
-    GlFunction(Void, "glMultiDrawRangeElementArrayAPPLE", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
+    GlFunction(Void, "glDrawElementArrayAPPLE", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count")]),
+    GlFunction(Void, "glDrawRangeElementArrayAPPLE", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (GLint, "first"), (GLsizei, "count")]),
+    GlFunction(Void, "glMultiDrawElementArrayAPPLE", [(GLenum_mode, "mode"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
+    GlFunction(Void, "glMultiDrawRangeElementArrayAPPLE", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
 
     # GL_APPLE_fence
     GlFunction(Void, "glGenFencesAPPLE", [(GLsizei, "n"), Out(Array(GLuint, "n"), "fences")]),
@@ -2270,7 +2297,7 @@ glapi.add_functions([
     GlFunction(GLboolean, "glIsEnabledIndexedEXT", [(GLenum, "target"), (GLuint, "index")], sideeffects=False),
 
     # GL_NV_transform_feedback
-    GlFunction(Void, "glBeginTransformFeedbackNV", [(GLenum, "primitiveMode")]),
+    GlFunction(Void, "glBeginTransformFeedbackNV", [(GLenum_mode, "primitiveMode")]),
     GlFunction(Void, "glEndTransformFeedbackNV", []),
     GlFunction(Void, "glTransformFeedbackAttribsNV", [(GLuint, "count"), (Const(OpaqueArray(GLint, "__glTransformFeedbackAttribsNV_size(count)")), "attribs"), (GLenum, "bufferMode")]),
     GlFunction(Void, "glBindBufferRangeNV", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
@@ -2297,7 +2324,7 @@ glapi.add_functions([
     GlFunction(Void, "glClearColorIuiEXT", [(GLuint, "red"), (GLuint, "green"), (GLuint, "blue"), (GLuint, "alpha")]),
 
     # GL_GREMEDY_frame_terminator
-    GlFunction(Void, "glFrameTerminatorGREMEDY", [], sideeffects=False),
+    GlFunction(Void, "glFrameTerminatorGREMEDY", []),
 
     # GL_NV_conditional_render
     GlFunction(Void, "glBeginConditionalRenderNV", [(GLuint, "id"), (GLenum, "mode")]),
@@ -2312,7 +2339,7 @@ glapi.add_functions([
     GlFunction(Void, "glGetVideoui64vNV", [(GLuint, "video_slot"), (GLenum, "pname"), Out(OpaqueArray(GLuint64EXT, "__glGetVideoui64vNV_size(pname)"), "params")], sideeffects=False),
 
     # GL_EXT_transform_feedback
-    GlFunction(Void, "glBeginTransformFeedbackEXT", [(GLenum, "primitiveMode")]),
+    GlFunction(Void, "glBeginTransformFeedbackEXT", [(GLenum_mode, "primitiveMode")]),
     GlFunction(Void, "glEndTransformFeedbackEXT", []),
     GlFunction(Void, "glBindBufferRangeEXT", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
     GlFunction(Void, "glBindBufferOffsetEXT", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset")]),
@@ -2527,25 +2554,25 @@ glapi.add_functions([
     GlFunction(Void, "glProgramUniformMatrix3x4dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*3*4")), "value")]),
     GlFunction(Void, "glProgramUniformMatrix4x2dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*4*2")), "value")]),
     GlFunction(Void, "glProgramUniformMatrix4x3dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*4*3")), "value")]),
-    Function(Void, "glVertexArrayVertexOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayColorOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayEdgeFlagOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayIndexOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayNormalOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayTexCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayMultiTexCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "texunit"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayFogCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArraySecondaryColorOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayVertexAttribOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLboolean, "normalized"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glVertexArrayVertexAttribIOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
-    Function(Void, "glEnableVertexArrayEXT", [(GLuint, "vaobj"), (GLenum, "array")]),
-    Function(Void, "glDisableVertexArrayEXT", [(GLuint, "vaobj"), (GLenum, "array")]),
-    Function(Void, "glEnableVertexArrayAttribEXT", [(GLuint, "vaobj"), (GLuint, "index")]),
-    Function(Void, "glDisableVertexArrayAttribEXT", [(GLuint, "vaobj"), (GLuint, "index")]),
-    Function(Void, "glGetVertexArrayIntegervEXT", [(GLuint, "vaobj"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
-    Function(Void, "glGetVertexArrayPointervEXT", [(GLuint, "vaobj"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
-    Function(Void, "glGetVertexArrayIntegeri_vEXT", [(GLuint, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
-    Function(Void, "glGetVertexArrayPointeri_vEXT", [(GLuint, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
+    GlFunction(Void, "glVertexArrayVertexOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayColorOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayEdgeFlagOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayIndexOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayNormalOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayTexCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayMultiTexCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "texunit"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayFogCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArraySecondaryColorOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayVertexAttribOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLboolean, "normalized"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayVertexAttribIOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glEnableVertexArrayEXT", [(GLarray, "vaobj"), (GLenum, "array")]),
+    GlFunction(Void, "glDisableVertexArrayEXT", [(GLarray, "vaobj"), (GLenum, "array")]),
+    GlFunction(Void, "glEnableVertexArrayAttribEXT", [(GLarray, "vaobj"), (GLuint, "index")]),
+    GlFunction(Void, "glDisableVertexArrayAttribEXT", [(GLarray, "vaobj"), (GLuint, "index")]),
+    GlFunction(Void, "glGetVertexArrayIntegervEXT", [(GLarray, "vaobj"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
+    GlFunction(Void, "glGetVertexArrayPointervEXT", [(GLarray, "vaobj"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
+    GlFunction(Void, "glGetVertexArrayIntegeri_vEXT", [(GLarray, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
+    GlFunction(Void, "glGetVertexArrayPointeri_vEXT", [(GLarray, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
 
     # GL_NV_explicit_multisample
     GlFunction(Void, "glGetMultisamplefvNV", [(GLenum, "pname"), (GLuint, "index"), Out(Array(GLfloat, "2"), "val")], sideeffects=False),
@@ -2553,13 +2580,13 @@ glapi.add_functions([
     GlFunction(Void, "glTexRenderbufferNV", [(GLenum, "target"), (GLuint, "renderbuffer")]),
 
     # GL_NV_transform_feedback2
-    GlFunction(Void, "glBindTransformFeedbackNV", [(GLenum, "target"), (GLuint, "id")]),
-    GlFunction(Void, "glDeleteTransformFeedbacksNV", [(GLsizei, "n"), (Const(Array(GLuint, "n")), "ids")]),
-    GlFunction(Void, "glGenTransformFeedbacksNV", [(GLsizei, "n"), Out(Array(GLuint, "n"), "ids")]),
-    GlFunction(GLboolean, "glIsTransformFeedbackNV", [(GLuint, "id")], sideeffects=False),
+    GlFunction(Void, "glBindTransformFeedbackNV", [(GLenum, "target"), (GLfeedback, "id")]),
+    GlFunction(Void, "glDeleteTransformFeedbacksNV", [(GLsizei, "n"), (Const(Array(GLfeedback, "n")), "ids")]),
+    GlFunction(Void, "glGenTransformFeedbacksNV", [(GLsizei, "n"), Out(Array(GLfeedback, "n"), "ids")]),
+    GlFunction(GLboolean, "glIsTransformFeedbackNV", [(GLfeedback, "id")], sideeffects=False),
     GlFunction(Void, "glPauseTransformFeedbackNV", []),
     GlFunction(Void, "glResumeTransformFeedbackNV", []),
-    GlFunction(Void, "glDrawTransformFeedbackNV", [(GLenum, "mode"), (GLuint, "id")]),
+    GlFunction(Void, "glDrawTransformFeedbackNV", [(GLenum_mode, "mode"), (GLfeedback, "id")]),
 
     # GL_AMD_performance_monitor
     GlFunction(Void, "glGetPerfMonitorGroupsAMD", [Out(Pointer(GLint), "numGroups"), (GLsizei, "groupsSize"), Out(Array(GLuint, "groupsSize"), "groups")], sideeffects=False),
@@ -2661,8 +2688,8 @@ glapi.add_functions([
     GlFunction(Void, "glTextureBarrierNV", []),
 
     # GL_EXT_shader_image_load_store
-    GlFunction(Void, "glBindImageTextureEXT", [(GLuint, "index"), (GLuint, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLint, "format")]),
-    GlFunction(Void, "glMemoryBarrierEXT", [(GLbitfield, "barriers")]),
+    GlFunction(Void, "glBindImageTextureEXT", [(GLuint, "index"), (GLtexture, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLint, "format")]),
+    GlFunction(Void, "glMemoryBarrierEXT", [(GLbitfield_barrier, "barriers")]),
 
     # GL_EXT_vertex_attrib_64bit
     GlFunction(Void, "glVertexAttribL1dEXT", [(GLuint, "index"), (GLdouble, "x")]),
@@ -2675,7 +2702,7 @@ glapi.add_functions([
     GlFunction(Void, "glVertexAttribL4dvEXT", [(GLuint, "index"), (Const(Array(GLdouble, "4")), "v")]),
     GlFunction(Void, "glVertexAttribLPointerEXT", [(GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (Const(Blob(GLvoid, "size")), "pointer")]),
     GlFunction(Void, "glGetVertexAttribLdvEXT", [(GLuint, "index"), (GLenum, "pname"), Out(OpaqueArray(GLdouble, "__glGetVertexAttribLdvEXT_size(pname)"), "params")], sideeffects=False),
-    GlFunction(Void, "glVertexArrayVertexAttribLOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+    GlFunction(Void, "glVertexArrayVertexAttribLOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
 
     # GL_NV_gpu_program5
     GlFunction(Void, "glProgramSubroutineParametersuivNV", [(GLenum, "target"), (GLsizei, "count"), (Const(Array(GLuint, "count")), "params")]),
@@ -2763,8 +2790,8 @@ glapi.add_functions([
     GlFunction(GLsync, "glImportSyncEXT", [(GLenum, "external_sync_type"), (GLintptr, "external_sync"), (GLbitfield, "flags")]),
 
     # GL_AMD_multi_draw_indirect
-    GlFunction(Void, "glMultiDrawArraysIndirectAMD", [(GLenum, "mode"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
-    GlFunction(Void, "glMultiDrawElementsIndirectAMD", [(GLenum, "mode"), (GLenum, "type"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
+    GlFunction(Void, "glMultiDrawArraysIndirectAMD", [(GLenum_mode, "mode"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
+    GlFunction(Void, "glMultiDrawElementsIndirectAMD", [(GLenum_mode, "mode"), (GLenum, "type"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
 
     # GL_KTX_buffer_region
     # XXX: http://www.west.net/~brittain/3dsmax2.htm does not mention EXT suffix
@@ -2781,7 +2808,7 @@ glapi.add_functions([
     GlFunction(GLuint, "glBufferRegionEnabledEXT", [], sideeffects=False),
 
     # GL_WIN_swap_hint
-    Function(Void, "glAddSwapHintRectWIN", [(GLint, "x"), (GLint, "y"), (GLsizei, "width"), (GLsizei, "height")]),
+    GlFunction(Void, "glAddSwapHintRectWIN", [(GLint, "x"), (GLint, "y"), (GLsizei, "width"), (GLsizei, "height")]),
 ])
 
 
index 9337a398b5e257b30bdf5bc86d38b7e1753e2b32..8636877285404cea6e1495a2f3d035d7aec0bc11 100644 (file)
@@ -33,7 +33,7 @@ from gltypes import *
 
 
 # Shorthands for the types
-X = None # To be determined
+X = None # To be determined, merely an enum
 B = GLboolean
 I = GLint
 I64 = GLint64
@@ -44,6 +44,8 @@ P = OpaquePointer(Void)
 S = CString
 H = GLhandleARB
 
+# A underscore prefix (e.g., _glGet) is used to skip automatic code generation
+# for parameters that are obtained through other ways.
 
 parameters = [
     # (functions, type, count, name) # value
@@ -285,7 +287,7 @@ parameters = [
     ("glGet",  F,      1,      "GL_DEPTH_BIAS"),       # 0x0D1F
     ("glGet",  I,      1,      "GL_MAX_EVAL_ORDER"),   # 0x0D30
     ("glGet",  I,      1,      "GL_MAX_LIGHTS"),       # 0x0D31
-    ("glGet",  I,      1,      "GL_MAX_CLIP_PLANES"),  # 0x0D32
+    ("glGet",  I,      1,      "GL_MAX_CLIP_DISTANCES"),       # 0x0D32
     ("glGet",  I,      1,      "GL_MAX_TEXTURE_SIZE"), # 0x0D33
     ("glGet",  I,      1,      "GL_MAX_PIXEL_MAP_TABLE"),      # 0x0D34
     ("glGet",  I,      1,      "GL_MAX_ATTRIB_STACK_DEPTH"),   # 0x0D35
@@ -331,8 +333,8 @@ parameters = [
     ("glGet",  I,      1,      "GL_MAP1_GRID_SEGMENTS"),       # 0x0DD1
     ("glGet",  F,      4,      "GL_MAP2_GRID_DOMAIN"), # 0x0DD2
     ("glGet",  I,      2,      "GL_MAP2_GRID_SEGMENTS"),       # 0x0DD3
-    ("glGet",  B,      1,      "GL_TEXTURE_1D"),       # 0x0DE0
-    ("glGet",  B,      1,      "GL_TEXTURE_2D"),       # 0x0DE1
+    ("_glGet", B,      1,      "GL_TEXTURE_1D"),       # 0x0DE0
+    ("_glGet", B,      1,      "GL_TEXTURE_2D"),       # 0x0DE1
     ("glGet",  P,      1,      "GL_FEEDBACK_BUFFER_POINTER"),  # 0x0DF0
     ("glGet",  I,      1,      "GL_FEEDBACK_BUFFER_SIZE"),     # 0x0DF1
     ("glGet",  E,      1,      "GL_FEEDBACK_BUFFER_TYPE"),     # 0x0DF2
@@ -497,14 +499,14 @@ parameters = [
     ("",       X,      1,      "GL_T2F_N3F_V3F"),      # 0x2A2B
     ("",       X,      1,      "GL_T2F_C4F_N3F_V3F"),  # 0x2A2C
     ("",       X,      1,      "GL_T4F_C4F_N3F_V4F"),  # 0x2A2D
-    ("glGet",  B,      1,      "GL_CLIP_PLANE0"),      # 0x3000
-    ("glGet",  B,      1,      "GL_CLIP_PLANE1"),      # 0x3001
-    ("glGet",  B,      1,      "GL_CLIP_PLANE2"),      # 0x3002
-    ("glGet",  B,      1,      "GL_CLIP_PLANE3"),      # 0x3003
-    ("glGet",  B,      1,      "GL_CLIP_PLANE4"),      # 0x3004
-    ("glGet",  B,      1,      "GL_CLIP_PLANE5"),      # 0x3005
-    ("",       X,      1,      "GL_CLIP_DISTANCE6"),   # 0x3006
-    ("",       X,      1,      "GL_CLIP_DISTANCE7"),   # 0x3007
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE0"),   # 0x3000
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE1"),   # 0x3001
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE2"),   # 0x3002
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE3"),   # 0x3003
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE4"),   # 0x3004
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE5"),   # 0x3005
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE6"),   # 0x3006
+    ("glGet",  B,      1,      "GL_CLIP_DISTANCE7"),   # 0x3007
     ("_glGet", B,      1,      "GL_LIGHT0"),   # 0x4000
     ("_glGet", B,      1,      "GL_LIGHT1"),   # 0x4001
     ("_glGet", B,      1,      "GL_LIGHT2"),   # 0x4002
@@ -617,9 +619,9 @@ parameters = [
     ("",       X,      1,      "GL_TEXTURE_TOO_LARGE_EXT"),    # 0x8065
     ("glGetTexParameter",      F,      1,      "GL_TEXTURE_PRIORITY"), # 0x8066
     ("glGetTexParameter",      B,      1,      "GL_TEXTURE_RESIDENT"), # 0x8067
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_1D"),       # 0x8068
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_2D"),       # 0x8069
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_3D"),       # 0x806A
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_1D"),       # 0x8068
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_2D"),       # 0x8069
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_3D"),       # 0x806A
     ("glGet",  I,      1,      "GL_PACK_SKIP_IMAGES"), # 0x806B
     ("glGet",  F,      1,      "GL_PACK_IMAGE_HEIGHT"),        # 0x806C
     ("glGet",  I,      1,      "GL_UNPACK_SKIP_IMAGES"),       # 0x806D
@@ -1182,8 +1184,8 @@ parameters = [
     ("",       X,      1,      "GL_ALL_COMPLETED_NV"), # 0x84F2
     ("",       X,      1,      "GL_FENCE_STATUS_NV"),  # 0x84F3
     ("",       X,      1,      "GL_FENCE_CONDITION_NV"),       # 0x84F4
-    ("glGet",  B,      1,      "GL_TEXTURE_RECTANGLE"),        # 0x84F5
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_RECTANGLE"),        # 0x84F6
+    ("_glGet", B,      1,      "GL_TEXTURE_RECTANGLE"),        # 0x84F5
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_RECTANGLE"),        # 0x84F6
     ("",       X,      1,      "GL_PROXY_TEXTURE_RECTANGLE"),  # 0x84F7
     ("glGet",  I,      1,      "GL_MAX_RECTANGLE_TEXTURE_SIZE"),       # 0x84F8
     ("",       X,      1,      "GL_DEPTH_STENCIL"),    # 0x84F9
@@ -1210,8 +1212,8 @@ parameters = [
     ("",       X,      1,      "GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT"),  # 0x8510
     ("",       X,      1,      "GL_NORMAL_MAP"),       # 0x8511
     ("",       X,      1,      "GL_REFLECTION_MAP"),   # 0x8512
-    ("glGet",  B,      1,      "GL_TEXTURE_CUBE_MAP"), # 0x8513
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_CUBE_MAP"), # 0x8514
+    ("_glGet", B,      1,      "GL_TEXTURE_CUBE_MAP"), # 0x8513
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_CUBE_MAP"), # 0x8514
     ("",       X,      1,      "GL_TEXTURE_CUBE_MAP_POSITIVE_X"),      # 0x8515
     ("",       X,      1,      "GL_TEXTURE_CUBE_MAP_NEGATIVE_X"),      # 0x8516
     ("",       X,      1,      "GL_TEXTURE_CUBE_MAP_POSITIVE_Y"),      # 0x8517
@@ -1233,8 +1235,8 @@ parameters = [
     ("",       X,      1,      "GL_VARIABLE_E_NV"),    # 0x8527
     ("",       X,      1,      "GL_VARIABLE_F_NV"),    # 0x8528
     ("",       X,      1,      "GL_VARIABLE_G_NV"),    # 0x8529
-    ("",       X,      1,      "GL_CONSTANT_COLOR0_NV"),       # 0x852A
-    ("",       X,      1,      "GL_CONSTANT_COLOR1_NV"),       # 0x852B
+    ("glGet",  F,      4,      "GL_CONSTANT_COLOR0_NV"),       # 0x852A
+    ("glGet",  F,      4,      "GL_CONSTANT_COLOR1_NV"),       # 0x852B
     ("",       X,      1,      "GL_PRIMARY_COLOR_NV"), # 0x852C
     ("",       X,      1,      "GL_SECONDARY_COLOR_NV"),       # 0x852D
     ("",       X,      1,      "GL_SPARE0_NV"),        # 0x852E
@@ -1268,9 +1270,9 @@ parameters = [
     ("",       X,      1,      "GL_COMBINER_AB_OUTPUT_NV"),    # 0x854A
     ("",       X,      1,      "GL_COMBINER_CD_OUTPUT_NV"),    # 0x854B
     ("",       X,      1,      "GL_COMBINER_SUM_OUTPUT_NV"),   # 0x854C
-    ("",       X,      1,      "GL_MAX_GENERAL_COMBINERS_NV"), # 0x854D
-    ("",       X,      1,      "GL_NUM_GENERAL_COMBINERS_NV"), # 0x854E
-    ("",       X,      1,      "GL_COLOR_SUM_CLAMP_NV"),       # 0x854F
+    ("glGet",  I,      1,      "GL_MAX_GENERAL_COMBINERS_NV"), # 0x854D
+    ("glGet",  I,      1,      "GL_NUM_GENERAL_COMBINERS_NV"), # 0x854E
+    ("glGet",  B,      1,      "GL_COLOR_SUM_CLAMP_NV"),       # 0x854F
     ("",       X,      1,      "GL_COMBINER0_NV"),     # 0x8550
     ("",       X,      1,      "GL_COMBINER1_NV"),     # 0x8551
     ("",       X,      1,      "GL_COMBINER2_NV"),     # 0x8552
@@ -1384,7 +1386,7 @@ parameters = [
     ("",       X,      1,      "GL_MATRIX7_NV"),       # 0x8637
     ("glGet",  I,      1,      "GL_CURRENT_MATRIX_STACK_DEPTH_ARB"),   # 0x8640
     ("glGet",  F,      16,     "GL_CURRENT_MATRIX_ARB"),       # 0x8641
-    ("glGet",  B,      1,      "GL_VERTEX_PROGRAM_POINT_SIZE"),        # 0x8642
+    ("glGet",  B,      1,      "GL_PROGRAM_POINT_SIZE"),       # 0x8642
     ("glGet",  B,      1,      "GL_VERTEX_PROGRAM_TWO_SIDE"),  # 0x8643
     ("",       X,      1,      "GL_PROGRAM_PARAMETER_NV"),     # 0x8644
     ("glGetVertexAttrib",      P,      1,      "GL_VERTEX_ATTRIB_ARRAY_POINTER"),      # 0x8645
@@ -1825,7 +1827,7 @@ parameters = [
     ("glGetTexParameter",      E,      1,      "GL_DEPTH_TEXTURE_MODE"),       # 0x884B
     ("glGetTexParameter",      E,      1,      "GL_TEXTURE_COMPARE_MODE"),     # 0x884C
     ("glGetTexParameter",      E,      1,      "GL_TEXTURE_COMPARE_FUNC"),     # 0x884D
-    ("",       X,      1,      "GL_COMPARE_R_TO_TEXTURE"),     # 0x884E
+    ("",       X,      1,      "GL_COMPARE_REF_TO_TEXTURE"),   # 0x884E
     ("glGet",  B,      1,      "GL_TEXTURE_CUBE_MAP_SEAMLESS"),        # 0x884F
     ("",       X,      1,      "GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV"),  # 0x8850
     ("",       X,      1,      "GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV"),    # 0x8851
@@ -2118,6 +2120,12 @@ parameters = [
     ("",       X,      1,      "GL_RESAMPLE_ZERO_FILL_OML"),   # 0x8987
     ("",       X,      1,      "GL_RESAMPLE_AVERAGE_OML"),     # 0x8988
     ("",       X,      1,      "GL_RESAMPLE_DECIMATE_OML"),    # 0x8989
+    #("",      X,      1,      "GL_POINT_SIZE_ARRAY_TYPE_OES"),        # 0x898A
+    #("",      X,      1,      "GL_POINT_SIZE_ARRAY_STRIDE_OES"),      # 0x898B
+    #("",      X,      1,      "GL_POINT_SIZE_ARRAY_POINTER_OES"),     # 0x898C
+    #("",      X,      1,      "GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES"),   # 0x898D
+    #("",      X,      1,      "GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES"),  # 0x898E
+    #("",      X,      1,      "GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES"),     # 0x898F
     ("",       X,      1,      "GL_VERTEX_ATTRIB_MAP1_APPLE"), # 0x8A00
     ("",       X,      1,      "GL_VERTEX_ATTRIB_MAP2_APPLE"), # 0x8A01
     ("",       X,      1,      "GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE"),    # 0x8A02
@@ -2177,9 +2185,9 @@ parameters = [
     ("glGetActiveUniformBlock",        B,      1,      "GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER"),        # 0x8A44
     ("glGetActiveUniformBlock",        B,      1,      "GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER"),      # 0x8A45
     ("glGetActiveUniformBlock",        B,      1,      "GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER"),      # 0x8A46
-    #"glGet",  (X,     1,      "GL_TEXTURE_SRGB_DECODE_EXT"),  # 0x8A48
-    #"glGet",  (X,     1,      "GL_DECODE_EXT"),       # 0x8A49
-    #"glGet",  (X,     1,      "GL_SKIP_DECODE_EXT"),  # 0x8A4A
+    ("glGetTexParameter",      E,      1,      "GL_TEXTURE_SRGB_DECODE_EXT"),  # 0x8A48
+    ("",       X,      1,      "GL_DECODE_EXT"),       # 0x8A49
+    ("",       X,      1,      "GL_SKIP_DECODE_EXT"),  # 0x8A4A
     ("",       X,      1,      "GL_FRAGMENT_SHADER"),  # 0x8B30
     ("",       X,      1,      "GL_VERTEX_SHADER"),    # 0x8B31
     ("",       H,      1,      "GL_PROGRAM_OBJECT_ARB"),       # 0x8B40
@@ -2232,8 +2240,30 @@ parameters = [
     ("",       X,      1,      "GL_FRAGMENT_SHADER_DERIVATIVE_HINT"),  # 0x8B8B
     ("",       X,      1,      "GL_SHADING_LANGUAGE_VERSION"), # 0x8B8C
     ("glGet",  I,      1,      "GL_CURRENT_PROGRAM"),  # 0x8B8D
+    #("",      X,      1,      "GL_PALETTE4_RGB8_OES"),        # 0x8B90
+    #("",      X,      1,      "GL_PALETTE4_RGBA8_OES"),       # 0x8B91
+    #("",      X,      1,      "GL_PALETTE4_R5_G6_B5_OES"),    # 0x8B92
+    #("",      X,      1,      "GL_PALETTE4_RGBA4_OES"),       # 0x8B93
+    #("",      X,      1,      "GL_PALETTE4_RGB5_A1_OES"),     # 0x8B94
+    #("",      X,      1,      "GL_PALETTE8_RGB8_OES"),        # 0x8B95
+    #("",      X,      1,      "GL_PALETTE8_RGBA8_OES"),       # 0x8B96
+    #("",      X,      1,      "GL_PALETTE8_R5_G6_B5_OES"),    # 0x8B97
+    #("",      X,      1,      "GL_PALETTE8_RGBA4_OES"),       # 0x8B98
+    #("",      X,      1,      "GL_PALETTE8_RGB5_A1_OES"),     # 0x8B99
     ("",       X,      1,      "GL_IMPLEMENTATION_COLOR_READ_TYPE"),   # 0x8B9A
     ("",       X,      1,      "GL_IMPLEMENTATION_COLOR_READ_FORMAT"), # 0x8B9B
+    #("",      X,      1,      "GL_POINT_SIZE_ARRAY_OES"),     # 0x8B9C
+    #("",      X,      1,      "GL_TEXTURE_CROP_RECT_OES"),    # 0x8B9D
+    #("",      X,      1,      "GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES"),    # 0x8B9E
+    #("",      X,      1,      "GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES"),      # 0x8B9F
+    #("",      X,      1,      "GL_FRAGMENT_PROGRAM_POSITION_MESA"),   # 0x8BB0
+    #("",      X,      1,      "GL_FRAGMENT_PROGRAM_CALLBACK_MESA"),   # 0x8BB1
+    #("",      X,      1,      "GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA"),      # 0x8BB2
+    #("",      X,      1,      "GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA"),      # 0x8BB3
+    #("",      X,      1,      "GL_VERTEX_PROGRAM_CALLBACK_MESA"),     # 0x8BB4
+    #("",      X,      1,      "GL_VERTEX_PROGRAM_POSITION_MESA"),     # 0x8BB4
+    #("",      X,      1,      "GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA"),        # 0x8BB6
+    #("",      X,      1,      "GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA"),        # 0x8BB7
     ("",       X,      1,      "GL_COUNTER_TYPE_AMD"), # 0x8BC0
     ("",       X,      1,      "GL_COUNTER_RANGE_AMD"),        # 0x8BC1
     ("",       X,      1,      "GL_UNSIGNED_INT64_AMD"),       # 0x8BC2
@@ -2241,6 +2271,28 @@ parameters = [
     ("",       X,      1,      "GL_PERFMON_RESULT_AVAILABLE_AMD"),     # 0x8BC4
     ("",       X,      1,      "GL_PERFMON_RESULT_SIZE_AMD"),  # 0x8BC5
     ("",       X,      1,      "GL_PERFMON_RESULT_AMD"),       # 0x8BC6
+    #("",      X,      1,      "GL_TEXTURE_WIDTH_QCOM"),       # 0x8BD2
+    #("",      X,      1,      "GL_TEXTURE_HEIGHT_QCOM"),      # 0x8BD3
+    #("",      X,      1,      "GL_TEXTURE_DEPTH_QCOM"),       # 0x8BD4
+    #("",      X,      1,      "GL_TEXTURE_INTERNAL_FORMAT_QCOM"),     # 0x8BD5
+    #("",      X,      1,      "GL_TEXTURE_FORMAT_QCOM"),      # 0x8BD6
+    #("",      X,      1,      "GL_TEXTURE_TYPE_QCOM"),        # 0x8BD7
+    #("",      X,      1,      "GL_TEXTURE_IMAGE_VALID_QCOM"), # 0x8BD8
+    #("",      X,      1,      "GL_TEXTURE_NUM_LEVELS_QCOM"),  # 0x8BD9
+    #("",      X,      1,      "GL_TEXTURE_TARGET_QCOM"),      # 0x8BDA
+    #("",      X,      1,      "GL_TEXTURE_OBJECT_VALID_QCOM"),        # 0x8BDB
+    #("",      X,      1,      "GL_STATE_RESTORE"),    # 0x8BDC
+    #("",      X,      1,      "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"),  # 0x8C00
+    #("",      X,      1,      "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"),  # 0x8C01
+    #("",      X,      1,      "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"), # 0x8C02
+    #("",      X,      1,      "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"), # 0x8C03
+    #("",      X,      1,      "GL_MODULATE_COLOR_IMG"),       # 0x8C04
+    #("",      X,      1,      "GL_RECIP_ADD_SIGNED_ALPHA_IMG"),       # 0x8C05
+    #("",      X,      1,      "GL_TEXTURE_ALPHA_MODULATE_IMG"),       # 0x8C06
+    #("",      X,      1,      "GL_FACTOR_ALPHA_MODULATE_IMG"),        # 0x8C07
+    #("",      X,      1,      "GL_FRAGMENT_ALPHA_MODULATE_IMG"),      # 0x8C08
+    #("",      X,      1,      "GL_ADD_BLEND_IMG"),    # 0x8C09
+    #("",      X,      1,      "GL_SGX_BINARY_IMG"),   # 0x8C0A
     ("",       X,      1,      "GL_TEXTURE_RED_TYPE"), # 0x8C10
     ("",       X,      1,      "GL_TEXTURE_GREEN_TYPE"),       # 0x8C11
     ("",       X,      1,      "GL_TEXTURE_BLUE_TYPE"),        # 0x8C12
@@ -2253,8 +2305,8 @@ parameters = [
     ("",       X,      1,      "GL_PROXY_TEXTURE_1D_ARRAY"),   # 0x8C19
     ("",       X,      1,      "GL_TEXTURE_2D_ARRAY"), # 0x8C1A
     ("",       X,      1,      "GL_PROXY_TEXTURE_2D_ARRAY"),   # 0x8C1B
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_1D_ARRAY"), # 0x8C1C
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_2D_ARRAY"), # 0x8C1D
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_1D_ARRAY"), # 0x8C1C
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_2D_ARRAY"), # 0x8C1D
     ("",       X,      1,      "GL_GEOMETRY_PROGRAM_NV"),      # 0x8C26
     ("",       X,      1,      "GL_MAX_PROGRAM_OUTPUT_VERTICES_NV"),   # 0x8C27
     ("",       X,      1,      "GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV"),   # 0x8C28
@@ -2321,6 +2373,8 @@ parameters = [
     ("",       X,      1,      "GL_SEPARATE_ATTRIBS"), # 0x8C8D
     ("",       X,      1,      "GL_TRANSFORM_FEEDBACK_BUFFER"),        # 0x8C8E
     ("glGet",  I,      1,      "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING"),        # 0x8C8F
+    #("",      X,      1,      "GL_ATC_RGB_AMD"),      # 0x8C92
+    #("",      X,      1,      "GL_ATC_RGBA_EXPLICIT_ALPHA_AMD"),      # 0x8C93
     ("glGet",  E,      1,      "GL_POINT_SPRITE_COORD_ORIGIN"),        # 0x8CA0
     ("",       X,      1,      "GL_LOWER_LEFT"),       # 0x8CA1
     ("",       X,      1,      "GL_UPPER_LEFT"),       # 0x8CA2
@@ -2384,6 +2438,14 @@ parameters = [
     ("glGetRenderbufferParameter",     I,      1,      "GL_RENDERBUFFER_STENCIL_SIZE"),        # 0x8D55
     ("",       X,      1,      "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"),       # 0x8D56
     ("glGet",  I,      1,      "GL_MAX_SAMPLES"),      # 0x8D57
+    #("",      X,      1,      "GL_TEXTURE_GEN_STR_OES"),      # 0x8D60
+    #("",      X,      1,      "GL_HALF_FLOAT_OES"),   # 0x8D61
+    #("",      X,      1,      "GL_RGB565_OES"),       # 0x8D62
+    #("",      X,      1,      "GL_ETC1_RGB8_OES"),    # 0x8D64
+    #("",      X,      1,      "GL_TEXTURE_EXTERNAL_OES"),     # 0x8D65
+    #("",      X,      1,      "GL_SAMPLER_EXTERNAL_OES"),     # 0x8D66
+    #("",      X,      1,      "GL_TEXTURE_BINDING_EXTERNAL_OES"),     # 0x8D67
+    #("",      X,      1,      "GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES"), # 0x8D68
     ("",       X,      1,      "GL_RGBA32UI"), # 0x8D70
     ("",       X,      1,      "GL_RGB32UI"),  # 0x8D71
     ("",       X,      1,      "GL_ALPHA32UI_EXT"),    # 0x8D72
@@ -2595,6 +2657,14 @@ parameters = [
     ("",       X,      1,      "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"),     # 0x8E8D
     ("",       X,      1,      "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"),     # 0x8E8E
     ("",       X,      1,      "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"),   # 0x8E8F
+    #("",      X,      1,      "GL_COVERAGE_COMPONENT_NV"),    # 0x8ED0
+    #("",      X,      1,      "GL_COVERAGE_COMPONENT4_NV"),   # 0x8ED1
+    #("",      X,      1,      "GL_COVERAGE_ATTACHMENT_NV"),   # 0x8ED2
+    #("",      X,      1,      "GL_COVERAGE_BUFFERS_NV"),      # 0x8ED3
+    #("",      X,      1,      "GL_COVERAGE_SAMPLES_NV"),      # 0x8ED4
+    #("",      X,      1,      "GL_COVERAGE_ALL_FRAGMENTS_NV"),        # 0x8ED5
+    #("",      X,      1,      "GL_COVERAGE_EDGE_FRAGMENTS_NV"),       # 0x8ED6
+    #("",      X,      1,      "GL_COVERAGE_AUTOMATIC_NV"),    # 0x8ED7
     ("",       X,      1,      "GL_BUFFER_GPU_ADDRESS_NV"),    # 0x8F1D
     ("",       X,      1,      "GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV"),   # 0x8F1E
     ("",       X,      1,      "GL_ELEMENT_ARRAY_UNIFIED_NV"), # 0x8F1F
@@ -2622,13 +2692,13 @@ parameters = [
     ("",       X,      1,      "GL_MAX_SHADER_BUFFER_ADDRESS_NV"),     # 0x8F35
     ("",       X,      1,      "GL_COPY_READ_BUFFER"), # 0x8F36
     ("",       X,      1,      "GL_COPY_WRITE_BUFFER"),        # 0x8F37
-    ("",       X,      1,      "GL_MAX_IMAGE_UNITS_EXT"),      # 0x8F38
-    ("",       X,      1,      "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT"),        # 0x8F39
-    ("",       X,      1,      "GL_IMAGE_BINDING_NAME_EXT"),   # 0x8F3A
-    ("",       X,      1,      "GL_IMAGE_BINDING_LEVEL_EXT"),  # 0x8F3B
-    ("",       X,      1,      "GL_IMAGE_BINDING_LAYERED_EXT"),        # 0x8F3C
-    ("",       X,      1,      "GL_IMAGE_BINDING_LAYER_EXT"),  # 0x8F3D
-    ("",       X,      1,      "GL_IMAGE_BINDING_ACCESS_EXT"), # 0x8F3E
+    ("",       X,      1,      "GL_MAX_IMAGE_UNITS"),  # 0x8F38
+    ("",       X,      1,      "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS"),    # 0x8F39
+    ("",       X,      1,      "GL_IMAGE_BINDING_NAME"),       # 0x8F3A
+    ("",       X,      1,      "GL_IMAGE_BINDING_LEVEL"),      # 0x8F3B
+    ("",       X,      1,      "GL_IMAGE_BINDING_LAYERED"),    # 0x8F3C
+    ("",       X,      1,      "GL_IMAGE_BINDING_LAYER"),      # 0x8F3D
+    ("",       X,      1,      "GL_IMAGE_BINDING_ACCESS"),     # 0x8F3E
     ("",       X,      1,      "GL_DRAW_INDIRECT_BUFFER"),     # 0x8F3F
     ("",       X,      1,      "GL_DRAW_INDIRECT_UNIFIED_NV"), # 0x8F40
     ("",       X,      1,      "GL_DRAW_INDIRECT_ADDRESS_NV"), # 0x8F41
@@ -2645,6 +2715,7 @@ parameters = [
     ("",       X,      1,      "GL_DOUBLE_MAT3x4"),    # 0x8F4C
     ("",       X,      1,      "GL_DOUBLE_MAT4x2"),    # 0x8F4D
     ("",       X,      1,      "GL_DOUBLE_MAT4x3"),    # 0x8F4E
+    #("",      X,      1,      "GL_MALI_SHADER_BINARY_ARM"),   # 0x8F60
     ("",       X,      1,      "GL_RED_SNORM"),        # 0x8F90
     ("",       X,      1,      "GL_RG_SNORM"), # 0x8F91
     ("",       X,      1,      "GL_RGB_SNORM"),        # 0x8F92
@@ -2660,6 +2731,9 @@ parameters = [
     ("",       X,      1,      "GL_SIGNED_NORMALIZED"),        # 0x8F9C
     ("glGet",  B,      1,      "GL_PRIMITIVE_RESTART"),        # 0x8F9D
     ("glGet",  I,      1,      "GL_PRIMITIVE_RESTART_INDEX"),  # 0x8F9E
+    #("",      X,      1,      "GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS"),    # 0x8F9F
+    #("",      X,      1,      "GL_PERFMON_GLOBAL_MODE_QCOM"), # 0x8FA0
+    #("",      X,      1,      "GL_SHADER_BINARY_VIV"),        # 0x8FC4
     ("",       X,      1,      "GL_INT8_NV"),  # 0x8FE0
     ("",       X,      1,      "GL_INT8_VEC2_NV"),     # 0x8FE1
     ("",       X,      1,      "GL_INT8_VEC3_NV"),     # 0x8FE2
@@ -2697,7 +2771,7 @@ parameters = [
     ("",       X,      1,      "GL_DISCRETE_AMD"),     # 0x9006
     ("",       X,      1,      "GL_CONTINUOUS_AMD"),   # 0x9007
     ("",       X,      1,      "GL_TEXTURE_CUBE_MAP_ARRAY"),   # 0x9009
-    ("glGet",  I,      1,      "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY"),   # 0x900A
+    ("_glGet", I,      1,      "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY"),   # 0x900A
     ("",       X,      1,      "GL_PROXY_TEXTURE_CUBE_MAP_ARRAY"),     # 0x900B
     ("",       X,      1,      "GL_SAMPLER_CUBE_MAP_ARRAY"),   # 0x900C
     ("",       X,      1,      "GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW"),    # 0x900D
@@ -2715,6 +2789,8 @@ parameters = [
     ("",       X,      1,      "GL_LUMINANCE16_SNORM"),        # 0x9019
     ("",       X,      1,      "GL_LUMINANCE16_ALPHA16_SNORM"),        # 0x901A
     ("",       X,      1,      "GL_INTENSITY16_SNORM"),        # 0x901B
+    ("",       X,      1,      "GL_FACTOR_MIN_AMD"),   # 0x901C
+    ("",       X,      1,      "GL_FACTOR_MAX_AMD"),   # 0x901D
     ("",       B,      1,      "GL_DEPTH_CLAMP_NEAR_AMD"),     # 0x901E
     ("",       B,      1,      "GL_DEPTH_CLAMP_FAR_AMD"),      # 0x901F
     ("",       X,      1,      "GL_VIDEO_BUFFER_NV"),  # 0x9020
@@ -2746,42 +2822,57 @@ parameters = [
     ("",       X,      1,      "GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV"),      # 0x903A
     ("",       X,      1,      "GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV"),      # 0x903B
     ("",       X,      1,      "GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV"),  # 0x903C
-    ("",       X,      1,      "GL_IMAGE_1D_EXT"),     # 0x904C
-    ("",       X,      1,      "GL_IMAGE_2D_EXT"),     # 0x904D
-    ("",       X,      1,      "GL_IMAGE_3D_EXT"),     # 0x904E
-    ("",       X,      1,      "GL_IMAGE_2D_RECT_EXT"),        # 0x904F
-    ("",       X,      1,      "GL_IMAGE_CUBE_EXT"),   # 0x9050
-    ("",       X,      1,      "GL_IMAGE_BUFFER_EXT"), # 0x9051
-    ("",       X,      1,      "GL_IMAGE_1D_ARRAY_EXT"),       # 0x9052
-    ("",       X,      1,      "GL_IMAGE_2D_ARRAY_EXT"),       # 0x9053
-    ("",       X,      1,      "GL_IMAGE_CUBE_MAP_ARRAY_EXT"), # 0x9054
-    ("",       X,      1,      "GL_IMAGE_2D_MULTISAMPLE_EXT"), # 0x9055
-    ("",       X,      1,      "GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"),   # 0x9056
-    ("",       X,      1,      "GL_INT_IMAGE_1D_EXT"), # 0x9057
-    ("",       X,      1,      "GL_INT_IMAGE_2D_EXT"), # 0x9058
-    ("",       X,      1,      "GL_INT_IMAGE_3D_EXT"), # 0x9059
-    ("",       X,      1,      "GL_INT_IMAGE_2D_RECT_EXT"),    # 0x905A
-    ("",       X,      1,      "GL_INT_IMAGE_CUBE_EXT"),       # 0x905B
-    ("",       X,      1,      "GL_INT_IMAGE_BUFFER_EXT"),     # 0x905C
-    ("",       X,      1,      "GL_INT_IMAGE_1D_ARRAY_EXT"),   # 0x905D
-    ("",       X,      1,      "GL_INT_IMAGE_2D_ARRAY_EXT"),   # 0x905E
-    ("",       X,      1,      "GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT"),     # 0x905F
-    ("",       X,      1,      "GL_INT_IMAGE_2D_MULTISAMPLE_EXT"),     # 0x9060
-    ("",       X,      1,      "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"),       # 0x9061
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_1D_EXT"),        # 0x9062
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_EXT"),        # 0x9063
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_3D_EXT"),        # 0x9064
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT"),   # 0x9065
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_CUBE_EXT"),      # 0x9066
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_BUFFER_EXT"),    # 0x9067
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT"),  # 0x9068
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT"),  # 0x9069
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT"),    # 0x906A
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT"),    # 0x906B
-    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"),      # 0x906C
-    ("",       X,      1,      "GL_MAX_IMAGE_SAMPLES_EXT"),    # 0x906D
-    ("",       X,      1,      "GL_IMAGE_BINDING_FORMAT_EXT"), # 0x906E
+    ("",       X,      1,      "GL_TEXTURE_COVERAGE_SAMPLES_NV"),      # 0x9045
+    ("",       X,      1,      "GL_TEXTURE_COLOR_SAMPLES_NV"), # 0x9046
+    ("",       X,      1,      "GL_IMAGE_1D"), # 0x904C
+    ("",       X,      1,      "GL_IMAGE_2D"), # 0x904D
+    ("",       X,      1,      "GL_IMAGE_3D"), # 0x904E
+    ("",       X,      1,      "GL_IMAGE_2D_RECT"),    # 0x904F
+    ("",       X,      1,      "GL_IMAGE_CUBE"),       # 0x9050
+    ("",       X,      1,      "GL_IMAGE_BUFFER"),     # 0x9051
+    ("",       X,      1,      "GL_IMAGE_1D_ARRAY"),   # 0x9052
+    ("",       X,      1,      "GL_IMAGE_2D_ARRAY"),   # 0x9053
+    ("",       X,      1,      "GL_IMAGE_CUBE_MAP_ARRAY"),     # 0x9054
+    ("",       X,      1,      "GL_IMAGE_2D_MULTISAMPLE"),     # 0x9055
+    ("",       X,      1,      "GL_IMAGE_2D_MULTISAMPLE_ARRAY"),       # 0x9056
+    ("",       X,      1,      "GL_INT_IMAGE_1D"),     # 0x9057
+    ("",       X,      1,      "GL_INT_IMAGE_2D"),     # 0x9058
+    ("",       X,      1,      "GL_INT_IMAGE_3D"),     # 0x9059
+    ("",       X,      1,      "GL_INT_IMAGE_2D_RECT"),        # 0x905A
+    ("",       X,      1,      "GL_INT_IMAGE_CUBE"),   # 0x905B
+    ("",       X,      1,      "GL_INT_IMAGE_BUFFER"), # 0x905C
+    ("",       X,      1,      "GL_INT_IMAGE_1D_ARRAY"),       # 0x905D
+    ("",       X,      1,      "GL_INT_IMAGE_2D_ARRAY"),       # 0x905E
+    ("",       X,      1,      "GL_INT_IMAGE_CUBE_MAP_ARRAY"), # 0x905F
+    ("",       X,      1,      "GL_INT_IMAGE_2D_MULTISAMPLE"), # 0x9060
+    ("",       X,      1,      "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY"),   # 0x9061
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_1D"),    # 0x9062
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D"),    # 0x9063
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_3D"),    # 0x9064
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_RECT"),       # 0x9065
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_CUBE"),  # 0x9066
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_BUFFER"),        # 0x9067
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_1D_ARRAY"),      # 0x9068
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_ARRAY"),      # 0x9069
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY"),        # 0x906A
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE"),        # 0x906B
+    ("",       X,      1,      "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY"),  # 0x906C
+    ("",       X,      1,      "GL_MAX_IMAGE_SAMPLES"),        # 0x906D
+    ("",       X,      1,      "GL_IMAGE_BINDING_FORMAT"),     # 0x906E
     ("",       X,      1,      "GL_RGB10_A2UI"),       # 0x906F
+    ("",       X,      1,      "GL_SCALED_RESOLVE_FASTEST_EXT"),       # 0x90BA
+    ("",       X,      1,      "GL_SCALED_RESOLVE_NICEST_EXT"),        # 0x90BB
+    ("",       X,      1,      "GL_MIN_MAP_BUFFER_ALIGNMENT"), # 0x90BC
+    ("",       X,      1,      "GL_IMAGE_FORMAT_COMPATIBILITY_TYPE"),  # 0x90C7
+    ("",       X,      1,      "GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE"),       # 0x90C8
+    ("",       X,      1,      "GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS"),      # 0x90C9
+    ("",       X,      1,      "GL_MAX_VERTEX_IMAGE_UNIFORMS"),        # 0x90CA
+    ("",       X,      1,      "GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS"),  # 0x90CB
+    ("",       X,      1,      "GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS"),       # 0x90CC
+    ("",       X,      1,      "GL_MAX_GEOMETRY_IMAGE_UNIFORMS"),      # 0x90CD
+    ("",       X,      1,      "GL_MAX_FRAGMENT_IMAGE_UNIFORMS"),      # 0x90CE
+    ("",       X,      1,      "GL_MAX_COMBINED_IMAGE_UNIFORMS"),      # 0x90CF
+    ("",       X,      1,      "GL_SYNC_X11_FENCE_EXT"),       # 0x90E1
     ("",       X,      1,      "GL_TEXTURE_2D_MULTISAMPLE"),   # 0x9100
     ("",       X,      1,      "GL_PROXY_TEXTURE_2D_MULTISAMPLE"),     # 0x9101
     ("",       X,      1,      "GL_TEXTURE_2D_MULTISAMPLE_ARRAY"),     # 0x9102
@@ -2820,6 +2911,20 @@ parameters = [
     ("",       X,      1,      "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS"),   # 0x9124
     ("",       X,      1,      "GL_MAX_FRAGMENT_INPUT_COMPONENTS"),    # 0x9125
     ("glGet",  I,      1,      "GL_CONTEXT_PROFILE_MASK"),     # 0x9126
+    ("",       X,      1,      "GL_UNPACK_COMPRESSED_BLOCK_WIDTH"),    # 0x9127
+    ("",       X,      1,      "GL_UNPACK_COMPRESSED_BLOCK_HEIGHT"),   # 0x9128
+    ("",       X,      1,      "GL_UNPACK_COMPRESSED_BLOCK_DEPTH"),    # 0x9129
+    ("",       X,      1,      "GL_UNPACK_COMPRESSED_BLOCK_SIZE"),     # 0x912A
+    ("",       X,      1,      "GL_PACK_COMPRESSED_BLOCK_WIDTH"),      # 0x912B
+    ("",       X,      1,      "GL_PACK_COMPRESSED_BLOCK_HEIGHT"),     # 0x912C
+    ("",       X,      1,      "GL_PACK_COMPRESSED_BLOCK_DEPTH"),      # 0x912D
+    ("",       X,      1,      "GL_PACK_COMPRESSED_BLOCK_SIZE"),       # 0x912E
+    ("",       X,      1,      "GL_TEXTURE_IMMUTABLE_FORMAT"), # 0x912F
+    #("",      X,      1,      "GL_SGX_PROGRAM_BINARY_IMG"),   # 0x9130
+    #("",      X,      1,      "GL_RENDERBUFFER_SAMPLES_IMG"), # 0x9133
+    #("",      X,      1,      "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG"),   # 0x9134
+    #("",      X,      1,      "GL_MAX_SAMPLES_IMG"),  # 0x9135
+    #("",      X,      1,      "GL_TEXTURE_SAMPLES_IMG"),      # 0x9136
     ("",       X,      1,      "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB"),     # 0x9143
     ("",       X,      1,      "GL_MAX_DEBUG_LOGGED_MESSAGES_ARB"),    # 0x9144
     ("",       X,      1,      "GL_DEBUG_LOGGED_MESSAGES_ARB"),        # 0x9145
@@ -2839,6 +2944,37 @@ parameters = [
     ("",       X,      1,      "GL_QUERY_OBJECT_AMD"), # 0x9153
     ("",       X,      1,      "GL_VERTEX_ARRAY_OBJECT_AMD"),  # 0x9154
     ("",       X,      1,      "GL_SAMPLER_OBJECT_AMD"),       # 0x9155
+    #("",      X,      1,      "GL_SHADER_BINARY_DMP"),        # 0x9250
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER"),    # 0x92C0
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_BINDING"),    # 0x92C1
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_START"),      # 0x92C2
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_SIZE"),       # 0x92C3
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE"),  # 0x92C4
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS"),     # 0x92C5
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES"),      # 0x92C6
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER"),        # 0x92C7
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER"),  # 0x92C8
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER"),       # 0x92C9
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER"),      # 0x92CA
+    ("",       X,      1,      "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER"),      # 0x92CB
+    ("",       X,      1,      "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS"),        # 0x92CC
+    ("",       X,      1,      "GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS"),  # 0x92CD
+    ("",       X,      1,      "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS"),       # 0x92CE
+    ("",       X,      1,      "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS"),      # 0x92CF
+    ("",       X,      1,      "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS"),      # 0x92D0
+    ("",       X,      1,      "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS"),      # 0x92D1
+    ("",       X,      1,      "GL_MAX_VERTEX_ATOMIC_COUNTERS"),       # 0x92D2
+    ("",       X,      1,      "GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS"), # 0x92D3
+    ("",       X,      1,      "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS"),      # 0x92D4
+    ("",       X,      1,      "GL_MAX_GEOMETRY_ATOMIC_COUNTERS"),     # 0x92D5
+    ("",       X,      1,      "GL_MAX_FRAGMENT_ATOMIC_COUNTERS"),     # 0x92D6
+    ("",       X,      1,      "GL_MAX_COMBINED_ATOMIC_COUNTERS"),     # 0x92D7
+    ("",       X,      1,      "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE"),   # 0x92D8
+    ("",       X,      1,      "GL_ACTIVE_ATOMIC_COUNTER_BUFFERS"),    # 0x92D9
+    ("",       X,      1,      "GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX"),      # 0x92DA
+    ("",       X,      1,      "GL_UNSIGNED_INT_ATOMIC_COUNTER"),      # 0x92DB
+    ("",       X,      1,      "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS"),       # 0x92DC
+    ("",       X,      1,      "GL_NUM_SAMPLE_COUNTS"),        # 0x9380
     ("",       X,      1,      "GL_INVALID_INDEX"),    # 0xFFFFFFFFu
 ]
 
index 255dd6f52d10c8c4a37677efeaa30315928239ed..5b93f2d82b026893f1551ab200cf13563a731b7a 100644 (file)
@@ -69,6 +69,7 @@ void retrace_call_wgl(Trace::Call &call);
 void snapshot(unsigned call_no);
 void frame_complete(unsigned call_no);
 
+void updateDrawable(int width, int height);
 
 } /* namespace glretrace */
 
index 6a5103e0db2523894d8ff60f7632191af4cc3f19..356659abbea11c4c6f365e293c2f807126a13151 100644 (file)
@@ -99,6 +99,11 @@ class GlRetracer(Retracer):
         "glMultiModeDrawElementsIBM",
     ])
 
+    draw_indirect_function_names = set([
+        "glDrawArraysIndirect",
+        "glDrawElementsIndirect",
+    ])
+
     misc_draw_function_names = set([
         "glClear",
         "glEnd",
@@ -170,6 +175,12 @@ class GlRetracer(Retracer):
             print '    GLint __pack_buffer = 0;'
             print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
             print '    if (!__pack_buffer) {'
+            if function.name == 'glReadPixels':
+                print '    glFinish();'
+                print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
+                print '        glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
+                print '        glretrace::snapshot(call.no);'
+                print '    }'
             print '        return;'
             print '    }'
 
@@ -178,6 +189,9 @@ class GlRetracer(Retracer):
             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
             print '        glretrace::snapshot(call.no - 1);'
             print '    }'
+        if function.name == 'glFrameTerminatorGREMEDY':
+            print '    glretrace::frame_complete(call.no);'
+            return
 
         Retracer.retrace_function_body(self, function)
 
@@ -186,12 +200,6 @@ class GlRetracer(Retracer):
             print '    if (!glretrace::double_buffer) {'
             print '        glretrace::frame_complete(call.no);'
             print '    }'
-        if function.name == 'glReadPixels':
-            print '    glFinish();'
-            print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
-            print '        glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
-            print '        glretrace::snapshot(call.no);'
-            print '    }'
         if is_draw_array or is_draw_elements or is_misc_draw:
             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_DRAW) {'
             print '        glretrace::snapshot(call.no);'
@@ -199,23 +207,13 @@ class GlRetracer(Retracer):
 
 
     def call_function(self, function):
+        # Infer the drawable size from GL calls
         if function.name == "glViewport":
-            print '    GLint draw_framebuffer = 0;'
-            print '    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);'
-            print '    if (draw_framebuffer == 0) {'
-            print '        if (glretrace::drawable) {'
-            print '            int drawable_width  = x + width;'
-            print '            int drawable_height = y + height;'
-            print '            if (drawable_width  > (int)glretrace::drawable->width ||'
-            print '                drawable_height > (int)glretrace::drawable->height) {'
-            print '                glretrace::drawable->resize(drawable_width, drawable_height);'
-            print '                if (!glretrace::drawable->visible) {'
-            print '                    glretrace::drawable->show();'
-            print '                }'
-            print '                glScissor(0, 0, drawable_width, drawable_height);'
-            print '            }'
-            print '        }'
-            print '    }'
+            print '    glretrace::updateDrawable(x + width, y + height);'
+        if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
+            # Some applications do all their rendering in a framebuffer, and
+            # then just blit to the drawable without ever calling glViewport.
+            print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
 
         if function.name == "glEnd":
             print '    glretrace::insideGlBeginEnd = false;'
@@ -290,13 +288,13 @@ class GlRetracer(Retracer):
             if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
                 print r'    GLint __orig_result = call.ret->toSInt();'
                 print r'    if (__result != __orig_result) {'
-                print r'        std::cerr << call.no << ": warning vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
+                print r'        std::cerr << call.no << ": warning: vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
                 print r'    }'
             if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
                 print r'    GLint __orig_result = call.ret->toSInt();'
                 print r'    if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
                 print r'        __result != GL_FRAMEBUFFER_COMPLETE) {'
-                print r'        std::cerr << call.no << ": incomplete framebuffer (" << __result << ")\n";'
+                print r'        std::cerr << call.no << ": warning: incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
                 print r'    }'
             print '    }'
 
@@ -305,7 +303,8 @@ class GlRetracer(Retracer):
             print '    %s = static_cast<%s>(%s.toPointer(true));' % (lvalue, arg_type, rvalue)
             return
 
-        if function.name in self.draw_elements_function_names and arg.name == 'indices':
+        if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
+           function.name in self.draw_indirect_function_names and arg.name == 'indirect':
             self.extract_opaque_arg(function, arg, arg_type, lvalue, rvalue)
             return
 
@@ -342,6 +341,7 @@ if __name__ == '__main__':
 
 #include "glproc.hpp"
 #include "glretrace.hpp"
+#include "glstate.hpp"
 
 
 '''
index 56ee763210b4e3848f4b359549cb9e72c8f42580..cd35889c9dff873303dd27d26274829d296e664d 100644 (file)
@@ -103,6 +103,37 @@ checkGlError(Trace::Call &call) {
     std::cerr << "\n";
 }
 
+/**
+ * Grow the current drawble.
+ *
+ * We need to infer the drawable size from GL calls because the drawable sizes
+ * are specified by OS specific calls which we do not trace.
+ */
+void
+updateDrawable(int width, int height) {
+    if (!drawable) {
+        return;
+    }
+
+    if (width  <= glretrace::drawable->width &&
+        height <= glretrace::drawable->height) {
+        return;
+    }
+
+    // Check for bound framebuffer last, as this may have a performance impact.
+    GLint draw_framebuffer = 0;
+    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
+    if (draw_framebuffer != 0) {
+        return;
+    }
+
+    glretrace::drawable->resize(width, height);
+    if (!drawable->visible) {
+        drawable->show();
+    }
+    glScissor(0, 0, width, height);
+}
+
 
 void snapshot(unsigned call_no) {
     if (!drawable ||
@@ -131,7 +162,9 @@ void snapshot(unsigned call_no) {
 
     if (snapshot_prefix) {
         if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
-            src->writePNM(std::cout);
+            char comment[21];
+            snprintf(comment, sizeof comment, "%u", call_no);
+            src->writePNM(std::cout, comment);
         } else {
             char filename[PATH_MAX];
             snprintf(filename, sizeof filename, "%s%010u.png", snapshot_prefix, call_no);
index a58b41e9a22f8703a585c5c118c844d48fdd660e..257d59913e46d0b5f4b7c8cd9e69eec3792f7594 100644 (file)
@@ -610,14 +610,18 @@ __gl_format_channels(GLenum format) {
     case GL_DEPTH_STENCIL:
     case GL_LUMINANCE_ALPHA:
     case GL_RG:
+    case GL_HILO_NV:
+    case GL_DSDT_NV:
         return 2;
     case GL_RGB:
     case GL_BGR:
+    case GL_DSDT_MAG_NV:
         return 3;
     case GL_RGBA:
     case GL_BGRA:
     case GL_ABGR_EXT:
     case GL_CMYK_EXT:
+    case GL_DSDT_MAG_VIB_NV:
         return 4;
     case GL_CMYKA_EXT:
         return 5;
index aaf4d4bd6b6b5b15c4a67c9c3f51947b1a5b0d91..ac63a78b84bbc8629acf12490db4b83956634d75 100644 (file)
@@ -591,7 +591,7 @@ dumpTextureImage(JSONWriter &json, GLenum target, GLint level)
         json.beginMember("__data__");
         char *pngBuffer;
         int pngBufferSize;
-        Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
+        Image::writePixelsToBuffer(pixels, width, height, 4, true, &pngBuffer, &pngBufferSize);
         json.writeBase64(pngBuffer, pngBufferSize);
         free(pngBuffer);
         json.endMember(); // __data__
@@ -949,7 +949,7 @@ dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format)
     json.beginMember("__data__");
     char *pngBuffer;
     int pngBufferSize;
-    Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
+    Image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize);
     //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
     //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
     json.writeBase64(pngBuffer, pngBufferSize);
index fb3e090bff8d094f66ce0ee4ea78ecfc9918d014..c348d2b99b69dd2273ca30067f6a5c1fe237f7c6 100644 (file)
@@ -380,13 +380,18 @@ class StateDumper:
         print '            json.beginMember(name);'
         print '            glActiveTexture(GL_TEXTURE0 + unit);'
         print '            json.beginObject();'
-        print '            GLint texture;'
+        print '            GLboolean enabled;'
+        print '            GLint binding;'
         print
         for target, binding in texture_targets:
             print '            // %s' % target
-            print '            texture = 0;'
-            print '            glGetIntegerv(%s, &texture);' % binding
-            print '            if (glIsEnabled(%s) || texture) {' % target
+            print '            enabled = GL_FALSE;'
+            print '            glGetBooleanv(%s, &enabled);' % target
+            print '            json.writeBoolMember("%s", enabled);' % target
+            print '            binding = 0;'
+            print '            glGetIntegerv(%s, &binding);' % binding
+            print '            json.writeNumberMember("%s", binding);' % binding
+            print '            if (enabled || binding) {'
             print '                json.beginMember("%s");' % target
             print '                json.beginObject();'
             self.dump_atoms(glGetTexParameter, target)
index 32a6ca890612431543032d140ff4d3169a6298b8..e25cd7e686b3352732594bd45fe65b2a2d4c49e8 100644 (file)
@@ -82,6 +82,7 @@ GLregion = Handle("region", GLuint)
 GLmap = Handle("map", OpaquePointer(GLvoid))
 GLpipeline = Handle("pipeline", GLuint)
 GLsampler = Handle("sampler", GLuint)
+GLfeedback = Handle("feedback", GLuint)
 
 GLsync_ = Opaque("GLsync")
 GLsync = Handle("sync", GLsync_)
@@ -182,3 +183,21 @@ GLbitfield_access = Flags(GLbitfield, [
 GLbitfield_sync_flush = Flags(GLbitfield, [
     "GL_SYNC_FLUSH_COMMANDS_BIT",                              # 0x00000001
 ])
+
+GLbitfield_barrier = Flags(GLbitfield, [
+    "GL_ALL_BARRIER_BITS",                      # 0xFFFFFFFF
+    "GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT",       # 0x00000001
+    "GL_ELEMENT_ARRAY_BARRIER_BIT",             # 0x00000002
+    "GL_UNIFORM_BARRIER_BIT",                   # 0x00000004
+    "GL_TEXTURE_FETCH_BARRIER_BIT",             # 0x00000008
+    "GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV",   # 0x00000010
+    "GL_SHADER_IMAGE_ACCESS_BARRIER_BIT",       # 0x00000020
+    "GL_COMMAND_BARRIER_BIT",                   # 0x00000040
+    "GL_PIXEL_BUFFER_BARRIER_BIT",              # 0x00000080
+    "GL_TEXTURE_UPDATE_BARRIER_BIT",            # 0x00000100
+    "GL_BUFFER_UPDATE_BARRIER_BIT",             # 0x00000200
+    "GL_FRAMEBUFFER_BARRIER_BIT",               # 0x00000400
+    "GL_TRANSFORM_FEEDBACK_BARRIER_BIT",        # 0x00000800
+    "GL_ATOMIC_COUNTER_BARRIER_BIT",            # 0x00001000
+])
+
index 7c389b6380e1352641728e476ffd6dfbc6b22b1b..4a35ce1ca776a93bb4145b51cc886ec643d66e8d 100644 (file)
--- a/glxapi.py
+++ b/glxapi.py
@@ -433,6 +433,10 @@ glxapi.add_functions([
     # GLX_NV_copy_image
     Function(Void, "glXCopyImageSubDataNV", [(Display, "dpy"), (GLXContext, "srcCtx"), (GLuint, "srcName"), (GLenum, "srcTarget"), (GLint, "srcLevel"), (GLint, "srcX"), (GLint, "srcY"), (GLint, "srcZ"), (GLXContext, "dstCtx"), (GLuint, "dstName"), (GLenum, "dstTarget"), (GLint, "dstLevel"), (GLint, "dstX"), (GLint, "dstY"), (GLint, "dstZ"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
 
+    # GLX_NV_vertex_array_range
+    Function(OpaquePointer(Void), "glXAllocateMemoryNV", [(GLsizei, "size"), (GLfloat, "readfreq"), (GLfloat, "writefreq"), (GLfloat, "priority")]),
+    Function(Void, "glXFreeMemoryNV", [(OpaquePointer(Void), "pointer")]),
+
     # Must be last
     Function(PROC, "glXGetProcAddressARB", [(Alias("const GLubyte *", CString), "procName")]),
     Function(PROC, "glXGetProcAddress", [(Alias("const GLubyte *", CString), "procName")]),
index 6973450a9e5c16a1688ae24c233f8623d319af00..777bc9255c7c1d4c83207ec7ac12e826657e1700 100644 (file)
@@ -12,7 +12,6 @@ set(qapitrace_SRCS
    glsledit.cpp
    imageviewer.cpp
    jumpwidget.cpp
-   loaderthread.cpp
    mainwindow.cpp
    main.cpp
    retracer.cpp
@@ -21,6 +20,7 @@ set(qapitrace_SRCS
    settingsdialog.cpp
    shaderssourcewidget.cpp
    tracedialog.cpp
+   traceloader.cpp
    traceprocess.cpp
    vertexdatainterpreter.cpp
  )
index dc9dc94a45248a50caf0a9941085a20d6367418a..11ed3a5ca03d5c59c96b8c7bc05c67e2e5583bf8 100644 (file)
@@ -33,7 +33,7 @@ void ApiCallDelegate::paint(QPainter *painter,
         //QStyledItemDelegate::paint(painter, option, index);
         QStyle *style = QApplication::style();
         style->drawControl(QStyle::CE_ItemViewItem, &option, painter, 0);
-        if (!event->state().isEmpty()) {
+        if (event->hasState()) {
             QPixmap px = m_stateEmblem.pixmap(option.rect.height(),
                                               option.rect.height());
             painter->drawPixmap(option.rect.topLeft(), px);
index 64aa1532bc7083a89de2ea130489c3f7b146d8bb..050c081756bf4ef7e1f9079802c0790b7589fe35 100644 (file)
@@ -31,7 +31,6 @@ void ApiSurface::contentsFromBase64(const QByteArray &base64)
 {
     QByteArray dataArray = QByteArray::fromBase64(base64);
     m_image.loadFromData(dataArray, "png");
-    m_image = m_image.mirrored();
     m_thumb = m_image.scaled(64, 64, Qt::KeepAspectRatio);
 }
 
index f3b95dc13c58e979e05b59da1998318da0dec5f9..bc862097099c75c0d48ce1a093ba3aff70711866 100644 (file)
@@ -1,32 +1,75 @@
 #include "apitrace.h"
 
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "saverthread.h"
 
+#include <QDebug>
 #include <QDir>
+#include <QThread>
 
 ApiTrace::ApiTrace()
     : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
       m_needsSaving(false)
 {
-    m_loader = new LoaderThread(this);
-    connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
+    m_loader = new TraceLoader();
+
+    connect(this, SIGNAL(loadTrace(QString)),
+            m_loader, SLOT(loadTrace(QString)));
+    connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
+            m_loader, SLOT(loadFrame(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
-    connect(m_loader, SIGNAL(started()),
+    connect(m_loader,
+            SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
+            this,
+            SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
+    connect(m_loader, SIGNAL(finishedParsing()),
+            this, SLOT(finishedParsing()));
+    connect(this, SIGNAL(loaderSearchNext(int,QString,Qt::CaseSensitivity)),
+            m_loader, SLOT(searchNext(int,QString,Qt::CaseSensitivity)));
+    connect(this, SIGNAL(loaderSearchPrev(int,QString,Qt::CaseSensitivity)),
+            m_loader, SLOT(searchPrev(int,QString,Qt::CaseSensitivity)));
+    connect(m_loader,
+            SIGNAL(searchResult(ApiTrace::SearchResult,ApiTraceCall*)),
+            this,
+            SLOT(loaderSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
+    connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
+            m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
+    connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
+            m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
+            this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
+    connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
+            this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
+    connect(this, SIGNAL(loaderFindCallIndex(int)),
+            m_loader, SLOT(findCallIndex(int)));
+    connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
+            this, SIGNAL(foundCallIndex(ApiTraceCall*)));
+
+
+    connect(m_loader, SIGNAL(startedParsing()),
             this, SIGNAL(startedLoadingTrace()));
-    connect(m_loader, SIGNAL(finished()),
+    connect(m_loader, SIGNAL(parsed(int)),
+            this, SIGNAL(loaded(int)));
+    connect(m_loader, SIGNAL(finishedParsing()),
             this, SIGNAL(finishedLoadingTrace()));
 
+
     m_saver = new SaverThread(this);
     connect(m_saver, SIGNAL(traceSaved()),
             this, SLOT(slotSaved()));
     connect(m_saver, SIGNAL(traceSaved()),
             this, SIGNAL(saved()));
+
+    m_loaderThread = new QThread();
+    m_loader->moveToThread(m_loaderThread);
+    m_loaderThread->start();
 }
 
 ApiTrace::~ApiTrace()
 {
-    qDeleteAll(m_calls);
+    m_loaderThread->quit();
+    m_loaderThread->deleteLater();
     qDeleteAll(m_frames);
     delete m_loader;
     delete m_saver;
@@ -35,8 +78,9 @@ ApiTrace::~ApiTrace()
 bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
                                   ApiTrace::FrameMarker marker)
 {
-    if (!call)
+    if (!call) {
         return false;
+    }
 
     switch (marker) {
     case FrameMarker_SwapBuffers:
@@ -58,13 +102,14 @@ bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
 
 bool ApiTrace::isEmpty() const
 {
-    return m_calls.isEmpty();
+    return m_frames.isEmpty();
 }
 
 QString ApiTrace::fileName() const
 {
-    if (edited())
+    if (edited()) {
         return m_tempFileName;
+    }
 
     return m_fileName;
 }
@@ -74,21 +119,6 @@ ApiTrace::FrameMarker ApiTrace::frameMarker() const
     return m_frameMarker;
 }
 
-QList<ApiTraceCall*> ApiTrace::calls() const
-{
-    return m_calls;
-}
-
-ApiTraceCall * ApiTrace::callAt(int idx) const
-{
-    return m_calls.value(idx);
-}
-
-int ApiTrace::numCalls() const
-{
-    return m_calls.count();
-}
-
 QList<ApiTraceFrame*> ApiTrace::frames() const
 {
     return m_frames;
@@ -107,10 +137,11 @@ int ApiTrace::numFrames() const
 int ApiTrace::numCallsInFrame(int idx) const
 {
     const ApiTraceFrame *frame = frameAt(idx);
-    if (frame)
+    if (frame) {
         return frame->numChildren();
-    else
+    } else {
         return 0;
+    }
 }
 
 void ApiTrace::setFileName(const QString &name)
@@ -118,35 +149,18 @@ void ApiTrace::setFileName(const QString &name)
     if (m_fileName != name) {
         m_fileName = name;
 
-        if (m_loader->isRunning()) {
-            m_loader->terminate();
-            m_loader->wait();
-        }
         m_frames.clear();
-        m_calls.clear();
         m_errors.clear();
         m_editedCalls.clear();
         m_needsSaving = false;
         emit invalidated();
 
-        m_loader->loadFile(m_fileName);
-    }
-}
-
-void ApiTrace::setFrameMarker(FrameMarker marker)
-{
-    if (m_frameMarker != marker) {
-        emit framesInvalidated();
-
-        qDeleteAll(m_frames);
-        m_frames.clear();
-        detectFrames();
+        emit loadTrace(m_fileName);
     }
 }
 
 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
 {
-    QList<ApiTraceCall*> calls;
     int currentFrames = m_frames.count();
     int numNewFrames = frames.count();
 
@@ -154,57 +168,20 @@ void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
 
     m_frames += frames;
 
-    int currentCalls = m_calls.count();
-    int numNewCalls = 0;
     foreach(ApiTraceFrame *frame, frames) {
-        Q_ASSERT(this == frame->parentTrace());
-        numNewCalls += frame->numChildren();
-        calls += frame->calls();
+        frame->setParentTrace(this);
     }
-    m_calls.reserve(m_calls.count() + calls.count());
-    m_calls += calls;
 
     emit endAddingFrames();
-    emit callsAdded(currentCalls, numNewCalls);
-}
-
-void ApiTrace::detectFrames()
-{
-    if (m_calls.isEmpty())
-        return;
-
-    emit beginAddingFrames(0, m_frames.count());
-
-    ApiTraceFrame *currentFrame = 0;
-    foreach(ApiTraceCall *apiCall, m_calls) {
-        if (!currentFrame) {
-            currentFrame = new ApiTraceFrame(this);
-            currentFrame->number = m_frames.count();
-        }
-        apiCall->setParentFrame(currentFrame);
-        currentFrame->addCall(apiCall);
-        if (ApiTrace::isCallAFrameMarker(apiCall,
-                                         m_frameMarker)) {
-            m_frames.append(currentFrame);
-            currentFrame = 0;
-        }
-    }
-    //last frames won't have markers
-    //  it's just a bunch of Delete calls for every object
-    //  after the last SwapBuffers
-    if (currentFrame) {
-        m_frames.append(currentFrame);
-        currentFrame = 0;
-    }
-    emit endAddingFrames();
 }
 
 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
 {
-    for (int i = 0; i < m_calls.count(); ++i) {
-        ApiTraceCall *call = m_calls[i];
-        if (call->index() == idx)
+    for (int i = 0; i < m_frames.count(); ++i) {
+        ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
+        if (call) {
             return call;
+        }
     }
     return NULL;
 }
@@ -212,10 +189,16 @@ ApiTraceCall * ApiTrace::callWithIndex(int idx) const
 ApiTraceState ApiTrace::defaultState() const
 {
     ApiTraceFrame *frame = frameAt(0);
-    if (!frame)
+    if (!frame || !frame->isLoaded() || frame->isEmpty()) {
+        return ApiTraceState();
+    }
+
+    ApiTraceCall *firstCall = frame->calls().first();
+    if (!firstCall->hasState()) {
         return ApiTraceState();
+    }
 
-    return frame->state();
+    return *firstCall->state();
 }
 
 void ApiTrace::callEdited(ApiTraceCall *call)
@@ -259,7 +242,9 @@ void ApiTrace::save()
     QDir dir;
     emit startedSaving();
     dir.mkpath(fi.absolutePath());
-    m_saver->saveFile(m_tempFileName, m_calls);
+    m_saver->saveFile(m_tempFileName,
+                      m_fileName,
+                      m_editedCalls);
 }
 
 void ApiTrace::slotSaved()
@@ -272,31 +257,223 @@ bool ApiTrace::isSaving() const
     return m_saver->isRunning();
 }
 
-void ApiTrace::callError(ApiTraceCall *call)
+bool ApiTrace::hasErrors() const
 {
-    Q_ASSERT(call);
+    return !m_errors.isEmpty();
+}
 
-    if (call->hasError())
-        m_errors.insert(call);
-    else
-        m_errors.remove(call);
+void ApiTrace::loadFrame(ApiTraceFrame *frame)
+{
+    Q_ASSERT(!frame->isLoaded());
+    emit requestFrame(frame);
+}
 
-    emit changed(call);
+void ApiTrace::finishedParsing()
+{
+    ApiTraceFrame *firstFrame = m_frames[0];
+    if (firstFrame && !firstFrame->isLoaded()) {
+        loadFrame(firstFrame);
+    }
 }
 
-bool ApiTrace::hasErrors() const
+void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
+                                 const QVector<ApiTraceCall*> &calls,
+                                 quint64 binaryDataSize)
 {
-    return !m_errors.isEmpty();
+    Q_ASSERT(frame->numChildrenToLoad() == calls.size());
+    emit beginLoadingFrame(frame, calls.size());
+    frame->setCalls(calls, binaryDataSize);
+    emit endLoadingFrame(frame);
+
+    if (!m_queuedErrors.isEmpty()) {
+        QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
+        for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
+             ++itr) {
+            const ApiTraceError &error = (*itr).second;
+            if ((*itr).first == frame) {
+                ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+
+                if (!call) {
+                    continue;
+                }
+
+                call->setError(error.message);
+                m_queuedErrors.erase(itr);
+
+                if (call->hasError()) {
+                    m_errors.insert(call);
+                } else {
+                    m_errors.remove(call);
+                }
+                emit changed(call);
+            }
+        }
+    }
+}
+
+void ApiTrace::findNext(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+
+    if (frame->isLoaded()) {
+        foundCall = frame->findNextCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(SearchResult_Found, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx += 1;
+    }
+
+    for (int i = frameIdx; i < m_frames.count(); ++i) {
+        ApiTraceFrame *frame = m_frames[i];
+        if (!frame->isLoaded()) {
+            emit loaderSearchNext(i, str, sensitivity);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(SearchResult_Found, call);
+                return;
+            }
+        }
+    }
+    emit findResult(SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::findPrev(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+
+    if (frame->isLoaded()) {
+        foundCall = frame->findPrevCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(SearchResult_Found, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx -= 1;
+    }
+
+    for (int i = frameIdx; i >= 0; --i) {
+        ApiTraceFrame *frame = m_frames[i];
+        if (!frame->isLoaded()) {
+            emit loaderSearchPrev(i, str, sensitivity);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(SearchResult_Found, call);
+                return;
+            }
+        }
+    }
+    emit findResult(SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
+                                  ApiTraceCall *call)
+{
+    //qDebug()<<"Search result = "<<result
+    //       <<", call is = "<<call;
+    emit findResult(result, call);
+}
+
+void ApiTrace::findFrameStart(ApiTraceFrame *frame)
+{
+    if (frame->isLoaded()) {
+        emit foundFrameStart(frame);
+    } else {
+        emit loaderFindFrameStart(frame);
+    }
+}
+
+void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
+{
+    if (frame->isLoaded()) {
+        emit foundFrameEnd(frame);
+    } else {
+        emit loaderFindFrameEnd(frame);
+    }
+}
+
+void ApiTrace::findCallIndex(int index)
+{
+    int frameIdx = callInFrame(index);
+    ApiTraceFrame *frame = 0;
+
+    if (frameIdx < 0) {
+        emit foundCallIndex(0);
+        return;
+    }
+
+    frame = m_frames[frameIdx];
+
+    if (frame) {
+        if (frame->isLoaded()) {
+            ApiTraceCall *call = frame->callWithIndex(index);
+            emit foundCallIndex(call);
+        } else {
+            emit loaderFindCallIndex(index);
+        }
+    }
 }
 
-ApiTraceCallSignature * ApiTrace::signature(const QString &callName)
+int ApiTrace::callInFrame(int callIdx) const
 {
-    return m_signatures[callName];
+    unsigned numCalls = 0;
+
+    for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
+        const ApiTraceFrame *frame = m_frames[frameIdx];
+        unsigned numCallsInFrame =  frame->isLoaded()
+                ? frame->numChildren()
+                : frame->numChildrenToLoad();
+        unsigned firstCall = numCalls;
+        unsigned endCall = numCalls + numCallsInFrame;
+        if (firstCall <= callIdx && endCall > callIdx) {
+            return frameIdx;
+        }
+        numCalls = endCall;
+    }
+
+    return -1;
 }
 
-void ApiTrace::addSignature(ApiTraceCallSignature *signature)
+void ApiTrace::setCallError(const ApiTraceError &error)
 {
-    m_signatures.insert(signature->name(), signature);
+    int frameIdx = callInFrame(error.callIndex);
+    ApiTraceFrame *frame = 0;
+
+    if (frameIdx < 0) {
+        return;
+    }
+    frame = m_frames[frameIdx];
+
+    if (frame->isLoaded()) {
+        ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+        call->setError(error.message);
+        if (call->hasError()) {
+            m_errors.insert(call);
+        } else {
+            m_errors.remove(call);
+        }
+        emit changed(call);
+    } else {
+        emit requestFrame(frame);
+        m_queuedErrors.append(qMakePair(frame, error));
+    }
 }
 
 #include "apitrace.moc"
index abcdb014ec200b831c05c9cc1982edd07a657a0b..bf90d17daf5577a656893726579f4b3049259fe0 100644 (file)
@@ -6,8 +6,9 @@
 #include <QObject>
 #include <QSet>
 
-class LoaderThread;
+class TraceLoader;
 class SaverThread;
+class QThread;
 
 class ApiTrace : public QObject
 {
@@ -19,6 +20,12 @@ public:
         FrameMarker_Finish,
         FrameMarker_Clear
     };
+    enum SearchResult {
+        SearchResult_NotFound,
+        SearchResult_Found,
+        SearchResult_Wrapped
+    };
+
     static bool isCallAFrameMarker(const ApiTraceCall *call,
                                    FrameMarker marker);
 public:
@@ -33,13 +40,7 @@ public:
 
     ApiTraceState defaultState() const;
 
-    ApiTraceCallSignature *signature(const QString &callName);
-    void addSignature(ApiTraceCallSignature *signature);
-
-    QList<ApiTraceCall*> calls() const;
-    ApiTraceCall *callAt(int idx) const;
     ApiTraceCall *callWithIndex(int idx) const;
-    int numCalls() const;
 
     QList<ApiTraceFrame*> frames() const;
     ApiTraceFrame *frameAt(int idx) const;
@@ -59,37 +60,78 @@ public:
 
 public slots:
     void setFileName(const QString &name);
-    void setFrameMarker(FrameMarker marker);
     void save();
+    void loadFrame(ApiTraceFrame *frame);
+    void findNext(ApiTraceFrame *frame,
+                  ApiTraceCall *call,
+                  const QString &str,
+                  Qt::CaseSensitivity sensitivity);
+    void findPrev(ApiTraceFrame *frame,
+                  ApiTraceCall *call,
+                  const QString &str,
+                  Qt::CaseSensitivity sensitivity);
+    void findFrameStart(ApiTraceFrame *frame);
+    void findFrameEnd(ApiTraceFrame *frame);
+    void findCallIndex(int index);
+    void setCallError(const ApiTraceError &error);
+
 
 signals:
+    void loadTrace(const QString &name);
+    void requestFrame(ApiTraceFrame *frame);
     void startedLoadingTrace();
+    void loaded(int percent);
     void finishedLoadingTrace();
     void invalidated();
     void framesInvalidated();
     void changed(ApiTraceCall *call);
     void startedSaving();
     void saved();
+    void findResult(ApiTrace::SearchResult result,
+                    ApiTraceCall *call);
 
     void beginAddingFrames(int oldCount, int numAdded);
     void endAddingFrames();
-    void callsAdded(int oldCount, int numAdded);
+    void beginLoadingFrame(ApiTraceFrame *frame, int numAdded);
+    void endLoadingFrame(ApiTraceFrame *frame);
+    void foundFrameStart(ApiTraceFrame *frame);
+    void foundFrameEnd(ApiTraceFrame *frame);
+    void foundCallIndex(ApiTraceCall *call);
+
+signals:
+    void loaderSearchNext(int startFrame,
+                          const QString &str,
+                          Qt::CaseSensitivity sensitivity);
+    void loaderSearchPrev(int startFrame,
+                          const QString &str,
+                          Qt::CaseSensitivity sensitivity);
+    void loaderFindFrameStart(ApiTraceFrame *frame);
+    void loaderFindFrameEnd(ApiTraceFrame *frame);
+    void loaderFindCallIndex(int index);
 
 private slots:
     void addFrames(const QList<ApiTraceFrame*> &frames);
     void slotSaved();
+    void finishedParsing();
+    void loaderFrameLoaded(ApiTraceFrame *frame,
+                           const QVector<ApiTraceCall*> &calls,
+                           quint64 binaryDataSize);
+    void loaderSearchResult(ApiTrace::SearchResult result,
+                            ApiTraceCall *call);
+
 private:
-    void detectFrames();
+    int callInFrame(int callIdx) const;
 private:
     QString m_fileName;
     QString m_tempFileName;
 
     QList<ApiTraceFrame*> m_frames;
-    QList<ApiTraceCall*> m_calls;
+    QVector<ApiTraceCall*> m_calls;
 
     FrameMarker m_frameMarker;
 
-    LoaderThread *m_loader;
+    TraceLoader *m_loader;
+    QThread     *m_loaderThread;
     SaverThread  *m_saver;
 
     QSet<ApiTraceCall*> m_editedCalls;
@@ -97,7 +139,7 @@ private:
     bool m_needsSaving;
 
     QSet<ApiTraceCall*> m_errors;
-    QHash<QString, ApiTraceCallSignature*> m_signatures;
+    QList< QPair<ApiTraceFrame*, ApiTraceError> > m_queuedErrors;
 };
 
 #endif
index 5c7d86177f237ef95b9d20baad46a2c1dbe4afc3..67fc955957805308f71fb8b9c0ac06c37933fe4e 100644 (file)
@@ -1,6 +1,7 @@
 #include "apitracecall.h"
 
 #include "apitrace.h"
+#include "traceloader.h"
 #include "trace_model.hpp"
 
 #include <QDebug>
@@ -173,10 +174,21 @@ void VariantVisitor::visit(Trace::String *node)
 
 void VariantVisitor::visit(Trace::Enum *e)
 {
-    QVariant val = QVariant(e->sig->value);
+    ApiTraceEnumSignature *sig = 0;
 
-    m_variant = QVariant::fromValue(
-        ApiEnum(QString::fromStdString(e->sig->name), val));
+    if (m_loader) {
+        sig = m_loader->enumSignature(e->sig->id);
+    }
+    if (!sig) {
+        sig = new ApiTraceEnumSignature(
+            QString::fromStdString(e->sig->name),
+            QVariant(e->sig->value));
+        if (m_loader) {
+            m_loader->addEnumSignature(e->sig->id, sig);
+        }
+    }
+
+    m_variant = QVariant::fromValue(ApiEnum(sig));
 }
 
 void VariantVisitor::visit(Trace::Bitmask *bitmask)
@@ -204,6 +216,7 @@ void VariantVisitor::visit(Trace::Blob *blob)
     //   Blob's will start deleting the data we will need to
     //   start deep copying it or switch to using something like
     //   Boost's shared_ptr or Qt's QSharedPointer to handle it
+    blob->toPointer(true);
     QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
     m_variant = QVariant(barray);
 }
@@ -214,25 +227,36 @@ void VariantVisitor::visit(Trace::Pointer *ptr)
 }
 
 
-ApiEnum::ApiEnum(const QString &name, const QVariant &val)
-    : m_name(name),
-      m_value(val)
+ApiEnum::ApiEnum(ApiTraceEnumSignature *sig)
+    : m_sig(sig)
 {
 }
 
 QString ApiEnum::toString() const
 {
-    return m_name;
+    if (m_sig) {
+        return m_sig->name();
+    }
+    Q_ASSERT(!"should never happen");
+    return QString();
 }
 
 QVariant ApiEnum::value() const
 {
-    return m_value;
+    if (m_sig) {
+        return m_sig->value();
+    }
+    Q_ASSERT(!"should never happen");
+    return QVariant();
 }
 
 QString ApiEnum::name() const
 {
-    return m_name;
+    if (m_sig) {
+        return m_sig->name();
+    }
+    Q_ASSERT(!"should never happen");
+    return QString();
 }
 
 unsigned long long ApiBitmask::value() const
@@ -353,7 +377,7 @@ void ApiStruct::init(const Trace::Struct *s)
 
     m_sig.name = QString::fromStdString(s->sig->name);
     for (unsigned i = 0; i < s->sig->num_members; ++i) {
-        VariantVisitor vis;
+        VariantVisitor vis(0);
         m_sig.memberNames.append(
             QString::fromStdString(s->sig->member_names[i]));
         s->members[i]->visit(vis);
@@ -366,12 +390,12 @@ ApiArray::ApiArray(const Trace::Array *arr)
     init(arr);
 }
 
-ApiArray::ApiArray(const QList<QVariant> &vals)
+ApiArray::ApiArray(const QVector<QVariant> &vals)
     : m_array(vals)
 {
 }
 
-QList<QVariant> ApiArray::values() const
+QVector<QVariant> ApiArray::values() const
 {
     return m_array;
 }
@@ -398,11 +422,12 @@ void ApiArray::init(const Trace::Array *arr)
 
     m_array.reserve(arr->values.size());
     for (int i = 0; i < arr->values.size(); ++i) {
-        VariantVisitor vis;
+        VariantVisitor vis(0);
         arr->values[i]->visit(vis);
 
         m_array.append(vis.variant());
     }
+    m_array.squeeze();
 }
 
 ApiTraceState::ApiTraceState()
@@ -512,6 +537,22 @@ const QList<ApiFramebuffer> & ApiTraceState::framebuffers() const
     return m_framebuffers;
 }
 
+ApiFramebuffer ApiTraceState::colorBuffer() const
+{
+    foreach (ApiFramebuffer fbo, m_framebuffers) {
+        if (fbo.type() == QLatin1String("GL_BACK")) {
+            return fbo;
+        }
+    }
+    foreach (ApiFramebuffer fbo, m_framebuffers) {
+        if (fbo.type() == QLatin1String("GL_FRONT")) {
+            return fbo;
+        }
+    }
+    return ApiFramebuffer();
+}
+
+
 ApiTraceCallSignature::ApiTraceCallSignature(const QString &name,
                                              const QStringList &argNames)
     : m_name(name),
@@ -535,68 +576,75 @@ void ApiTraceCallSignature::setHelpUrl(const QUrl &url)
 
 ApiTraceEvent::ApiTraceEvent()
     : m_type(ApiTraceEvent::None),
+      m_hasBinaryData(false),
+      m_binaryDataIndex(0),
+      m_state(0),
       m_staticText(0)
 {
 }
 
 ApiTraceEvent::ApiTraceEvent(Type t)
     : m_type(t),
+      m_hasBinaryData(false),
+      m_binaryDataIndex(0),
+      m_state(0),
       m_staticText(0)
 {
 }
 
 ApiTraceEvent::~ApiTraceEvent()
 {
+    delete m_state;
     delete m_staticText;
 }
 
 QVariantMap ApiTraceEvent::stateParameters() const
 {
-    return m_state.parameters();
+    if (m_state) {
+        return m_state->parameters();
+    } else {
+        return QVariantMap();
+    }
 }
 
-ApiTraceState ApiTraceEvent::state() const
+ApiTraceState *ApiTraceEvent::state() const
 {
     return m_state;
 }
 
-void ApiTraceEvent::setState(const ApiTraceState &state)
+void ApiTraceEvent::setState(ApiTraceState *state)
 {
     m_state = state;
 }
 
-ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
+ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
+                           TraceLoader *loader,
+                           const Trace::Call *call)
     : ApiTraceEvent(ApiTraceEvent::Call),
-      m_parentFrame(parentFrame),
-      m_hasBinaryData(false),
-      m_binaryDataIndex(0)
+      m_parentFrame(parentFrame)
 {
-    ApiTrace *trace = parentTrace();
-
-    Q_ASSERT(trace);
-
     m_index = call->no;
 
-    QString name = QString::fromStdString(call->sig->name);
-    m_signature = trace->signature(name);
+    m_signature = loader->signature(call->sig->id);
 
     if (!m_signature) {
+        QString name = QString::fromStdString(call->sig->name);
         QStringList argNames;
         argNames.reserve(call->sig->num_args);
         for (int i = 0; i < call->sig->num_args; ++i) {
             argNames += QString::fromStdString(call->sig->arg_names[i]);
         }
         m_signature = new ApiTraceCallSignature(name, argNames);
-        trace->addSignature(m_signature);
+        loader->addSignature(call->sig->id, m_signature);
     }
     if (call->ret) {
-        VariantVisitor retVisitor;
+        VariantVisitor retVisitor(loader);
         call->ret->visit(retVisitor);
         m_returnValue = retVisitor.variant();
     }
     m_argValues.reserve(call->args.size());
     for (int i = 0; i < call->args.size(); ++i) {
-        VariantVisitor argVisitor;
+        VariantVisitor argVisitor(loader);
         call->args[i]->visit(argVisitor);
         m_argValues.append(argVisitor.variant());
         if (m_argValues[i].type() == QVariant::ByteArray) {
@@ -604,6 +652,7 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
             m_binaryDataIndex = i;
         }
     }
+    m_argValues.squeeze();
 }
 
 ApiTraceCall::~ApiTraceCall()
@@ -624,11 +673,8 @@ QString ApiTraceCall::error() const
 void ApiTraceCall::setError(const QString &msg)
 {
     if (m_error != msg) {
-        ApiTrace *trace = parentTrace();
         m_error = msg;
         m_richText = QString();
-        if (trace)
-            trace->callError(this);
     }
 }
 
@@ -639,12 +685,12 @@ ApiTrace * ApiTraceCall::parentTrace() const
     return NULL;
 }
 
-QVariantList ApiTraceCall::originalValues() const
+QVector<QVariant> ApiTraceCall::originalValues() const
 {
     return m_argValues;
 }
 
-void ApiTraceCall::setEditedValues(const QVariantList &lst)
+void ApiTraceCall::setEditedValues(const QVector<QVariant> &lst)
 {
     ApiTrace *trace = parentTrace();
 
@@ -664,7 +710,7 @@ void ApiTraceCall::setEditedValues(const QVariantList &lst)
     }
 }
 
-QVariantList ApiTraceCall::editedValues() const
+QVector<QVariant> ApiTraceCall::editedValues() const
 {
     return m_editedValues;
 }
@@ -676,7 +722,7 @@ bool ApiTraceCall::edited() const
 
 void ApiTraceCall::revert()
 {
-    setEditedValues(QVariantList());
+    setEditedValues(QVector<QVariant>());
 }
 
 void ApiTraceCall::setHelpUrl(const QUrl &url)
@@ -709,7 +755,7 @@ QStringList ApiTraceCall::argNames() const
     return m_signature->argNames();
 }
 
-QVariantList ApiTraceCall::arguments() const
+QVector<QVariant> ApiTraceCall::arguments() const
 {
     if (m_editedValues.isEmpty())
         return m_argValues;
@@ -742,7 +788,7 @@ QStaticText ApiTraceCall::staticText() const
     if (m_staticText && !m_staticText->text().isEmpty())
         return *m_staticText;
 
-    QVariantList argValues = arguments();
+    QVector<QVariant> argValues = arguments();
 
     QString richText = QString::fromLatin1(
         "<span style=\"font-weight:bold\">%1</span>(").arg(
@@ -811,7 +857,7 @@ QString ApiTraceCall::toHtml() const
                       .arg(m_signature->name());
     }
 
-    QVariantList argValues = arguments();
+    QVector<QVariant> argValues = arguments();
     QStringList argNames = m_signature->argNames();
     for (int i = 0; i < argNames.count(); ++i) {
         m_richText +=
@@ -861,7 +907,7 @@ QString ApiTraceCall::searchText() const
     if (!m_searchText.isEmpty())
         return m_searchText;
 
-    QVariantList argValues = arguments();
+    QVector<QVariant> argValues = arguments();
     m_searchText = m_signature->name() + QLatin1Literal("(");
     QStringList argNames = m_signature->argNames();
     for (int i = 0; i < argNames.count(); ++i) {
@@ -886,11 +932,27 @@ int ApiTraceCall::numChildren() const
     return 0;
 }
 
+bool ApiTraceCall::contains(const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    QString txt = searchText();
+    return txt.contains(str, sensitivity);
+}
+
+
 ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
     : ApiTraceEvent(ApiTraceEvent::Frame),
       m_parentTrace(parentTrace),
-      m_binaryDataSize(0)
+      m_binaryDataSize(0),
+      m_loaded(false),
+      m_callsToLoad(0),
+      m_lastCallIndex(0)
+{
+}
+
+ApiTraceFrame::~ApiTraceFrame()
 {
+    qDeleteAll(m_calls);
 }
 
 QStaticText ApiTraceFrame::staticText() const
@@ -898,23 +960,23 @@ QStaticText ApiTraceFrame::staticText() const
     if (m_staticText && !m_staticText->text().isEmpty())
         return *m_staticText;
 
-    QString richText;
+    QString richText = QObject::tr(
+                "<span style=\"font-weight:bold\">Frame %1</span>"
+                "&nbsp;&nbsp;&nbsp;"
+                "<span style=\"font-style:italic;font-size:small;font-weight:lighter;\"> "
+                "(%2 calls)</span>")
+            .arg(number)
+            .arg(m_loaded ? m_calls.count() : m_callsToLoad);
 
     //mark the frame if it uploads more than a meg a frame
     if (m_binaryDataSize > (1024*1024)) {
         richText =
             QObject::tr(
-                "<span style=\"font-weight:bold;\">"
-                "Frame&nbsp;%1</span>"
+                "%1"
                 "<span style=\"font-style:italic;\">"
                 "&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
-            .arg(number)
+            .arg(richText)
             .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
-    } else {
-        richText =
-            QObject::tr(
-                "<span style=\"font-weight:bold\">Frame %1</span>")
-            .arg(number);
     }
 
     if (!m_staticText)
@@ -948,7 +1010,7 @@ void ApiTraceFrame::addCall(ApiTraceCall *call)
     }
 }
 
-QList<ApiTraceCall*> ApiTraceFrame::calls() const
+QVector<ApiTraceCall*> ApiTraceFrame::calls() const
 {
     return m_calls;
 }
@@ -958,6 +1020,18 @@ ApiTraceCall * ApiTraceFrame::call(int idx) const
     return m_calls.value(idx);
 }
 
+
+ApiTraceCall * ApiTraceFrame::callWithIndex(int index) const
+{
+    QVector<ApiTraceCall*>::const_iterator itr;
+    for (itr = m_calls.constBegin(); itr != m_calls.constEnd(); ++itr) {
+        if ((*itr)->index() == index) {
+            return *itr;
+        }
+    }
+    return 0;
+}
+
 int ApiTraceFrame::callIndex(ApiTraceCall *call) const
 {
     return m_calls.indexOf(call);
@@ -965,10 +1039,107 @@ int ApiTraceFrame::callIndex(ApiTraceCall *call) const
 
 bool ApiTraceFrame::isEmpty() const
 {
-    return m_calls.isEmpty();
+    if (m_loaded) {
+        return m_calls.isEmpty();
+    } else {
+        return m_callsToLoad == 0;
+    }
 }
 
 int ApiTraceFrame::binaryDataSize() const
 {
     return m_binaryDataSize;
 }
+
+void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
+                             quint64 binaryDataSize)
+{
+    m_calls = calls;
+    m_binaryDataSize = binaryDataSize;
+    m_loaded = true;
+    delete m_staticText;
+    m_staticText = 0;
+}
+
+bool ApiTraceFrame::isLoaded() const
+{
+    return m_loaded;
+}
+
+void ApiTraceFrame::setLoaded(bool l)
+{
+    m_loaded = l;
+}
+
+void ApiTraceFrame::setNumChildren(int num)
+{
+    m_callsToLoad = num;
+}
+
+void ApiTraceFrame::setParentTrace(ApiTrace *parent)
+{
+    m_parentTrace = parent;
+}
+
+int ApiTraceFrame::numChildrenToLoad() const
+{
+    return m_callsToLoad;
+}
+
+ApiTraceCall *
+ApiTraceFrame::findNextCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    Q_ASSERT(m_loaded);
+
+    int callIndex = 0;
+
+    if (from) {
+        callIndex = m_calls.indexOf(from) + 1;
+    }
+
+    for (int i = callIndex; i < m_calls.count(); ++i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
+        }
+    }
+    return 0;
+}
+
+ApiTraceCall *
+ApiTraceFrame::findPrevCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    Q_ASSERT(m_loaded);
+
+    int callIndex = m_calls.count() - 1;
+
+    if (from) {
+        callIndex = m_calls.indexOf(from) - 1;
+    }
+
+    for (int i = callIndex; i >= 0; --i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
+        }
+    }
+    return 0;
+}
+
+void ApiTraceFrame::setLastCallIndex(unsigned index)
+{
+    m_lastCallIndex = index;
+}
+
+unsigned ApiTraceFrame::lastCallIndex() const
+{
+    if (m_loaded && !m_calls.isEmpty()) {
+        return m_calls.last()->index();
+    } else {
+        return m_lastCallIndex;
+    }
+}
index 89f310205545f23e62f5713a958104e168efae0a..12b0216a6e6ee4763da8d915d4cabbbb12b42858 100644 (file)
 
 
 class ApiTrace;
+class TraceLoader;
 
 class VariantVisitor : public Trace::Visitor
 {
 public:
+    VariantVisitor(TraceLoader *loader)
+        : m_loader(loader)
+    {}
     virtual void visit(Trace::Null *);
     virtual void visit(Trace::Bool *node);
     virtual void visit(Trace::SInt *node);
@@ -34,21 +38,45 @@ public:
         return m_variant;
     }
 private:
+    TraceLoader *m_loader;
     QVariant m_variant;
 };
 
+
+struct ApiTraceError
+{
+    int callIndex;
+    QString type;
+    QString message;
+};
+
+class ApiTraceEnumSignature
+{
+public:
+    ApiTraceEnumSignature(const QString &name = QString(),
+                          const QVariant &val=QVariant())\
+        : m_name(name),
+          m_value(val)
+    {}
+
+    QVariant value() const { return m_value; }
+    QString name() const { return m_name; }
+private:
+    QString m_name;
+    QVariant m_value;
+};
+
 class ApiEnum
 {
 public:
-    ApiEnum(const QString &name = QString(), const QVariant &val=QVariant());
+    ApiEnum(ApiTraceEnumSignature *sig=0);
 
     QString toString() const;
 
     QVariant value() const;
     QString name() const;
 private:
-    QString m_name;
-    QVariant m_value;
+    ApiTraceEnumSignature *m_sig;
 };
 Q_DECLARE_METATYPE(ApiEnum);
 
@@ -112,15 +140,15 @@ class ApiArray
 {
 public:
     ApiArray(const Trace::Array *arr = 0);
-    ApiArray(const QList<QVariant> &vals);
+    ApiArray(const QVector<QVariant> &vals);
 
     QString toString() const;
 
-    QList<QVariant> values() const;
+    QVector<QVariant> values() const;
 private:
     void init(const Trace::Array *arr);
 private:
-    QList<QVariant> m_array;
+    QVector<QVariant> m_array;
 };
 Q_DECLARE_METATYPE(ApiArray);
 
@@ -141,6 +169,7 @@ public:
     const QList<ApiTexture> & textures() const;
     const QList<ApiFramebuffer> & framebuffers() const;
 
+    ApiFramebuffer colorBuffer() const;
 private:
     QVariantMap m_parameters;
     QMap<QString, QString> m_shaderSources;
@@ -179,27 +208,33 @@ class ApiTraceEvent
 {
 public:
     enum Type {
-        None,
-        Call,
-        Frame
+        None  = 0,
+        Call  = 1 << 0,
+        Frame = 1 << 1
     };
 public:
     ApiTraceEvent();
     ApiTraceEvent(Type t);
     virtual ~ApiTraceEvent();
 
-    Type type() const { return m_type; }
+    Type type() const { return (Type)m_type; }
 
     virtual QStaticText staticText() const = 0;
     virtual int numChildren() const = 0;
 
     QVariantMap stateParameters() const;
-    ApiTraceState state() const;
-    void setState(const ApiTraceState &state);
+    ApiTraceState *state() const;
+    void setState(ApiTraceState *state);
+    bool hasState() const
+    {
+        return m_state && !m_state->isEmpty();
+    }
 
 protected:
-    Type m_type;
-    ApiTraceState m_state;
+    int m_type : 4;
+    mutable bool m_hasBinaryData;
+    mutable int m_binaryDataIndex:8;
+    ApiTraceState *m_state;
 
     mutable QStaticText *m_staticText;
 };
@@ -208,13 +243,14 @@ Q_DECLARE_METATYPE(ApiTraceEvent*);
 class ApiTraceCall : public ApiTraceEvent
 {
 public:
-    ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *tcall);
+    ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader,
+                 const Trace::Call *tcall);
     ~ApiTraceCall();
 
     int index() const;
     QString name() const;
     QStringList argNames() const;
-    QVariantList arguments() const;
+    QVector<QVariant> arguments() const;
     QVariant returnValue() const;
     QUrl helpUrl() const;
     void setHelpUrl(const QUrl &url);
@@ -225,13 +261,16 @@ public:
     QString error() const;
     void setError(const QString &msg);
 
-    QVariantList originalValues() const;
+    QVector<QVariant> originalValues() const;
 
     bool edited() const;
-    void setEditedValues(const QVariantList &lst);
-    QVariantList editedValues() const;
+    void setEditedValues(const QVector<QVariant> &lst);
+    QVector<QVariant> editedValues() const;
     void revert();
 
+    bool contains(const QString &str,
+                  Qt::CaseSensitivity sensitivity) const;
+
     ApiTrace *parentTrace() const;
 
     QString toHtml() const;
@@ -243,44 +282,66 @@ public:
 private:
     int m_index;
     ApiTraceCallSignature *m_signature;
-    QVariantList m_argValues;
+    QVector<QVariant> m_argValues;
     QVariant m_returnValue;
     ApiTraceFrame *m_parentFrame;
 
-    QVariantList m_editedValues;
+    QVector<QVariant> m_editedValues;
 
     QString m_error;
 
     mutable QString m_richText;
     mutable QString m_searchText;
-    mutable bool m_hasBinaryData;
-    mutable int m_binaryDataIndex;
 };
 Q_DECLARE_METATYPE(ApiTraceCall*);
 
 class ApiTraceFrame : public ApiTraceEvent
 {
 public:
-    ApiTraceFrame(ApiTrace *parent);
+    ApiTraceFrame(ApiTrace *parent=0);
+    ~ApiTraceFrame();
     int number;
 
     bool isEmpty() const;
 
+    void setParentTrace(ApiTrace *parent);
     ApiTrace *parentTrace() const;
 
+    void setNumChildren(int num);
     int numChildren() const;
+    int numChildrenToLoad() const;
     QStaticText staticText() const;
 
     int callIndex(ApiTraceCall *call) const;
     ApiTraceCall *call(int idx) const;
+    ApiTraceCall *callWithIndex(int index) const;
     void addCall(ApiTraceCall *call);
-    QList<ApiTraceCall*> calls() const;
+    QVector<ApiTraceCall*> calls() const;
+    void setCalls(const QVector<ApiTraceCall*> &calls,
+                  quint64 binaryDataSize);
+
+    ApiTraceCall *findNextCall(ApiTraceCall *from,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity) const;
+
+    ApiTraceCall *findPrevCall(ApiTraceCall *from,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity) const;
 
     int binaryDataSize() const;
+
+    bool isLoaded() const;
+    void setLoaded(bool l);
+
+    void setLastCallIndex(unsigned index);
+    unsigned lastCallIndex() const;
 private:
     ApiTrace *m_parentTrace;
     quint64 m_binaryDataSize;
-    QList<ApiTraceCall*> m_calls;
+    QVector<ApiTraceCall*> m_calls;
+    bool m_loaded;
+    unsigned m_callsToLoad;
+    unsigned m_lastCallIndex;
 };
 Q_DECLARE_METATYPE(ApiTraceFrame*);
 
index 2bf7bf8d007ec8b2131c4446d555b822044b7d26..cfa930d74f7c8752974027350e8867be3ae2d4ac 100644 (file)
@@ -89,12 +89,6 @@ void ApiTraceFilter::setFilterOptions(ApiTraceFilter::FilterOptions opts)
     }
 }
 
-QModelIndex ApiTraceFilter::callIndex(int callIdx) const
-{
-    ApiTraceModel *model = static_cast<ApiTraceModel *>(sourceModel());
-    QModelIndex index = model->callIndex(callIdx);
-    return mapFromSource(index);
-}
 
 QModelIndex ApiTraceFilter::indexForCall(ApiTraceCall *call) const
 {
index 217938c82a0fa2775175317afff428c58bca6a49..30c92a1287ff55794892068686d745c7d0155fcc 100644 (file)
@@ -27,7 +27,6 @@ public:
     void setFilterRegexp(const QRegExp &regexp);
     QRegExp filterRegexp() const;
 
-    QModelIndex callIndex(int callNum) const;
     QModelIndex indexForCall(ApiTraceCall *call) const;
 protected:
     bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
index e60b176f02311387ab62d35fa25544833293e99c..7303ae1c31e836bb2e507fe9b5fd34af657fa574 100644 (file)
@@ -1,9 +1,10 @@
 #include "apitracemodel.h"
 
 #include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "trace_parser.hpp"
 
+#include <QBuffer>
 #include <QDebug>
 #include <QImage>
 #include <QVariant>
@@ -42,7 +43,7 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
         const QString stateText = tr("State info available.");
         if (itm->type() == ApiTraceEvent::Call) {
             ApiTraceCall *call = static_cast<ApiTraceCall*>(itm);
-            if (call->state().isEmpty())
+            if (!call->hasState())
                 return QString::fromLatin1("%1)&nbsp;<b>%2</b>")
                     .arg(call->index())
                     .arg(call->name());
@@ -52,22 +53,53 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
                     .arg(call->name())
                     .arg(stateText);
         } else {
+            const char *htmlTempl =
+                    "<div>\n"
+                    "<div>\n"
+                    "%1"
+                    "<span style=\"font-weight:bold; font-size:large; vertical-align:center; padding-bottom: 30px \">\n"
+                    "Frame %2</span>\n"
+                    "</div>\n"
+                    "<div >%3 calls%4</div>\n"
+                    "</div>\n";
+
+
             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(itm);
-            QString text = QObject::tr("%1)&nbsp;Frame&nbsp;")
-                           .arg(frame->number);
-            int binaryDataSize = frame->binaryDataSize() / 1024;
-            if (frame->state().isEmpty())
-                return QObject::tr(
-                    "<b>%1&nbsp;</b>(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)")
-                    .arg(text)
-                    .arg(binaryDataSize);
-            else
-                return QObject::tr(
-                    "<b>%1&nbsp;(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)</b>"
-                    "<br/>%3")
-                    .arg(text)
-                    .arg(binaryDataSize)
-                    .arg(stateText);
+            QString thumbStr, sizeStr;
+
+            if (frame->hasState()) {
+                static const char *imgTempl =
+                        "<img style=\"float:left;\" "
+                        "src=\"data:image/png;base64,%1\"/>\n";
+                static const char *sizeTempl =
+                        ", %1kb";
+
+                ApiFramebuffer fbo = frame->state()->colorBuffer();
+                QImage thumb = fbo.thumb();
+                if (!thumb.isNull()) {
+                    QByteArray ba;
+                    QBuffer buffer(&ba);
+                    buffer.open(QIODevice::WriteOnly);
+                    thumb.save(&buffer, "PNG");
+                    thumbStr = tr(imgTempl).arg(
+                                QString(buffer.data().toBase64()));
+                }
+
+                int binaryDataSize = frame->binaryDataSize() / 1024;
+                if (binaryDataSize > 0) {
+                    sizeStr = tr(sizeTempl).arg(binaryDataSize);
+                }
+            }
+
+            int numCalls = frame->isLoaded()
+                    ? frame->numChildren()
+                    : frame->numChildrenToLoad();
+
+            return tr(htmlTempl)
+                    .arg(thumbStr)
+                    .arg(frame->number)
+                    .arg(numCalls)
+                    .arg(sizeStr);
         }
     }
     case ApiTraceModel::EventRole:
@@ -218,6 +250,11 @@ void ApiTraceModel::setApiTrace(ApiTrace *trace)
             this, SLOT(endAddingFrames()));
     connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
             this, SLOT(callChanged(ApiTraceCall*)));
+    connect(m_trace, SIGNAL(beginLoadingFrame(ApiTraceFrame*,int)),
+            this, SLOT(beginLoadingFrame(ApiTraceFrame*,int)));
+    connect(m_trace, SIGNAL(endLoadingFrame(ApiTraceFrame*)),
+            this, SLOT(endLoadingFrame(ApiTraceFrame*)));
+
 }
 
 const ApiTrace * ApiTraceModel::apiTrace() const
@@ -264,12 +301,6 @@ void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event)
     }
 }
 
-QModelIndex ApiTraceModel::callIndex(int callNum) const
-{
-    ApiTraceCall *call = m_trace->callWithIndex(callNum);
-    return indexForCall(call);
-}
-
 QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const
 {
     if (!call) {
@@ -313,4 +344,58 @@ void ApiTraceModel::endAddingFrames()
     endInsertRows();
 }
 
+bool ApiTraceModel::canFetchMore(const QModelIndex &parent) const
+{
+    if (parent.isValid()) {
+        ApiTraceEvent *event = item(parent);
+        if (event && event->type() == ApiTraceEvent::Frame) {
+            ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+            return !frame->isLoaded() && !m_loadingFrames.contains(frame);
+        } else
+            return false;
+    } else {
+        return false;
+    }
+}
+
+void ApiTraceModel::fetchMore(const QModelIndex &parent)
+{
+    if (parent.isValid()) {
+        ApiTraceEvent *event = item(parent);
+        if (event && event->type() == ApiTraceEvent::Frame) {
+            ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+            QModelIndex index = createIndex(frame->number, 0, frame);
+
+            Q_ASSERT(!frame->isLoaded());
+            m_loadingFrames.insert(frame);
+
+            m_trace->loadFrame(frame);
+        }
+    }
+}
+
+void ApiTraceModel::beginLoadingFrame(ApiTraceFrame *frame, int numAdded)
+{
+    QModelIndex index = createIndex(frame->number, 0, frame);
+    beginInsertRows(index, 0, numAdded - 1);
+}
+
+void ApiTraceModel::endLoadingFrame(ApiTraceFrame *frame)
+{
+    QModelIndex index = createIndex(frame->number, 0, frame);
+#if 0
+    qDebug()<<"Frame loaded = "<<frame->loaded();
+    qDebug()<<"\tframe idx = "<<frame->number;
+    qDebug()<<"\tis empty = "<<frame->isEmpty();
+    qDebug()<<"\tnum children = "<<frame->numChildren();
+    qDebug()<<"\tindex is "<<index;
+#endif
+
+    endInsertRows();
+
+    emit dataChanged(index, index);
+
+    m_loadingFrames.remove(frame);
+}
+
 #include "apitracemodel.moc"
index 2cdd7d0bfe6fd9e1cfcbd83f25bfe4a018aab262..fe6b5cea69deb5f0702c8af239066b1db5b806bb 100644 (file)
@@ -4,11 +4,13 @@
 
 #include <QAbstractItemModel>
 #include <QModelIndex>
+#include <QSet>
 #include <QVariant>
 
 class ApiTrace;
 class ApiTraceCall;
 class ApiTraceEvent;
+class ApiTraceFrame;
 
 class ApiTraceModel : public QAbstractItemModel
 {
@@ -25,7 +27,6 @@ public:
     const ApiTrace *apiTrace() const;
     void stateSetOnEvent(ApiTraceEvent *event);
 
-    QModelIndex callIndex(int callNum) const;
     QModelIndex indexForCall(ApiTraceCall *call) const;
 
 public:
@@ -45,6 +46,8 @@ public:
                     const QModelIndex &parent = QModelIndex());
     bool removeRows(int position, int rows,
                     const QModelIndex &parent = QModelIndex());
+    virtual bool canFetchMore(const QModelIndex & parent) const;
+    virtual void fetchMore(const QModelIndex &parent);
     /* } QAbstractItemModel; */
 
 private slots:
@@ -52,12 +55,15 @@ private slots:
     void beginAddingFrames(int oldCount, int numAdded);
     void endAddingFrames();
     void callChanged(ApiTraceCall *call);
+    void beginLoadingFrame(ApiTraceFrame *frame, int numAdded);
+    void endLoadingFrame(ApiTraceFrame *frame);
 
 private:
     ApiTraceEvent *item(const QModelIndex &index) const;
 
 private:
     ApiTrace *m_trace;
+    QSet<ApiTraceFrame*> m_loadingFrames;
 };
 
 #endif
index 8848122b60089479c3343eb69a6c7010ca060483..1ee519ea444d672598d414f7dc12f559c4914862 100644 (file)
@@ -16,7 +16,7 @@ isVariantEditable(const QVariant &var)
 {
     if (var.canConvert<ApiArray>()) {
         ApiArray array = var.value<ApiArray>();
-        QList<QVariant> vals = array.values();
+        QVector<QVariant> vals = array.values();
         if (vals.isEmpty())
             return false;
         else
@@ -42,7 +42,7 @@ isVariantStringArray(const QVariant &var)
         return false;
 
     ApiArray array = var.value<ApiArray>();
-    QList<QVariant> origValues = array.values();
+    QVector<QVariant> origValues = array.values();
     if (origValues.isEmpty() ||
         origValues.first().userType() != QVariant::String)
         return false;
@@ -210,7 +210,7 @@ void ArgumentsEditor::setupCall()
 
         if (val.canConvert<ApiArray>()) {
             ApiArray array = val.value<ApiArray>();
-            QList<QVariant> vals = array.values();
+            QVector<QVariant> vals = array.values();
 
             QVariant firstVal = vals.value(0);
             if (firstVal.userType() == QVariant::String) {
@@ -304,7 +304,7 @@ void ArgumentsEditor::setupCall()
     }
 }
 
-void ArgumentsEditor::setupShaderEditor(const QList<QVariant> &sources)
+void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources)
 {
     m_ui.selectStringCB->clear();
     m_ui.glslEdit->clear();
@@ -339,8 +339,8 @@ void ArgumentsEditor::sourceChanged()
 void ArgumentsEditor::accept()
 {
     QStringList argNames = m_call->argNames();
-    QList<QVariant> originalValues = m_call->arguments();
-    QList<QVariant> newValues;
+    QVector<QVariant> originalValues = m_call->arguments();
+    QVector<QVariant> newValues;
     bool changed = false;
     for (int i = 0; i < argNames.count(); ++i) {
         bool valChanged = false;
@@ -405,14 +405,14 @@ QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
                                          const ApiArray &origArray,
                                          bool *changed) const
 {
-    QList<QVariant> origValues = origArray.values();
+    QVector<QVariant> origValues = origArray.values();
 
     *changed = false;
 
     if (origValues.isEmpty())
         return QVariant::fromValue(ApiArray());
 
-    QList<QVariant> lst;
+    QVector<QVariant> lst;
     for (int i = 0; i < origValues.count(); ++i) {
         QModelIndex valIdx = m_model->index(i, 1, parentIndex);
         QVariant var = valIdx.data();
@@ -428,8 +428,8 @@ QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
 QVariant ArgumentsEditor::arrayFromEditor(const ApiArray &origArray,
                                           bool *changed) const
 {
-    QList<QVariant> vals;
-    QList<QVariant> origValues = origArray.values();
+    QVector<QVariant> vals;
+    QVector<QVariant> origValues = origArray.values();
 
     Q_ASSERT(isVariantStringArray(QVariant::fromValue(origArray)));
     *changed = false;
index e6b3d8fd65f01043ad5072787d0a622a18a90d44..7671d71bcd0264f720e2fbeac506bf8b71293328 100644 (file)
@@ -49,7 +49,7 @@ private slots:
 private:
     void init();
     void setupCall();
-    void setupShaderEditor(const QList<QVariant> &sources);
+    void setupShaderEditor(const QVector<QVariant> &sources);
     QVariant valueForName(const QString &name,
                           const QVariant &orignalValue,
                           bool *changed) const;
diff --git a/gui/loaderthread.cpp b/gui/loaderthread.cpp
deleted file mode 100644 (file)
index 0545453..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#include "loaderthread.h"
-
-#include "trace_parser.hpp"
-
-#include <QFile>
-#include <QHash>
-#include <QUrl>
-
-#include <QDebug>
-
-#define FRAMES_TO_CACHE 100
-
-static ApiTraceCall *
-apiCallFromTraceCall(const Trace::Call *call,
-                     const QHash<QString, QUrl> &helpHash,
-                     ApiTraceFrame *frame)
-{
-    ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
-
-    apiCall->setHelpUrl(helpHash.value(apiCall->name()));
-
-    return apiCall;
-}
-
-LoaderThread::LoaderThread(ApiTrace *parent)
-    : QThread(parent),
-      m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
-      m_trace(parent)
-{
-}
-
-void LoaderThread::run()
-{
-    QList<ApiTraceFrame*> frames;
-    ApiTraceFrame *currentFrame = 0;
-    int frameCount = 0;
-
-    QHash<QString, QUrl> helpHash;
-
-
-    QFile file(":/resources/glreference.tsv");
-    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-        QString line;
-        while (!file.atEnd()) {
-            line = file.readLine();
-            QString function = line.section('\t', 0, 0).trimmed();
-            QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
-            //qDebug()<<"function = "<<function<<", url = "<<url.toString();
-            helpHash.insert(function, url);
-        }
-    } else {
-        qWarning() << "Couldn't open reference file "
-                   << file.fileName();
-    }
-    file.close();
-
-    Trace::Parser p;
-    if (p.open(m_fileName.toLatin1().constData())) {
-        Trace::Call *call = p.parse_call();
-        while (call) {
-            //std::cout << *call;
-            if (!currentFrame) {
-                currentFrame = new ApiTraceFrame(m_trace);
-                currentFrame->number = frameCount;
-                ++frameCount;
-            }
-            ApiTraceCall *apiCall =
-                apiCallFromTraceCall(call, helpHash, currentFrame);
-            currentFrame->addCall(apiCall);
-            if (ApiTrace::isCallAFrameMarker(apiCall,
-                                             m_frameMarker)) {
-                frames.append(currentFrame);
-                currentFrame = 0;
-                if (frames.count() >= FRAMES_TO_CACHE) {
-                    emit parsedFrames(frames);
-                    frames.clear();
-                }
-            }
-            delete call;
-            call = p.parse_call();
-        }
-    }
-    //last frames won't have markers
-    //  it's just a bunch of Delete calls for every object
-    //  after the last SwapBuffers
-    if (currentFrame) {
-        frames.append(currentFrame);
-        currentFrame = 0;
-    }
-    if (frames.count()) {
-        emit parsedFrames(frames);
-    }
-}
-
-void LoaderThread::loadFile(const QString &fileName)
-{
-    m_fileName = fileName;
-    start();
-}
-
-ApiTrace::FrameMarker LoaderThread::frameMarker() const
-{
-    return m_frameMarker;
-}
-
-void LoaderThread::setFrameMarker(ApiTrace::FrameMarker marker)
-{
-    Q_ASSERT(!isRunning());
-    m_frameMarker = marker;
-}
-
-#include "loaderthread.moc"
diff --git a/gui/loaderthread.h b/gui/loaderthread.h
deleted file mode 100644 (file)
index c847c73..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef LOADERTHREAD_H
-#define LOADERTHREAD_H
-
-#include "apitrace.h"
-#include <QThread>
-#include <QList>
-
-class ApiTraceCall;
-class ApiTraceFrame;
-
-class LoaderThread : public QThread
-{
-    Q_OBJECT
-public:
-    LoaderThread(ApiTrace *parent);
-
-    ApiTrace::FrameMarker frameMarker() const;
-    void setFrameMarker(ApiTrace::FrameMarker marker);
-public slots:
-    void loadFile(const QString &fileName);
-
-signals:
-    void parsedFrames(const QList<ApiTraceFrame*> &frames);
-
-protected:
-    virtual void run();
-
-private:
-    QString m_fileName;
-    ApiTrace::FrameMarker m_frameMarker;
-    ApiTrace *m_trace;
-};
-
-#endif
index 3f8cfa6b6bcb7b884e4c47ba27da0018dc9fb1b0..6043b750ded5a2b17d513f2e0e67e36e38b24843 100644 (file)
@@ -1,5 +1,6 @@
 #include "mainwindow.h"
 
+#include "apitrace.h"
 #include "apitracecall.h"
 
 #include <QApplication>
@@ -7,13 +8,20 @@
 #include <QVariant>
 
 Q_DECLARE_METATYPE(QList<ApiTraceFrame*>);
+Q_DECLARE_METATYPE(QVector<ApiTraceCall*>);
+Q_DECLARE_METATYPE(Qt::CaseSensitivity);
+Q_DECLARE_METATYPE(ApiTrace::SearchResult);
+
 
 int main(int argc, char **argv)
 {
     QApplication app(argc, argv);
 
     qRegisterMetaType<QList<ApiTraceFrame*> >();
+    qRegisterMetaType<QVector<ApiTraceCall*> >();
     qRegisterMetaType<ApiTraceState>();
+    qRegisterMetaType<Qt::CaseSensitivity>();
+    qRegisterMetaType<ApiTrace::SearchResult>();
     MainWindow window;
 
     window.show();
index ba19b4db3d606621534ca489c69e31b573d060af..8d7af8a0a1f4a5c24041f7a511e0c1930f1c06b6 100644 (file)
@@ -47,8 +47,6 @@ MainWindow::MainWindow()
 
 void MainWindow::createTrace()
 {
-    TraceDialog dialog;
-
     if (!m_traceProcess->canTrace()) {
         QMessageBox::warning(
             this,
@@ -57,6 +55,7 @@ void MainWindow::createTrace()
         return;
     }
 
+    TraceDialog dialog;
     if (dialog.exec() == QDialog::Accepted) {
         qDebug()<< "App : " <<dialog.applicationPath();
         qDebug()<< "  Arguments: "<<dialog.arguments();
@@ -69,11 +68,11 @@ void MainWindow::createTrace()
 void MainWindow::openTrace()
 {
     QString fileName =
-        QFileDialog::getOpenFileName(
-            this,
-            tr("Open Trace"),
-            QDir::homePath(),
-            tr("Trace Files (*.trace)"));
+            QFileDialog::getOpenFileName(
+                this,
+                tr("Open Trace"),
+                QDir::homePath(),
+                tr("Trace Files (*.trace)"));
 
     if (!fileName.isEmpty() && QFile::exists(fileName)) {
         newTraceFile(fileName);
@@ -104,8 +103,8 @@ void MainWindow::callItemSelected(const QModelIndex &index)
             QByteArray data =
                 call->arguments()[call->binaryDataIndex()].toByteArray();
             m_vdataInterpreter->setData(data);
-            QVariantList args = call->arguments();
 
+            QVector<QVariant> args = call->arguments();
             for (int i = 0; i < call->argNames().count(); ++i) {
                 QString name = call->argNames()[i];
                 if (name == QLatin1String("stride")) {
@@ -117,8 +116,9 @@ void MainWindow::callItemSelected(const QModelIndex &index)
                 } else if (name == QLatin1String("type")) {
                     QString val = args[i].toString();
                     int textIndex = m_ui.vertexTypeCB->findText(val);
-                    if (textIndex >= 0)
+                    if (textIndex >= 0) {
                         m_ui.vertexTypeCB->setCurrentIndex(textIndex);
+                    }
                 }
             }
         }
@@ -127,15 +127,17 @@ void MainWindow::callItemSelected(const QModelIndex &index)
     } else {
         if (event && event->type() == ApiTraceEvent::Frame) {
             m_selectedEvent = static_cast<ApiTraceFrame*>(event);
-        } else
+        } else {
             m_selectedEvent = 0;
+        }
         m_ui.detailsDock->hide();
         m_ui.vertexDataDock->hide();
     }
-    if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
+    if (m_selectedEvent && m_selectedEvent->hasState()) {
         fillStateForFrame();
-    } else
+    } else {
         m_ui.stateDock->hide();
+    }
 }
 
 void MainWindow::replayStart()
@@ -207,8 +209,9 @@ void MainWindow::replayFinished(const QString &output)
     m_stateEvent = 0;
     m_ui.actionShowErrorsDock->setEnabled(m_trace->hasErrors());
     m_ui.errorsDock->setVisible(m_trace->hasErrors());
-    if (!m_trace->hasErrors())
+    if (!m_trace->hasErrors()) {
         m_ui.errorsTreeWidget->clear();
+    }
 
     statusBar()->showMessage(
         tr("Replaying finished!"), 2000);
@@ -251,8 +254,9 @@ void MainWindow::finishedLoadingTrace()
 
 void MainWindow::replayTrace(bool dumpState)
 {
-    if (m_trace->fileName().isEmpty())
+    if (m_trace->fileName().isEmpty()) {
         return;
+    }
 
     m_retracer->setFileName(m_trace->fileName());
     m_retracer->setCaptureState(dumpState);
@@ -268,7 +272,7 @@ void MainWindow::replayTrace(bool dumpState)
                 qDebug()<<"tried to get a state for an empty frame";
                 return;
             }
-            index = frame->calls().first()->index();
+            index = frame->lastCallIndex();
         } else {
             qDebug()<<"Unknown event type";
             return;
@@ -279,12 +283,13 @@ void MainWindow::replayTrace(bool dumpState)
 
     m_ui.actionStop->setEnabled(true);
     m_progressBar->show();
-    if (dumpState)
+    if (dumpState) {
         statusBar()->showMessage(
             tr("Looking up the state..."));
-    else
+    } else {
         statusBar()->showMessage(
             tr("Replaying the trace file..."));
+    }
 }
 
 void MainWindow::lookupState()
@@ -320,7 +325,7 @@ static void
 variantToString(const QVariant &var, QString &str)
 {
     if (var.type() == QVariant::List) {
-        QVariantList lst = var.toList();
+        QVector<QVariant> lst = var.toList().toVector();
         str += QLatin1String("[");
         for (int i = 0; i < lst.count(); ++i) {
             QVariant val = lst[i];
@@ -339,10 +344,12 @@ variantToString(const QVariant &var, QString &str)
 }
 
 static QTreeWidgetItem *
-variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar);
+variantToItem(const QString &key, const QVariant &var,
+              const QVariant &defaultVar);
 
 static void
-variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<QTreeWidgetItem *> &items)
+variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap,
+                  QList<QTreeWidgetItem *> &items)
 {
     QVariantMap::const_iterator itr;
     for (itr = map.constBegin(); itr != map.constEnd(); ++itr) {
@@ -358,7 +365,9 @@ variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<Q
 }
 
 static void
-variantListToItems(const QVariantList &lst, const QVariantList &defaultLst, QList<QTreeWidgetItem *> &items)
+variantListToItems(const QVector<QVariant> &lst,
+                   const QVector<QVariant> &defaultLst,
+                   QList<QTreeWidgetItem *> &items)
 {
     for (int i = 0; i < lst.count(); ++i) {
         QString key = QString::number(i);
@@ -380,7 +389,7 @@ static bool
 isVariantDeep(const QVariant &var)
 {
     if (var.type() == QVariant::List) {
-        QVariantList lst = var.toList();
+        QVector<QVariant> lst = var.toList().toVector();
         for (int i = 0; i < lst.count(); ++i) {
             if (isVariantDeep(lst[i])) {
                 return true;
@@ -397,7 +406,8 @@ isVariantDeep(const QVariant &var)
 }
 
 static QTreeWidgetItem *
-variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar)
+variantToItem(const QString &key, const QVariant &var,
+              const QVariant &defaultVar)
 {
     if (var == defaultVar) {
         return NULL;
@@ -426,8 +436,8 @@ variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVa
             variantMapToItems(map, defaultMap, children);
         }
         if (var.type() == QVariant::List) {
-            QVariantList lst = var.toList();
-            QVariantList defaultLst = defaultVar.toList();
+            QVector<QVariant> lst = var.toList().toVector();
+            QVector<QVariant> defaultLst = defaultVar.toList().toVector();
             variantListToItems(lst, defaultLst, children);
         }
         item->addChildren(children);
@@ -441,13 +451,12 @@ static void addSurfaceItem(const ApiSurface &surface,
                            QTreeWidgetItem *parent,
                            QTreeWidget *tree)
 {
-    int width = surface.size().width();
-    int height = surface.size().height();
     QIcon icon(QPixmap::fromImage(surface.thumb()));
     QTreeWidgetItem *item = new QTreeWidgetItem(parent);
-
     item->setIcon(0, icon);
 
+    int width = surface.size().width();
+    int height = surface.size().height();
     QString descr =
         QString::fromLatin1("%1, %2 x %3")
         .arg(label)
@@ -464,8 +473,9 @@ static void addSurfaceItem(const ApiSurface &surface,
 
 void MainWindow::fillStateForFrame()
 {
-    if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
+    if (!m_selectedEvent || !m_selectedEvent->hasState()) {
         return;
+    }
 
     if (m_nonDefaultsLookupEvent) {
         m_ui.nonDefaultsCB->blockSignals(true);
@@ -480,7 +490,7 @@ void MainWindow::fillStateForFrame()
         defaultParams = defaultState.parameters();
     }
 
-    const ApiTraceState &state = m_selectedEvent->state();
+    const ApiTraceState &state = *m_selectedEvent->state();
     m_ui.stateTreeWidget->clear();
     QList<QTreeWidgetItem *> items;
     variantMapToItems(state.parameters(), defaultParams, items);
@@ -512,8 +522,9 @@ void MainWindow::fillStateForFrame()
             QTreeWidgetItem *textureItem =
                 new QTreeWidgetItem(m_ui.surfacesTreeWidget);
             textureItem->setText(0, tr("Textures"));
-            if (textures.count() <= 6)
+            if (textures.count() <= 6) {
                 textureItem->setExpanded(true);
+            }
 
             for (int i = 0; i < textures.count(); ++i) {
                 const ApiTexture &texture =
@@ -527,8 +538,9 @@ void MainWindow::fillStateForFrame()
             QTreeWidgetItem *fboItem =
                 new QTreeWidgetItem(m_ui.surfacesTreeWidget);
             fboItem->setText(0, tr("Framebuffers"));
-            if (fbos.count() <= 6)
+            if (fbos.count() <= 6) {
                 fboItem->setExpanded(true);
+            }
 
             for (int i = 0; i < fbos.count(); ++i) {
                 const ApiFramebuffer &fbo =
@@ -560,8 +572,9 @@ void MainWindow::showSurfacesMenu(const QPoint &pos)
 {
     QTreeWidget *tree = m_ui.surfacesTreeWidget;
     QTreeWidgetItem *item = tree->itemAt(pos);
-    if (!item)
+    if (!item) {
         return;
+    }
 
     QMenu menu(tr("Surfaces"), this);
 
@@ -583,24 +596,28 @@ void MainWindow::showSelectedSurface()
     QTreeWidgetItem *item =
         m_ui.surfacesTreeWidget->currentItem();
 
-    if (!item)
+    if (!item) {
         return;
+    }
 
-    QVariant var = item->data(0, Qt::UserRole);
-    QImage img = var.value<QImage>();
     ImageViewer *viewer = new ImageViewer(this);
 
     QString title;
-    if (currentCall()) {
+    if (selectedCall()) {
         title = tr("QApiTrace - Surface at %1 (%2)")
-                .arg(currentCall()->name())
-                .arg(currentCall()->index());
+                .arg(selectedCall()->name())
+                .arg(selectedCall()->index());
     } else {
         title = tr("QApiTrace - Surface Viewer");
     }
     viewer->setWindowTitle(title);
+
     viewer->setAttribute(Qt::WA_DeleteOnClose, true);
+
+    QVariant var = item->data(0, Qt::UserRole);
+    QImage img = var.value<QImage>();
     viewer->setImage(img);
+
     QRect screenRect = QApplication::desktop()->availableGeometry();
     viewer->resize(qMin(int(0.75 * screenRect.width()), img.width()) + 40,
                    qMin(int(0.75 * screenRect.height()), img.height()) + 40);
@@ -646,7 +663,7 @@ void MainWindow::initObjects()
     m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu);
 
     m_progressBar = new QProgressBar();
-    m_progressBar->setRange(0, 0);
+    m_progressBar->setRange(0, 100);
     statusBar()->addPermanentWidget(m_progressBar);
     m_progressBar->hide();
 
@@ -681,6 +698,8 @@ void MainWindow::initConnections()
 {
     connect(m_trace, SIGNAL(startedLoadingTrace()),
             this, SLOT(startedLoadingTrace()));
+    connect(m_trace, SIGNAL(loaded(int)),
+            this, SLOT(loadProgess(int)));
     connect(m_trace, SIGNAL(finishedLoadingTrace()),
             this, SLOT(finishedLoadingTrace()));
     connect(m_trace, SIGNAL(startedSaving()),
@@ -689,15 +708,23 @@ void MainWindow::initConnections()
             this, SLOT(slotSaved()));
     connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
             this, SLOT(slotTraceChanged(ApiTraceCall*)));
+    connect(m_trace, SIGNAL(findResult(ApiTrace::SearchResult,ApiTraceCall*)),
+            this, SLOT(slotSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
+    connect(m_trace, SIGNAL(foundFrameStart(ApiTraceFrame*)),
+            this, SLOT(slotFoundFrameStart(ApiTraceFrame*)));
+    connect(m_trace, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
+            this, SLOT(slotFoundFrameEnd(ApiTraceFrame*)));
+    connect(m_trace, SIGNAL(foundCallIndex(ApiTraceCall*)),
+            this, SLOT(slotJumpToResult(ApiTraceCall*)));
 
     connect(m_retracer, SIGNAL(finished(const QString&)),
             this, SLOT(replayFinished(const QString&)));
     connect(m_retracer, SIGNAL(error(const QString&)),
             this, SLOT(replayError(const QString&)));
-    connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)),
-            this, SLOT(replayStateFound(const ApiTraceState&)));
-    connect(m_retracer, SIGNAL(retraceErrors(const QList<RetraceError>&)),
-            this, SLOT(slotRetraceErrors(const QList<RetraceError>&)));
+    connect(m_retracer, SIGNAL(foundState(ApiTraceState*)),
+            this, SLOT(replayStateFound(ApiTraceState*)));
+    connect(m_retracer, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
+            this, SLOT(slotRetraceErrors(const QList<ApiTraceError>&)));
 
     connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
             m_vdataInterpreter, SLOT(interpretData()));
@@ -778,7 +805,7 @@ void MainWindow::initConnections()
             this, SLOT(slotErrorSelected(QTreeWidgetItem*)));
 }
 
-void MainWindow::replayStateFound(const ApiTraceState &state)
+void MainWindow::replayStateFound(ApiTraceState *state)
 {
     m_stateEvent->setState(state);
     m_model->stateSetOnEvent(m_stateEvent);
@@ -799,10 +826,7 @@ void MainWindow::slotGoTo()
 
 void MainWindow::slotJumpTo(int callNum)
 {
-    QModelIndex index = m_proxyModel->callIndex(callNum);
-    if (index.isValid()) {
-        m_ui.callView->setCurrentIndex(index);
-    }
+    m_trace->findCallIndex(callNum);
 }
 
 void MainWindow::createdTrace(const QString &path)
@@ -828,103 +852,31 @@ void MainWindow::slotSearch()
 void MainWindow::slotSearchNext(const QString &str,
                                 Qt::CaseSensitivity sensitivity)
 {
-    QModelIndex index = m_ui.callView->currentIndex();
-    ApiTraceEvent *event = 0;
-
-
-    if (!index.isValid()) {
-        index = m_proxyModel->index(0, 0, QModelIndex());
-        if (!index.isValid()) {
-            qDebug()<<"no currently valid index";
-            m_searchWidget->setFound(false);
-            return;
-        }
-    }
-
-    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
-    ApiTraceCall *call = 0;
+    ApiTraceCall *call = currentCall();
+    ApiTraceFrame *frame = currentFrame();
 
-    if (event->type() == ApiTraceCall::Call)
-        call = static_cast<ApiTraceCall*>(event);
-    else {
-        Q_ASSERT(event->type() == ApiTraceCall::Frame);
-        ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
-        call = frame->call(0);
+    Q_ASSERT(call || frame);
+    if (!frame) {
+        frame = call->parentFrame();
     }
+    Q_ASSERT(frame);
 
-    if (!call) {
-        m_searchWidget->setFound(false);
-        return;
-    }
-    const QList<ApiTraceCall*> &calls = m_trace->calls();
-    int callNum = calls.indexOf(call);
-
-    for (int i = callNum + 1; i < calls.count(); ++i) {
-        ApiTraceCall *testCall = calls[i];
-        QModelIndex index = m_proxyModel->indexForCall(testCall);
-        /* if it's not valid it means that the proxy model has already
-         * filtered it out */
-        if (index.isValid()) {
-            QString txt = testCall->searchText();
-            if (txt.contains(str, sensitivity)) {
-                m_ui.callView->setCurrentIndex(index);
-                m_searchWidget->setFound(true);
-                return;
-            }
-        }
-    }
-    m_searchWidget->setFound(false);
+    m_trace->findNext(frame, call, str, sensitivity);
 }
 
 void MainWindow::slotSearchPrev(const QString &str,
                                 Qt::CaseSensitivity sensitivity)
 {
-    QModelIndex index = m_ui.callView->currentIndex();
-    ApiTraceEvent *event = 0;
-
-
-    if (!index.isValid()) {
-        index = m_proxyModel->index(0, 0, QModelIndex());
-        if (!index.isValid()) {
-            qDebug()<<"no currently valid index";
-            m_searchWidget->setFound(false);
-            return;
-        }
-    }
-
-    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
-    ApiTraceCall *call = 0;
+    ApiTraceCall *call = currentCall();
+    ApiTraceFrame *frame = currentFrame();
 
-    if (event->type() == ApiTraceCall::Call)
-        call = static_cast<ApiTraceCall*>(event);
-    else {
-        Q_ASSERT(event->type() == ApiTraceCall::Frame);
-        ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
-        call = frame->call(0);
+    Q_ASSERT(call || frame);
+    if (!frame) {
+        frame = call->parentFrame();
     }
+    Q_ASSERT(frame);
 
-    if (!call) {
-        m_searchWidget->setFound(false);
-        return;
-    }
-    const QList<ApiTraceCall*> &calls = m_trace->calls();
-    int callNum = calls.indexOf(call);
-
-    for (int i = callNum - 1; i >= 0; --i) {
-        ApiTraceCall *testCall = calls[i];
-        QModelIndex index = m_proxyModel->indexForCall(testCall);
-        /* if it's not valid it means that the proxy model has already
-         * filtered it out */
-        if (index.isValid()) {
-            QString txt = testCall->searchText();
-            if (txt.contains(str, sensitivity)) {
-                m_ui.callView->setCurrentIndex(index);
-                m_searchWidget->setFound(true);
-                return;
-            }
-        }
-    }
-    m_searchWidget->setFound(false);
+    m_trace->findPrev(frame, call, str, sensitivity);
 }
 
 void MainWindow::fillState(bool nonDefaults)
@@ -937,11 +889,17 @@ void MainWindow::fillState(bool nonDefaults)
             m_ui.nonDefaultsCB->blockSignals(false);
             ApiTraceFrame *firstFrame =
                 m_trace->frameAt(0);
-            ApiTraceEvent *oldSelected = m_selectedEvent;
-            if (!firstFrame)
+            if (!firstFrame) {
+                return;
+            }
+            if (!firstFrame->isLoaded()) {
+                m_trace->loadFrame(firstFrame);
                 return;
+            }
+            ApiTraceCall *firstCall = firstFrame->calls().first();
+            ApiTraceEvent *oldSelected = m_selectedEvent;
             m_nonDefaultsLookupEvent = m_selectedEvent;
-            m_selectedEvent = firstFrame;
+            m_selectedEvent = firstCall;
             lookupState();
             m_selectedEvent = oldSelected;
         }
@@ -951,18 +909,20 @@ void MainWindow::fillState(bool nonDefaults)
 
 void MainWindow::customContextMenuRequested(QPoint pos)
 {
-    QMenu menu;
     QModelIndex index = m_ui.callView->indexAt(pos);
 
     callItemSelected(index);
-    if (!index.isValid())
+    if (!index.isValid()) {
         return;
+    }
 
     ApiTraceEvent *event =
         index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
-    if (!event)
+    if (!event) {
         return;
+    }
 
+    QMenu menu;
     menu.addAction(QIcon(":/resources/media-record.png"),
                    tr("Lookup state"), this, SLOT(lookupState()));
     if (event->type() == ApiTraceEvent::Call) {
@@ -998,47 +958,28 @@ void MainWindow::slotSaved()
 void MainWindow::slotGoFrameStart()
 {
     ApiTraceFrame *frame = currentFrame();
-    if (!frame || frame->isEmpty()) {
-        return;
-    }
-
-    QList<ApiTraceCall*>::const_iterator itr;
-    QList<ApiTraceCall*> calls = frame->calls();
+    ApiTraceCall *call = currentCall();
 
-    itr = calls.constBegin();
-    while (itr != calls.constEnd()) {
-        ApiTraceCall *call = *itr;
-        QModelIndex idx = m_proxyModel->indexForCall(call);
-        if (idx.isValid()) {
-            m_ui.callView->setCurrentIndex(idx);
-            break;
-        }
-        ++itr;
+    if (!frame && call) {
+        frame = call->parentFrame();
     }
+
+    m_trace->findFrameStart(frame);
 }
 
 void MainWindow::slotGoFrameEnd()
 {
     ApiTraceFrame *frame = currentFrame();
-    if (!frame || frame->isEmpty()) {
-        return;
+    ApiTraceCall *call = currentCall();
+
+    if (!frame && call) {
+        frame = call->parentFrame();
     }
-    QList<ApiTraceCall*>::const_iterator itr;
-    QList<ApiTraceCall*> calls = frame->calls();
 
-    itr = calls.constEnd();
-    do {
-        --itr;
-        ApiTraceCall *call = *itr;
-        QModelIndex idx = m_proxyModel->indexForCall(call);
-        if (idx.isValid()) {
-            m_ui.callView->setCurrentIndex(idx);
-            break;
-        }
-    } while (itr != calls.constBegin());
+    m_trace->findFrameEnd(frame);
 }
 
-ApiTraceFrame * MainWindow::currentFrame() const
+ApiTraceFrame * MainWindow::selectedFrame() const
 {
     if (m_selectedEvent) {
         if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
@@ -1060,20 +1001,17 @@ void MainWindow::slotTraceChanged(ApiTraceCall *call)
     }
 }
 
-void MainWindow::slotRetraceErrors(const QList<RetraceError> &errors)
+void MainWindow::slotRetraceErrors(const QList<ApiTraceError> &errors)
 {
     m_ui.errorsTreeWidget->clear();
 
-    foreach(RetraceError error, errors) {
-        ApiTraceCall *call = m_trace->callWithIndex(error.callIndex);
-        if (!call)
-            continue;
-        call->setError(error.message);
+    foreach(ApiTraceError error, errors) {
+        m_trace->setCallError(error);
 
         QTreeWidgetItem *item =
             new QTreeWidgetItem(m_ui.errorsTreeWidget);
         item->setData(0, Qt::DisplayRole, error.callIndex);
-        item->setData(0, Qt::UserRole, QVariant::fromValue(call));
+        item->setData(0, Qt::UserRole, error.callIndex);
         QString type = error.type;
         type[0] = type[0].toUpper();
         item->setData(1, Qt::DisplayRole, type);
@@ -1084,19 +1022,13 @@ void MainWindow::slotRetraceErrors(const QList<RetraceError> &errors)
 void MainWindow::slotErrorSelected(QTreeWidgetItem *current)
 {
     if (current) {
-        ApiTraceCall *call =
-            current->data(0, Qt::UserRole).value<ApiTraceCall*>();
-        Q_ASSERT(call);
-        QModelIndex index = m_proxyModel->indexForCall(call);
-        if (index.isValid()) {
-            m_ui.callView->setCurrentIndex(index);
-        } else {
-            statusBar()->showMessage(tr("Call has been filtered out."));
-        }
+        int callIndex =
+            current->data(0, Qt::UserRole).toInt();
+        m_trace->findCallIndex(callIndex);
     }
 }
 
-ApiTraceCall * MainWindow::currentCall() const
+ApiTraceCall * MainWindow::selectedCall() const
 {
     if (m_selectedEvent &&
         m_selectedEvent->type() == ApiTraceEvent::Call) {
@@ -1110,18 +1042,19 @@ void MainWindow::saveSelectedSurface()
     QTreeWidgetItem *item =
         m_ui.surfacesTreeWidget->currentItem();
 
-    if (!item || !m_trace)
+    if (!item || !m_trace) {
         return;
+    }
 
     QVariant var = item->data(0, Qt::UserRole);
     QImage img = var.value<QImage>();
 
     QString imageIndex;
-    if (currentCall()) {
+    if (selectedCall()) {
         imageIndex = tr("_call_%1")
-                     .arg(currentCall()->index());
-    } else if (currentFrame()) {
-        ApiTraceCall *firstCall = currentFrame()->call(0);
+                     .arg(selectedCall()->index());
+    } else if (selectedFrame()) {
+        ApiTraceCall *firstCall = selectedFrame()->call(0);
         if (firstCall) {
             imageIndex = tr("_frame_%1")
                          .arg(firstCall->index());
@@ -1158,4 +1091,135 @@ void MainWindow::saveSelectedSurface()
     statusBar()->showMessage( tr("Saved '%1'").arg(fileName), 5000);
 }
 
+void MainWindow::loadProgess(int percent)
+{
+    m_progressBar->setValue(percent);
+}
+
+void MainWindow::slotSearchResult(ApiTrace::SearchResult result,
+                                  ApiTraceCall *call)
+{
+    switch (result) {
+    case ApiTrace::SearchResult_NotFound:
+        m_searchWidget->setFound(false);
+        break;
+    case ApiTrace::SearchResult_Found: {
+        QModelIndex index = m_proxyModel->indexForCall(call);
+        m_ui.callView->setCurrentIndex(index);
+        m_searchWidget->setFound(true);
+    }
+        break;
+    case ApiTrace::SearchResult_Wrapped:
+        m_searchWidget->setFound(false);
+        break;
+    }
+}
+
+ApiTraceFrame * MainWindow::currentFrame() const
+{
+    QModelIndex index = m_ui.callView->currentIndex();
+    ApiTraceEvent *event = 0;
+
+    if (!index.isValid()) {
+        index = m_proxyModel->index(0, 0, QModelIndex());
+        if (!index.isValid()) {
+            qDebug()<<"no currently valid index";
+            return 0;
+        }
+    }
+
+    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+    Q_ASSERT(event);
+    if (!event) {
+        return 0;
+    }
+
+    ApiTraceFrame *frame = 0;
+    if (event->type() == ApiTraceCall::Frame) {
+        frame = static_cast<ApiTraceFrame*>(event);
+    }
+    return frame;
+}
+
+ApiTraceCall * MainWindow::currentCall() const
+{
+    QModelIndex index = m_ui.callView->currentIndex();
+    ApiTraceEvent *event = 0;
+
+    if (!index.isValid()) {
+        index = m_proxyModel->index(0, 0, QModelIndex());
+        if (!index.isValid()) {
+            qDebug()<<"no currently valid index";
+            return 0;
+        }
+    }
+
+    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+    Q_ASSERT(event);
+    if (!event) {
+        return 0;
+    }
+
+    ApiTraceCall *call = 0;
+    if (event->type() == ApiTraceCall::Call) {
+        call = static_cast<ApiTraceCall*>(event);
+    }
+
+    return call;
+
+}
+
+void MainWindow::slotFoundFrameStart(ApiTraceFrame *frame)
+{
+    Q_ASSERT(frame->isLoaded());
+    if (!frame || frame->isEmpty()) {
+        return;
+    }
+
+    QVector<ApiTraceCall*>::const_iterator itr;
+    QVector<ApiTraceCall*> calls = frame->calls();
+
+    itr = calls.constBegin();
+    while (itr != calls.constEnd()) {
+        ApiTraceCall *call = *itr;
+        QModelIndex idx = m_proxyModel->indexForCall(call);
+        if (idx.isValid()) {
+            m_ui.callView->setCurrentIndex(idx);
+            break;
+        }
+        ++itr;
+    }
+}
+
+void MainWindow::slotFoundFrameEnd(ApiTraceFrame *frame)
+{
+    Q_ASSERT(frame->isLoaded());
+    if (!frame || frame->isEmpty()) {
+        return;
+    }
+    QVector<ApiTraceCall*>::const_iterator itr;
+    QVector<ApiTraceCall*> calls = frame->calls();
+
+    itr = calls.constEnd();
+    do {
+        --itr;
+        ApiTraceCall *call = *itr;
+        QModelIndex idx = m_proxyModel->indexForCall(call);
+        if (idx.isValid()) {
+            m_ui.callView->setCurrentIndex(idx);
+            break;
+        }
+    } while (itr != calls.constBegin());
+}
+
+void MainWindow::slotJumpToResult(ApiTraceCall *call)
+{
+    QModelIndex index = m_proxyModel->indexForCall(call);
+    if (index.isValid()) {
+        m_ui.callView->setCurrentIndex(index);
+    } else {
+        statusBar()->showMessage(tr("Call has been filtered out."));
+    }
+}
+
 #include "mainwindow.moc"
index 5cb2e767eacaa0342a1d21d3307e96d6ac7cdf4c..0ae8ab78e9315c619aa99d843b32f27c873e0ea5 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "ui_mainwindow.h"
 
+#include "apitrace.h"
+
 #include <QMainWindow>
 #include <QProcess>
 
@@ -19,7 +21,7 @@ class QModelIndex;
 class QProgressBar;
 class QTreeWidgetItem;
 class QUrl;
-struct RetraceError;
+struct ApiTraceError;
 class Retracer;
 class SearchWidget;
 class ShadersSourceWidget;
@@ -43,9 +45,10 @@ private slots:
     void replayStart();
     void replayStop();
     void replayFinished(const QString &output);
-    void replayStateFound(const ApiTraceState &state);
+    void replayStateFound(ApiTraceState *state);
     void replayError(const QString &msg);
     void startedLoadingTrace();
+    void loadProgess(int percent);
     void finishedLoadingTrace();
     void lookupState();
     void showSettings();
@@ -68,8 +71,13 @@ private slots:
     void slotGoFrameStart();
     void slotGoFrameEnd();
     void slotTraceChanged(ApiTraceCall *call);
-    void slotRetraceErrors(const QList<RetraceError> &errors);
+    void slotRetraceErrors(const QList<ApiTraceError> &errors);
     void slotErrorSelected(QTreeWidgetItem *current);
+    void slotSearchResult(ApiTrace::SearchResult result,
+                          ApiTraceCall *call);
+    void slotFoundFrameStart(ApiTraceFrame *frame);
+    void slotFoundFrameEnd(ApiTraceFrame *frame);
+    void slotJumpToResult(ApiTraceCall *call);
 
 private:
     void initObjects();
@@ -77,9 +85,17 @@ private:
     void newTraceFile(const QString &fileName);
     void replayTrace(bool dumpState);
     void fillStateForFrame();
+
+    /* there's a difference between selected frame/call and
+     * current call/frame. the former implies actual selection
+     * the latter might be just a highlight, e.g. during searching
+     */
+    ApiTraceFrame *selectedFrame() const;
+    ApiTraceCall *selectedCall() const;
     ApiTraceFrame *currentFrame() const;
     ApiTraceCall *currentCall() const;
 
+
 private:
     Ui_MainWindow m_ui;
     ShadersSourceWidget *m_sourcesWidget;
index 98a4db220e7d203d320774ec790fce87ff8a8de2..251028ce5ab316066dcfd8baac94a6376a91eb5b 100644 (file)
@@ -98,10 +98,10 @@ void Retracer::run()
             this, SIGNAL(finished(const QString&)));
     connect(retrace, SIGNAL(error(const QString&)),
             this, SIGNAL(error(const QString&)));
-    connect(retrace, SIGNAL(foundState(const ApiTraceState&)),
-            this, SIGNAL(foundState(const ApiTraceState&)));
-    connect(retrace, SIGNAL(retraceErrors(const QList<RetraceError>&)),
-            this, SIGNAL(retraceErrors(const QList<RetraceError>&)));
+    connect(retrace, SIGNAL(foundState(ApiTraceState*)),
+            this, SIGNAL(foundState(ApiTraceState*)));
+    connect(retrace, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
+            this, SIGNAL(retraceErrors(const QList<ApiTraceError>&)));
 
     retrace->start();
 
@@ -155,7 +155,7 @@ void RetraceProcess::replayFinished()
     if (m_captureState) {
         bool ok = false;
         QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
-        ApiTraceState state(parsedJson);
+        ApiTraceState *state = new ApiTraceState(parsedJson);
         emit foundState(state);
         msg = tr("State fetched.");
     } else {
@@ -163,11 +163,11 @@ void RetraceProcess::replayFinished()
     }
 
     QStringList errorLines = errStr.split('\n');
-    QList<RetraceError> errors;
+    QList<ApiTraceError> errors;
     QRegExp regexp("(^\\d+): +(\\b\\w+\\b): (.+$)");
     foreach(QString line, errorLines) {
         if (regexp.indexIn(line) != -1) {
-            RetraceError error;
+            ApiTraceError error;
             error.callIndex = regexp.cap(1).toInt();
             error.type = regexp.cap(2);
             error.message = regexp.cap(3);
@@ -190,14 +190,14 @@ void RetraceProcess::replayError(QProcess::ProcessError err)
         tr("Couldn't execute the replay file '%1'").arg(m_fileName));
 }
 
-Q_DECLARE_METATYPE(QList<RetraceError>);
+Q_DECLARE_METATYPE(QList<ApiTraceError>);
 RetraceProcess::RetraceProcess(QObject *parent)
     : QObject(parent)
 {
     m_process = new QProcess(this);
     m_jsonParser = new QJson::Parser();
 
-    qRegisterMetaType<QList<RetraceError> >();
+    qRegisterMetaType<QList<ApiTraceError> >();
 
     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
             this, SLOT(replayFinished()));
index 1b5a4bd04313ed0ed3406eb42588397583bdc60f..4a43c261d7ec10ad1442b909e7414aa63866dd2b 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef RETRACER_H
 #define RETRACER_H
 
+#include "apitracecall.h"
+
 #include <QThread>
 #include <QProcess>
 
@@ -9,12 +11,6 @@ namespace QJson {
     class Parser;
 }
 
-struct RetraceError {
-    int callIndex;
-    QString type;
-    QString message;
-};
-
 /* internal class used by the retracer to run
  * in the thread */
 class RetraceProcess : public QObject
@@ -48,8 +44,8 @@ public slots:
 signals:
     void finished(const QString &output);
     void error(const QString &msg);
-    void foundState(const ApiTraceState &state);
-    void retraceErrors(const QList<RetraceError> &errors);
+    void foundState(ApiTraceState *state);
+    void retraceErrors(const QList<ApiTraceError> &errors);
 
 private slots:
     void replayFinished();
@@ -89,9 +85,9 @@ public:
 
 signals:
     void finished(const QString &output);
-    void foundState(const ApiTraceState &state);
+    void foundState(ApiTraceState *state);
     void error(const QString &msg);
-    void retraceErrors(const QList<RetraceError> &errors);
+    void retraceErrors(const QList<ApiTraceError> &errors);
 
 protected:
     virtual void run();
index d7f6906c7e136b7653d18084d487522ebf764b86..d5f4d6b0ce5d1461b753b91b6a069792a45563a4 100644 (file)
@@ -1,6 +1,8 @@
 #include "saverthread.h"
 
 #include "trace_writer.hpp"
+#include "trace_model.hpp"
+#include "trace_parser.hpp"
 
 #include <QFile>
 #include <QHash>
@@ -8,7 +10,7 @@
 
 #include <QDebug>
 
-
+#if 0
 static Trace::FunctionSig *
 createFunctionSig(ApiTraceCall *call, unsigned id)
 {
@@ -162,7 +164,7 @@ writeValue(Trace::Writer &writer, const QVariant &var, unsigned &id)
     default:
         if (type == arrayType) {
             ApiArray array = var.value<ApiArray>();
-            QList<QVariant> vals = array.values();
+            QVector<QVariant> vals = array.values();
             writer.beginArray(vals.count());
             foreach(QVariant el, vals) {
                 writer.beginElement();
@@ -203,54 +205,164 @@ writeValue(Trace::Writer &writer, const QVariant &var, unsigned &id)
         }
     }
 }
+#endif
+
+class EditVisitor : public Trace::Visitor
+{
+public:
+    EditVisitor(const QVariant &variant)
+        : m_variant(variant),
+          m_editedValue(0)
+    {}
+    virtual void visit(Trace::Null *val)
+    {
+        m_editedValue = val;
+    }
+
+    virtual void visit(Trace::Bool *node)
+    {
+//        Q_ASSERT(m_variant.userType() == QVariant::Bool);
+        bool var = m_variant.toBool();
+        m_editedValue = new Trace::Bool(var);
+    }
+
+    virtual void visit(Trace::SInt *node)
+    {
+//        Q_ASSERT(m_variant.userType() == QVariant::Int);
+        m_editedValue = new Trace::SInt(m_variant.toInt());
+    }
+
+    virtual void visit(Trace::UInt *node)
+    {
+//        Q_ASSERT(m_variant.userType() == QVariant::UInt);
+        m_editedValue = new Trace::SInt(m_variant.toUInt());
+    }
+
+    virtual void visit(Trace::Float *node)
+    {
+        m_editedValue = new Trace::Float(m_variant.toFloat());
+    }
+
+    virtual void visit(Trace::String *node)
+    {
+        QString str = m_variant.toString();
+        m_editedValue = new Trace::String(str.toLocal8Bit().constData());
+    }
+
+    virtual void visit(Trace::Enum *e)
+    {
+        m_editedValue = e;
+    }
+
+    virtual void visit(Trace::Bitmask *bitmask)
+    {
+        m_editedValue = bitmask;
+    }
+
+    virtual void visit(Trace::Struct *str)
+    {
+        m_editedValue = str;
+    }
+
+    virtual void visit(Trace::Array *array)
+    {
+        ApiArray apiArray = m_variant.value<ApiArray>();
+        QVector<QVariant> vals = apiArray.values();
+
+        Trace::Array *newArray = new Trace::Array(vals.count());
+        for (int i = 0; i < vals.count(); ++i) {
+            EditVisitor visitor(vals[i]);
+
+            array->values[i]->visit(visitor);
+            if (array->values[i] == visitor.value()) {
+                //non-editabled
+                delete newArray;
+                m_editedValue = array;
+                return;
+            }
+
+            newArray->values.push_back(visitor.value());
+        }
+        m_editedValue = newArray;
+    }
+
+    virtual void visit(Trace::Blob *blob)
+    {
+        m_editedValue = blob;
+    }
+
+    virtual void visit(Trace::Pointer *ptr)
+    {
+        m_editedValue = ptr;
+    }
+
+    Trace::Value *value() const
+    {
+        return m_editedValue;
+    }
+private:
+    QVariant m_variant;
+    Trace::Value *m_editedValue;
+};
+
+static void
+overwriteValue(Trace::Call *call, const QVariant &val, int index)
+{
+    EditVisitor visitor(val);
+    Trace::Value *origValue = call->args[index];
+    origValue->visit(visitor);
+
+    if (visitor.value() && origValue != visitor.value()) {
+        delete origValue;
+        call->args[index] = visitor.value();
+    }
+}
 
 SaverThread::SaverThread(QObject *parent)
     : QThread(parent)
 {
 }
 
-void SaverThread::saveFile(const QString &fileName,
-                           const QList<ApiTraceCall*> &calls)
+void SaverThread::saveFile(const QString &writeFileName,
+                           const QString &readFileName,
+                           const QSet<ApiTraceCall*> &editedCalls)
 {
-    m_fileName = fileName;
-    m_calls = calls;
+    m_writeFileName = writeFileName;
+    m_readFileName = readFileName;
+    m_editedCalls = editedCalls;
     start();
 }
 
 void SaverThread::run()
 {
-    unsigned id = 0;
-    qDebug() << "Saving  : " << m_fileName;
+    qDebug() << "Saving  " << m_readFileName
+             << ", to " << m_writeFileName;
+    QMap<int, ApiTraceCall*> callIndexMap;
+
+    foreach(ApiTraceCall *call, m_editedCalls) {
+        callIndexMap.insert(call->index(), call);
+    }
+
     Trace::Writer writer;
-    writer.open(m_fileName.toLocal8Bit());
-    for (int i = 0; i < m_calls.count(); ++i) {
-        ApiTraceCall *call = m_calls[i];
-        Trace::FunctionSig *funcSig = createFunctionSig(call, ++id);
-        unsigned callNo = writer.beginEnter(funcSig);
-        {
-            //args
-            QVariantList vars = call->arguments();
-            int index = 0;
-            foreach(QVariant var, vars) {
-                writer.beginArg(index++);
-                writeValue(writer, var, ++id);
-                writer.endArg();
-            }
-        }
-        writer.endEnter();
-        writer.beginLeave(callNo);
-        {
-            QVariant ret = call->returnValue();
-            if (!ret.isNull()) {
-                writer.beginReturn();
-                writeValue(writer, ret, ++id);
-                writer.endReturn();
+    writer.open(m_writeFileName.toLocal8Bit());
+
+    Trace::Parser parser;
+    parser.open(m_readFileName.toLocal8Bit());
+
+    Trace::Call *call;
+    while ((call = parser.parse_call())) {
+        if (callIndexMap.contains(call->no)) {
+            QVector<QVariant> values = callIndexMap[call->no]->editedValues();
+            for (int i = 0; i < values.count(); ++i) {
+                const QVariant &val = values[i];
+                overwriteValue(call, val, i);
             }
+            writer.writeCall(call);
+        } else {
+            writer.writeCall(call);
         }
-        writer.endLeave();
-
-        deleteFunctionSig(funcSig);
     }
+
     writer.close();
 
     emit traceSaved();
index 5bea5b7581fc8d07a3857da494ddeaa74e7dea08..e8c6889f2c80c5cda6a9933f18970889d9713729 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "apitrace.h"
 #include <QThread>
-#include <QList>
+#include <QVector>
 
 class ApiTraceCall;
 class ApiTraceFrame;
@@ -16,8 +16,9 @@ public:
     SaverThread(QObject *parent=0);
 
 public slots:
-    void saveFile(const QString &fileName,
-                  const QList<ApiTraceCall*> &calls);
+    void saveFile(const QString &saveFileName,
+                  const QString &readFileName,
+                  const QSet<ApiTraceCall*> &editedCalls);
 
 signals:
     void traceSaved();
@@ -26,8 +27,9 @@ protected:
     virtual void run();
 
 private:
-    QString m_fileName;
-    QList<ApiTraceCall*> m_calls;
+    QString m_readFileName;
+    QString m_writeFileName;
+    QSet<ApiTraceCall*> m_editedCalls;
 };
 
 
diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp
new file mode 100644 (file)
index 0000000..0fee815
--- /dev/null
@@ -0,0 +1,496 @@
+#include "traceloader.h"
+
+#include "apitrace.h"
+#include <QDebug>
+#include <QFile>
+
+#define FRAMES_TO_CACHE 100
+
+static ApiTraceCall *
+apiCallFromTraceCall(const Trace::Call *call,
+                     const QHash<QString, QUrl> &helpHash,
+                     ApiTraceFrame *frame,
+                     TraceLoader *loader)
+{
+    ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+
+    apiCall->setHelpUrl(helpHash.value(apiCall->name()));
+
+    return apiCall;
+}
+
+TraceLoader::TraceLoader(QObject *parent)
+    : QObject(parent),
+      m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
+{
+}
+
+TraceLoader::~TraceLoader()
+{
+    m_parser.close();
+    qDeleteAll(m_signatures);
+    qDeleteAll(m_enumSignatures);
+}
+
+void TraceLoader::loadTrace(const QString &filename)
+{
+    if (m_helpHash.isEmpty()) {
+        loadHelpFile();
+    }
+
+    if (!m_parser.open(filename.toLatin1())) {
+        qDebug() << "error: failed to open " << filename;
+        return;
+    }
+
+    emit startedParsing();
+
+    if (m_parser.supportsOffsets()) {
+        scanTrace();
+    } else {
+        //Load the entire file into memory
+        parseTrace();
+    }
+
+    emit finishedParsing();
+}
+
+void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
+{
+    fetchFrameContents(currentFrame);
+}
+
+void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
+{
+    m_frameMarker = marker;
+}
+
+bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
+{
+    std::string name = call->name();
+
+    switch (m_frameMarker) {
+    case ApiTrace::FrameMarker_SwapBuffers:
+        return  name.find("SwapBuffers") != std::string::npos ||
+                name == "CGLFlushDrawable" ||
+                name == "glFrameTerminatorGREMEDY";
+        break;
+    case ApiTrace::FrameMarker_Flush:
+        return name == "glFlush";
+        break;
+    case ApiTrace::FrameMarker_Finish:
+        return name == "glFinish";
+        break;
+    case ApiTrace::FrameMarker_Clear:
+        return name == "glClear";
+        break;
+    }
+    return false;
+}
+
+int TraceLoader::numberOfFrames() const
+{
+    return m_frameBookmarks.size();
+}
+
+int TraceLoader::numberOfCallsInFrame(int frameIdx) const
+{
+    if (frameIdx > m_frameBookmarks.size()) {
+        return 0;
+    }
+    FrameBookmarks::const_iterator itr =
+            m_frameBookmarks.find(frameIdx);
+    return itr->numberOfCalls;
+}
+
+void TraceLoader::loadHelpFile()
+{
+    QFile file(":/resources/glreference.tsv");
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        QString line;
+        while (!file.atEnd()) {
+            line = file.readLine();
+            QString function = line.section('\t', 0, 0).trimmed();
+            QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
+            //qDebug()<<"function = "<<function<<", url = "<<url.toString();
+            m_helpHash.insert(function, url);
+        }
+    } else {
+        qWarning() << "Couldn't open reference file "
+                   << file.fileName();
+    }
+    file.close();
+}
+
+void TraceLoader::scanTrace()
+{
+    QList<ApiTraceFrame*> frames;
+    ApiTraceFrame *currentFrame = 0;
+
+    Trace::Call *call;
+    Trace::ParseBookmark startBookmark;
+    int numOfFrames = 0;
+    int numOfCalls = 0;
+    int lastPercentReport = 0;
+
+    m_parser.getBookmark(startBookmark);
+
+    while ((call = m_parser.scan_call())) {
+        ++numOfCalls;
+
+        if (isCallAFrameMarker(call)) {
+            FrameBookmark frameBookmark(startBookmark);
+            frameBookmark.numberOfCalls = numOfCalls;
+
+            currentFrame = new ApiTraceFrame();
+            currentFrame->number = numOfFrames;
+            currentFrame->setNumChildren(numOfCalls);
+            currentFrame->setLastCallIndex(call->no);
+            frames.append(currentFrame);
+
+            m_createdFrames.append(currentFrame);
+            m_frameBookmarks[numOfFrames] = frameBookmark;
+            ++numOfFrames;
+
+            if (m_parser.percentRead() - lastPercentReport >= 5) {
+                emit parsed(m_parser.percentRead());
+                lastPercentReport = m_parser.percentRead();
+            }
+            m_parser.getBookmark(startBookmark);
+            numOfCalls = 0;
+        }
+        delete call;
+    }
+
+    if (numOfCalls) {
+        //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
+        FrameBookmark frameBookmark(startBookmark);
+        frameBookmark.numberOfCalls = numOfCalls;
+
+        currentFrame = new ApiTraceFrame();
+        currentFrame->number = numOfFrames;
+        currentFrame->setNumChildren(numOfCalls);
+        frames.append(currentFrame);
+
+        m_createdFrames.append(currentFrame);
+        m_frameBookmarks[numOfFrames] = frameBookmark;
+        ++numOfFrames;
+    }
+
+    emit parsed(100);
+
+    emit framesLoaded(frames);
+}
+
+void TraceLoader::parseTrace()
+{
+    QList<ApiTraceFrame*> frames;
+    ApiTraceFrame *currentFrame = 0;
+    int frameCount = 0;
+    QVector<ApiTraceCall*> calls;
+    quint64 binaryDataSize = 0;
+
+    int lastPercentReport = 0;
+
+    Trace::Call *call = m_parser.parse_call();
+    while (call) {
+        //std::cout << *call;
+        if (!currentFrame) {
+            currentFrame = new ApiTraceFrame();
+            currentFrame->number = frameCount;
+            ++frameCount;
+        }
+        ApiTraceCall *apiCall =
+                apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
+        calls.append(apiCall);
+        if (apiCall->hasBinaryData()) {
+            QByteArray data =
+                    apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+            binaryDataSize += data.size();
+        }
+        if (ApiTrace::isCallAFrameMarker(apiCall,
+                                         m_frameMarker)) {
+            calls.squeeze();
+            currentFrame->setCalls(calls, binaryDataSize);
+            calls.clear();
+            frames.append(currentFrame);
+            currentFrame = 0;
+            binaryDataSize = 0;
+            if (frames.count() >= FRAMES_TO_CACHE) {
+                emit framesLoaded(frames);
+                frames.clear();
+            }
+            if (m_parser.percentRead() - lastPercentReport >= 5) {
+                emit parsed(m_parser.percentRead());
+                lastPercentReport = m_parser.percentRead();
+            }
+        }
+        delete call;
+        call = m_parser.parse_call();
+    }
+
+    //last frames won't have markers
+    //  it's just a bunch of Delete calls for every object
+    //  after the last SwapBuffers
+    if (currentFrame) {
+        calls.squeeze();
+        currentFrame->setCalls(calls, binaryDataSize);
+        frames.append(currentFrame);
+        currentFrame = 0;
+    }
+    if (frames.count()) {
+        emit framesLoaded(frames);
+    }
+}
+
+
+ApiTraceCallSignature * TraceLoader::signature(unsigned id)
+{
+    if (id >= m_signatures.count()) {
+        m_signatures.resize(id + 1);
+        return NULL;
+    } else {
+        return m_signatures[id];
+    }
+}
+
+void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
+{
+    m_signatures[id] = signature;
+}
+
+ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
+{
+    if (id >= m_enumSignatures.count()) {
+        m_enumSignatures.resize(id + 1);
+        return NULL;
+    } else {
+        return m_enumSignatures[id];
+    }
+}
+
+void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
+{
+    m_enumSignatures[id] = signature;
+}
+
+void TraceLoader::searchNext(int startFrame,
+                             const QString &str,
+                             Qt::CaseSensitivity sensitivity)
+{
+    Q_ASSERT(m_parser.supportsOffsets());
+    if (m_parser.supportsOffsets()) {
+        const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
+        m_parser.setBookmark(frameBookmark.start);
+        Trace::Call *call = 0;
+        while ((call = m_parser.parse_call())) {
+
+            if (callContains(call, str, sensitivity)) {
+                unsigned frameIdx = callInFrame(call->no);
+                ApiTraceFrame *frame = m_createdFrames[frameIdx];
+                const QVector<ApiTraceCall*> calls =
+                        fetchFrameContents(frame);
+                for (int i = 0; i < calls.count(); ++i) {
+                    if (calls[i]->index() == call->no) {
+                        emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
+                        break;
+                    }
+                }
+                delete call;
+                return;
+            }
+
+            delete call;
+        }
+    }
+    emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+}
+
+void TraceLoader::searchPrev(int startFrame,
+                             const QString &str,
+                             Qt::CaseSensitivity sensitivity)
+{
+    Q_ASSERT(m_parser.supportsOffsets());
+    if (m_parser.supportsOffsets()) {
+        Trace::Call *call = 0;
+        QList<Trace::Call*> frameCalls;
+        int frameIdx = startFrame;
+
+        const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+        int numCallsToParse = frameBookmark.numberOfCalls;
+        m_parser.setBookmark(frameBookmark.start);
+
+        while ((call = m_parser.parse_call())) {
+
+            frameCalls.append(call);
+            --numCallsToParse;
+
+            if (numCallsToParse == 0) {
+                bool foundCall = searchCallsBackwards(frameCalls,
+                                                      frameIdx,
+                                                      str, sensitivity);
+
+                qDeleteAll(frameCalls);
+                frameCalls.clear();
+                if (foundCall) {
+                    return;
+                }
+
+                --frameIdx;
+
+                if (frameIdx >= 0) {
+                    const FrameBookmark &frameBookmark =
+                            m_frameBookmarks[frameIdx];
+                    m_parser.setBookmark(frameBookmark.start);
+                    numCallsToParse = frameBookmark.numberOfCalls;
+                }
+            }
+        }
+    }
+    emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+}
+
+bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
+                                       int frameIdx,
+                                       const QString &str,
+                                       Qt::CaseSensitivity sensitivity)
+{
+    for (int i = calls.count() - 1; i >= 0; --i) {
+        Trace::Call *call = calls[i];
+        if (callContains(call, str, sensitivity)) {
+            ApiTraceFrame *frame = m_createdFrames[frameIdx];
+            const QVector<ApiTraceCall*> apiCalls =
+                    fetchFrameContents(frame);
+            for (int i = 0; i < apiCalls.count(); ++i) {
+                if (apiCalls[i]->index() == call->no) {
+                    emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
+                    break;
+                }
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+int TraceLoader::callInFrame(int callIdx) const
+{
+    unsigned numCalls = 0;
+
+    for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
+        const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+        unsigned firstCall = numCalls;
+        unsigned endCall = numCalls + frameBookmark.numberOfCalls;
+        if (firstCall <= callIdx && endCall > callIdx) {
+            return frameIdx;
+        }
+        numCalls = endCall;
+    }
+    Q_ASSERT(!"call not in the trace");
+    return 0;
+}
+
+bool TraceLoader::callContains(Trace::Call *call,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity)
+{
+    /*
+     * FIXME: do string comparison directly on Trace::Call
+     */
+    ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
+                                                 0, this);
+    bool result = apiCall->contains(str, sensitivity);
+    delete apiCall;
+    return result;
+}
+
+QVector<ApiTraceCall*>
+TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
+{
+    Q_ASSERT(currentFrame);
+
+    if (currentFrame->isLoaded()) {
+        return currentFrame->calls();
+    }
+
+    if (m_parser.supportsOffsets()) {
+        unsigned frameIdx = currentFrame->number;
+        int numOfCalls = numberOfCallsInFrame(frameIdx);
+
+        if (numOfCalls) {
+            quint64 binaryDataSize = 0;
+            QVector<ApiTraceCall*> calls(numOfCalls);
+            const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+
+            m_parser.setBookmark(frameBookmark.start);
+
+            Trace::Call *call;
+            int parsedCalls = 0;
+            while ((call = m_parser.parse_call())) {
+                ApiTraceCall *apiCall =
+                    apiCallFromTraceCall(call, m_helpHash,
+                                         currentFrame, this);
+                calls[parsedCalls] = apiCall;
+                Q_ASSERT(calls[parsedCalls]);
+                if (apiCall->hasBinaryData()) {
+                    QByteArray data =
+                        apiCall->arguments()[
+                            apiCall->binaryDataIndex()].toByteArray();
+                    binaryDataSize += data.size();
+                }
+
+                ++parsedCalls;
+
+                delete call;
+
+                if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
+                    break;
+                }
+
+            }
+            assert(parsedCalls == numOfCalls);
+            Q_ASSERT(parsedCalls == calls.size());
+            calls.squeeze();
+
+            Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
+            emit frameContentsLoaded(currentFrame,
+                                     calls, binaryDataSize);
+            return calls;
+        }
+    }
+    return QVector<ApiTraceCall*>();
+}
+
+void TraceLoader::findFrameStart(ApiTraceFrame *frame)
+{
+    if (!frame->isLoaded()) {
+        loadFrame(frame);
+    }
+    emit foundFrameStart(frame);
+}
+
+void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
+{
+    if (!frame->isLoaded()) {
+        loadFrame(frame);
+    }
+    emit foundFrameEnd(frame);
+}
+
+void TraceLoader::findCallIndex(int index)
+{
+    int frameIdx = callInFrame(index);
+    ApiTraceFrame *frame = m_createdFrames[frameIdx];
+    QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
+    QVector<ApiTraceCall*>::const_iterator itr;
+    ApiTraceCall *call = 0;
+    for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
+        if ((*itr)->index() == index) {
+            call = *itr;
+        }
+    }
+    Q_ASSERT(call);
+    emit foundCallIndex(call);
+}
+
+#include "traceloader.moc"
diff --git a/gui/traceloader.h b/gui/traceloader.h
new file mode 100644 (file)
index 0000000..4b88ec6
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef TRACELOADER_H
+#define TRACELOADER_H
+
+
+#include "apitrace.h"
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+
+class TraceLoader : public QObject
+{
+    Q_OBJECT
+public:
+    TraceLoader(QObject *parent=0);
+    ~TraceLoader();
+
+
+    ApiTraceCallSignature *signature(unsigned id);
+    void addSignature(unsigned id, ApiTraceCallSignature *signature);
+
+    ApiTraceEnumSignature *enumSignature(unsigned id);
+    void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature);
+
+public slots:
+    void loadTrace(const QString &filename);
+    void loadFrame(ApiTraceFrame *frame);
+    void setFrameMarker(ApiTrace::FrameMarker marker);
+    void searchNext(int startFrame,
+                    const QString &str,
+                    Qt::CaseSensitivity sensitivity);
+    void searchPrev(int startFrame,
+                    const QString &str,
+                    Qt::CaseSensitivity sensitivity);
+    void findFrameStart(ApiTraceFrame *frame);
+    void findFrameEnd(ApiTraceFrame *frame);
+    void findCallIndex(int index);
+
+signals:
+    void startedParsing();
+    void parsed(int percent);
+    void finishedParsing();
+
+    void framesLoaded(const QList<ApiTraceFrame*> &frames);
+    void frameContentsLoaded(ApiTraceFrame *frame,
+                             const QVector<ApiTraceCall*> &calls,
+                             quint64 binaryDataSize);
+
+    void searchResult(ApiTrace::SearchResult result, ApiTraceCall *call);
+    void foundFrameStart(ApiTraceFrame *frame);
+    void foundFrameEnd(ApiTraceFrame *frame);
+    void foundCallIndex(ApiTraceCall *call);
+private:
+    struct FrameBookmark {
+        FrameBookmark()
+            : numberOfCalls(0)
+        {}
+        FrameBookmark(const Trace::ParseBookmark &s)
+            : start(s),
+              numberOfCalls(0)
+        {}
+
+        Trace::ParseBookmark start;
+        int numberOfCalls;
+    };
+    bool isCallAFrameMarker(const Trace::Call *call) const;
+    int numberOfFrames() const;
+    int numberOfCallsInFrame(int frameIdx) const;
+
+    void loadHelpFile();
+    void scanTrace();
+    void parseTrace();
+
+    int callInFrame(int callIdx) const;
+    bool callContains(Trace::Call *call,
+                      const QString &str,
+                      Qt::CaseSensitivity sensitivity);
+     QVector<ApiTraceCall*> fetchFrameContents(ApiTraceFrame *frame);
+     bool searchCallsBackwards(const QList<Trace::Call*> &calls,
+                               int frameIdx,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity);
+
+private:
+    Trace::Parser m_parser;
+    QString m_fileName;
+    ApiTrace::FrameMarker m_frameMarker;
+
+    typedef QMap<int, FrameBookmark> FrameBookmarks;
+    FrameBookmarks m_frameBookmarks;
+    QList<ApiTraceFrame*> m_createdFrames;
+
+    QHash<QString, QUrl> m_helpHash;
+
+    QVector<ApiTraceCallSignature*> m_signatures;
+    QVector<ApiTraceEnumSignature*> m_enumSignatures;
+};
+
+#endif
diff --git a/image.cpp b/image.cpp
deleted file mode 100644 (file)
index 4da9c13..0000000
--- a/image.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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 <assert.h>
-#include <math.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-double Image::compare(Image &ref)
-{
-    if (width != ref.width ||
-        height != ref.height ||
-        channels != ref.channels) {
-        return 0.0;
-    }
-
-    const unsigned char *pSrc = start();
-    const unsigned char *pRef = ref.start();
-
-    assert(channels >= 3);
-
-    unsigned long long error = 0;
-    for (unsigned y = 0; y < height; ++y) {
-        for (unsigned  x = 0; x < width; ++x) {
-            // FIXME: Ignore alpha channel until we are able to pick a visual
-            // that matches the traces
-            for (unsigned  c = 0; c < 3; ++c) {
-                int delta = pSrc[x*channels + c] - pRef[x*channels + c];
-                error += delta*delta;
-            }
-        }
-
-        pSrc += stride();
-        pRef += ref.stride();
-    }
-
-    double numerator = error*2 + 1;
-    double denominator = height*width*3ULL*255ULL*255ULL*2;
-    double quotient = numerator/denominator;
-
-    // Precision in bits
-    double precision = -log(quotient)/log(2.0);
-
-    return precision;
-}
-
-
-} /* namespace Image */
diff --git a/image.hpp b/image.hpp
deleted file mode 100644 (file)
index 44fc4f4..0000000
--- a/image.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Image I/O.
- */
-
-#ifndef _IMAGE_HPP_
-#define _IMAGE_HPP_
-
-
-#include <fstream>
-
-
-namespace Image {
-
-
-class Image {
-public:
-    unsigned width;
-    unsigned height;
-    unsigned channels;
-
-    // Flipped vertically or not
-    bool flipped;
-
-    // Pixels in RGBA format
-    unsigned char *pixels;
-
-    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
-        width(w),
-        height(h),
-        channels(c),
-        flipped(f),
-        pixels(new unsigned char[h*w*c])
-    {}
-
-    inline ~Image() {
-        delete [] pixels;
-    }
-
-    inline unsigned char *start(void) {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline const unsigned char *start(void) const {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline unsigned char *end(void) {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline const unsigned char *end(void) const {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline signed stride(void) const {
-        return flipped ? -width*channels : width*channels;
-    }
-
-    bool writeBMP(const char *filename) const;
-
-    void writePNM(std::ostream &os) const;
-
-    inline bool writePNM(const char *filename) const {
-        std::ofstream os(filename, std::ofstream::binary);
-        if (!os) {
-            return false;
-        }
-        writePNM(os);
-        return true;
-    }
-
-    bool writePNG(const char *filename) const;
-
-    double compare(Image &ref);
-};
-
-bool writePixelsToBuffer(unsigned char *pixels,
-                         unsigned w, unsigned h, unsigned numChannels,
-                         bool flipped,
-                         char **buffer,
-                         int *size);
-
-Image *
-readPNG(const char *filename);
-
-
-} /* namespace Image */
-
-
-#endif /* _IMAGE_HPP_ */
diff --git a/image_bmp.cpp b/image_bmp.cpp
deleted file mode 100644 (file)
index 346f39a..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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 <assert.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-#pragma pack(push,2)
-struct FileHeader {
-    uint16_t bfType;
-    uint32_t bfSize;
-    uint16_t bfReserved1;
-    uint16_t bfReserved2;
-    uint32_t bfOffBits;
-};
-#pragma pack(pop)
-
-struct InfoHeader {
-    uint32_t biSize;
-    int32_t biWidth;
-    int32_t biHeight;
-    uint16_t biPlanes;
-    uint16_t biBitCount;
-    uint32_t biCompression;
-    uint32_t biSizeImage;
-    int32_t biXPelsPerMeter;
-    int32_t biYPelsPerMeter;
-    uint32_t biClrUsed;
-    uint32_t biClrImportant;
-};
-
-struct Pixel {
-    uint8_t rgbBlue;
-    uint8_t rgbGreen;
-    uint8_t rgbRed;
-    uint8_t rgbAlpha;
-};
-
-
-bool
-Image::writeBMP(const char *filename) const {
-    assert(channels == 4);
-
-    struct FileHeader bmfh;
-    struct InfoHeader bmih;
-    unsigned x, y;
-
-    bmfh.bfType = 0x4d42;
-    bmfh.bfSize = 14 + 40 + height*width*4;
-    bmfh.bfReserved1 = 0;
-    bmfh.bfReserved2 = 0;
-    bmfh.bfOffBits = 14 + 40;
-
-    bmih.biSize = 40;
-    bmih.biWidth = width;
-    bmih.biHeight = height;
-    bmih.biPlanes = 1;
-    bmih.biBitCount = 32;
-    bmih.biCompression = 0;
-    bmih.biSizeImage = height*width*4;
-    bmih.biXPelsPerMeter = 0;
-    bmih.biYPelsPerMeter = 0;
-    bmih.biClrUsed = 0;
-    bmih.biClrImportant = 0;
-
-    std::ofstream stream(filename, std::ofstream::binary);
-
-    if (!stream) {
-        return false;
-    }
-
-    stream.write((const char *)&bmfh, 14);
-    stream.write((const char *)&bmih, 40);
-
-    unsigned stride = width*4;
-
-    if (flipped) {
-        for (y = 0; y < height; ++y) {
-            const unsigned char *ptr = pixels + y * stride;
-            for (x = 0; x < width; ++x) {
-                struct Pixel pixel;
-                pixel.rgbRed   = ptr[x*4 + 0];
-                pixel.rgbGreen = ptr[x*4 + 1];
-                pixel.rgbBlue  = ptr[x*4 + 2];
-                pixel.rgbAlpha = ptr[x*4 + 3];
-                stream.write((const char *)&pixel, 4);
-            }
-        }
-    } else {
-        y = height;
-        while (y--) {
-            const unsigned char *ptr = pixels + y * stride;
-            for (x = 0; x < width; ++x) {
-                struct Pixel pixel;
-                pixel.rgbRed   = ptr[x*4 + 0];
-                pixel.rgbGreen = ptr[x*4 + 1];
-                pixel.rgbBlue  = ptr[x*4 + 2];
-                pixel.rgbAlpha = ptr[x*4 + 3];
-                stream.write((const char *)&pixel, 4);
-            }
-        }
-    }
-
-    stream.close();
-
-    return true;
-}
-
-
-} /* namespace Image */
diff --git a/image_png.cpp b/image_png.cpp
deleted file mode 100644 (file)
index fd22213..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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 <zlib.h>
-#include <png.h>
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <fstream>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-bool
-Image::writePNG(const char *filename) const {
-    FILE *fp;
-    png_structp png_ptr;
-    png_infop info_ptr;
-
-    fp = fopen(filename, "wb");
-    if (!fp)
-        goto no_fp;
-
-    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_ptr)
-        goto no_png;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr) {
-        png_destroy_write_struct(&png_ptr,  NULL);
-        goto no_png;
-    }
-
-    if (setjmp(png_jmpbuf(png_ptr))) {
-        png_destroy_write_struct(&png_ptr, &info_ptr);
-        goto no_png;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    int color_type;
-    switch (channels) {
-    case 4:
-        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-        break;
-    case 3:
-        color_type = PNG_COLOR_TYPE_RGB;
-        break;
-    case 2:
-        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
-        break;
-    case 1:
-        color_type = PNG_COLOR_TYPE_GRAY;
-        break;
-    default:
-        assert(0);
-        return false;
-    }
-
-    png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
-        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
-
-    png_write_info(png_ptr, info_ptr);
-
-    if (!flipped) {
-        for (unsigned y = 0; y < height; ++y) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    } else {
-        unsigned y = height;
-        while (y--) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    }
-
-    png_write_end(png_ptr, info_ptr);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    fclose(fp);
-    return true;
-
-no_png:
-    fclose(fp);
-no_fp:
-    return false;
-}
-
-
-Image *
-readPNG(const char *filename)
-{
-    FILE *fp;
-    png_structp png_ptr;
-    png_infop info_ptr;
-    png_infop end_info;
-    Image *image;
-
-    fp = fopen(filename, "rb");
-    if (!fp)
-        goto no_fp;
-
-    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_ptr)
-        goto no_png;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr) {
-        png_destroy_read_struct(&png_ptr, NULL, NULL);
-        goto no_png;
-    }
-
-    end_info = png_create_info_struct(png_ptr);
-    if (!end_info) {
-        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-        goto no_png;
-    }
-
-    if (setjmp(png_jmpbuf(png_ptr))) {
-        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-        goto no_png;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    png_read_info(png_ptr, info_ptr);
-
-    png_uint_32 width, height;
-    int bit_depth, color_type, interlace_type, compression_type, filter_method;
-
-    png_get_IHDR(png_ptr, info_ptr,
-                 &width, &height,
-                 &bit_depth, &color_type, &interlace_type,
-                 &compression_type, &filter_method);
-
-    image = new Image(width, height);
-    if (!image)
-        goto no_image;
-
-    /* Convert to RGBA8 */
-    if (color_type == PNG_COLOR_TYPE_PALETTE)
-        png_set_palette_to_rgb(png_ptr);
-    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
-        png_set_expand_gray_1_2_4_to_8(png_ptr);
-    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
-        png_set_tRNS_to_alpha(png_ptr);
-    if (bit_depth == 16)
-        png_set_strip_16(png_ptr);
-
-    for (unsigned y = 0; y < height; ++y) {
-        png_bytep row = (png_bytep)(image->pixels + y*width*4);
-        png_read_row(png_ptr, row, NULL);
-    }
-
-    png_read_end(png_ptr, info_ptr);
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-    fclose(fp);
-    return image;
-
-no_image:
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-no_png:
-    fclose(fp);
-no_fp:
-    return NULL;
-}
-
-
-struct png_tmp_buffer
-{
-    char *buffer;
-    size_t size;
-};
-
-static void
-pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
-{
-    struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
-    size_t nsize = buf->size + length;
-
-    /* allocate or grow buffer */
-    if (buf->buffer)
-        buf->buffer = (char*)realloc(buf->buffer, nsize);
-    else
-        buf->buffer = (char*)malloc(nsize);
-
-    if (!buf->buffer)
-        png_error(png_ptr, "Buffer allocation error");
-
-    memcpy(buf->buffer + buf->size, data, length);
-    buf->size += length;
-}
-
-bool writePixelsToBuffer(unsigned char *pixels,
-                         unsigned width, unsigned height, unsigned numChannels,
-                         bool flipped,
-                         char **buffer,
-                         int *size)
-{
-    struct png_tmp_buffer png_mem;
-    png_structp png_ptr;
-    png_infop info_ptr;
-    int type;
-
-    png_mem.buffer = NULL;
-    png_mem.size = 0;
-
-    switch (numChannels) {
-    case 4:
-        type = PNG_COLOR_TYPE_RGB_ALPHA;
-        break;
-    case 3:
-        type = PNG_COLOR_TYPE_RGB;
-        break;
-    case 2:
-        type = PNG_COLOR_TYPE_GRAY_ALPHA;
-        break;
-    case 1:
-        type = PNG_COLOR_TYPE_GRAY;
-        break;
-    default:
-        goto no_png;
-    }
-
-    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_ptr)
-        goto no_png;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr) {
-        png_destroy_write_struct(&png_ptr,  NULL);
-        goto no_png;
-    }
-
-    if (setjmp(png_jmpbuf(png_ptr))) {
-        png_destroy_write_struct(&png_ptr, &info_ptr);
-        goto no_png;
-    }
-
-    png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
-
-    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
-                 type, PNG_INTERLACE_NONE,
-                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
-
-    png_write_info(png_ptr, info_ptr);
-
-    if (!flipped) {
-        for (unsigned y = 0; y < height; ++y) {
-            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    } else {
-        unsigned y = height;
-        while (y--) {
-            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    }
-
-    png_write_end(png_ptr, info_ptr);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    *buffer = png_mem.buffer;
-    *size = png_mem.size;
-
-    return true;
-
-no_png:
-    *buffer = NULL;
-    *size = 0;
-
-    if (png_mem.buffer)
-        free(png_mem.buffer);
-    return false;
-}
-
-} /* namespace Image */
diff --git a/image_pnm.cpp b/image_pnm.cpp
deleted file mode 100644 (file)
index 6625f3d..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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 <assert.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-/**
- * http://en.wikipedia.org/wiki/Netpbm_format
- */
-void
-Image::writePNM(std::ostream &os) const {
-    assert(channels == 1 || channels >= 3);
-
-    os << (channels == 1 ? "P5" : "P6") << "\n";
-    os << width << " " << height << "\n";
-    os << "255" << "\n";
-
-    const unsigned char *row;
-
-    if (channels == 1 || channels == 3) {
-        for (row = start(); row != end(); row += stride()) {
-            os.write((const char *)row, width*channels);
-        }
-    } else {
-        unsigned char pixel[3] = {0, 0, 0};
-        for (row = start(); row != end(); row += stride()) {
-            for (unsigned x = 0; x < width; ++x) {
-                for (unsigned channel = 0; channel < channels; ++channel) {
-                    pixel[channel] = row[x*channels + channel];
-                }
-                os.write((const char *)pixel, sizeof pixel);
-            }
-        }
-    }
-}
-
-
-} /* namespace Image */
diff --git a/json.hpp b/json.hpp
deleted file mode 100644 (file)
index 9e6b960..0000000
--- a/json.hpp
+++ /dev/null
@@ -1,337 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace writing functions.
- */
-
-#ifndef _JSON_HPP_
-#define _JSON_HPP_
-
-#include <assert.h>
-#include <stddef.h>
-#include <wchar.h>
-
-#include <iomanip>
-#include <ostream>
-#include <string>
-
-
-class JSONWriter
-{
-private:
-    std::ostream &os;
-
-    int level;
-    bool value;
-    char space;
-
-    void newline(void) {
-        os << "\n";
-        for (int i = 0; i < level; ++i) 
-            os << "  ";
-    }
-
-    void separator(void) {
-        if (value) {
-            os << ",";
-            switch (space) {
-            case '\0':
-                break;
-            case '\n':
-                newline();
-                break;
-            default:
-                os << space;
-                break;
-            }
-        } else {
-            if (space == '\n') {
-                newline();
-            }
-        }
-    }
-
-    void escapeAsciiString(const char *str) {
-        os << "\"";
-
-        const unsigned char *src = (const unsigned char *)str;
-        unsigned char c;
-        while ((c = *src++)) {
-            if ((c == '\"') ||
-                (c == '\\')) {
-                // escape character
-                os << '\\' << (unsigned char)c;
-            } else if ((c >= 0x20 && c <= 0x7e) ||
-                        c == '\t' ||
-                        c == '\r' ||
-                        c == '\n') {
-                // pass-through character
-                os << (unsigned char)c;
-            } else {
-                assert(0);
-                os << "?";
-            }
-        }
-
-        os << "\"";
-    }
-
-    void escapeUnicodeString(const char *str) {
-        os << "\"";
-
-        const char *locale = setlocale(LC_CTYPE, "");
-        const char *src = str;
-        mbstate_t state;
-
-        memset(&state, 0, sizeof state);
-
-        do {
-            // Convert characters one at a time in order to recover from
-            // conversion errors
-            wchar_t c;
-            size_t written = mbsrtowcs(&c, &src, 1, &state);
-            if (written == 0) {
-                // completed
-                break;
-            } if (written == (size_t)-1) {
-                // conversion error -- skip 
-                os << "?";
-                do {
-                    ++src;
-                } while (*src & 0x80);
-            } else if ((c == '\"') ||
-                       (c == '\\')) {
-                // escape character
-                os << '\\' << (unsigned char)c;
-            } else if ((c >= 0x20 && c <= 0x7e) ||
-                        c == '\t' ||
-                        c == '\r' ||
-                        c == '\n') {
-                // pass-through character
-                os << (unsigned char)c;
-            } else {
-                // unicode
-                os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
-                os << std::dec;
-            }
-        } while (src);
-
-        setlocale(LC_CTYPE, locale);
-
-        os << "\"";
-    }
-
-    void encodeBase64String(const unsigned char *bytes, size_t size) {
-        const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-        unsigned char c0, c1, c2, c3;
-        char buf[4];
-        unsigned written;
-
-        os << "\"";
-
-        written = 0;
-        while (size >= 3) {
-            c0 = bytes[0] >> 2;
-            c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
-            c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
-            c3 = bytes[2] & 0x3f;
-
-            buf[0] = table64[c0];
-            buf[1] = table64[c1];
-            buf[2] = table64[c2];
-            buf[3] = table64[c3];
-
-            os.write(buf, 4);
-
-            bytes += 3;
-            size -= 3;
-            ++written;
-
-            if (written >= 76/4 && size) {
-                os << "\n";
-                written = 0;
-            }
-        }
-
-        if (size > 0) {
-            c0 = bytes[0] >> 2;
-            c1 = ((bytes[0] & 0x03) << 4);
-            buf[2] = '=';
-            buf[3] = '=';
-            
-            if (size > 1) {
-                c1 |= ((bytes[1] & 0xf0) >> 4);
-                c2 = ((bytes[1] & 0x0f) << 2);
-                if (size > 2) {
-                    c2 |= ((bytes[2] & 0xc0) >> 6);
-                    c3 = bytes[2] & 0x3f;
-                    buf[3] = table64[c3];
-                }
-                buf[2] = table64[c2];
-            }
-            buf[1] = table64[c1];
-            buf[0] = table64[c0];
-
-            os.write(buf, 4);
-        }
-
-        os << "\"";
-    }
-
-public:
-    JSONWriter(std::ostream &_os) : 
-        os(_os), 
-        level(0),
-        value(false),
-        space(0)
-    {
-        beginObject();
-    }
-
-    ~JSONWriter() {
-        endObject();
-        newline();
-    }
-
-    inline void beginObject() {
-        separator();
-        os << "{";
-        ++level;
-        value = false;
-    }
-
-    inline void endObject() {
-        --level;
-        if (value)
-            newline();
-        os << "}";
-        value = true;
-        space = '\n';
-    }
-
-    inline void beginMember(const char * name) {
-        space = 0;
-        separator();
-        newline();
-        escapeAsciiString(name);
-        os << ": ";
-        value = false;
-    }
-
-    inline void beginMember(const std::string &name) {
-        beginMember(name.c_str());
-    }
-
-    inline void endMember(void) {
-        assert(value);
-        value = true;
-        space = 0;
-    }
-
-    inline void beginArray() {
-        separator();
-        os << "[";
-        ++level;
-        value = false;
-        space = 0;
-    }
-
-    inline void endArray(void) {
-        --level;
-        if (space == '\n') {
-            newline();
-        }
-        os << "]";
-        value = true;
-        space = '\n';
-    }
-
-    inline void writeString(const char *s) {
-        separator();
-        escapeUnicodeString(s);
-        value = true;
-        space = ' ';
-    }
-
-    inline void writeString(const std::string &s) {
-        writeString(s.c_str());
-    }
-
-    inline void writeBase64(const void *bytes, size_t size) {
-        separator();
-        encodeBase64String((const unsigned char *)bytes, size);
-        value = true;
-        space = ' ';
-    }
-
-    inline void writeNull(void) {
-        separator();
-        os << "null";
-        value = true;
-        space = ' ';
-    }
-
-    inline void writeBool(bool b) {
-        separator();
-        os << (b ? "true" : "false");
-        value = true;
-        space = ' ';
-    }
-
-    template<class T>
-    inline void writeNumber(T n) {
-        if (n != n) {
-            // NaN
-            writeNull();
-        } else {
-            separator();
-            os << std::dec << std::setprecision(9) << n;
-            value = true;
-            space = ' ';
-        }
-    }
-    
-    inline void writeStringMember(const char *name, const char *s) {
-        beginMember(name);
-        writeString(s);
-        endMember();
-    }
-
-    inline void writeBoolMember(const char *name, bool b) {
-        beginMember(name);
-        writeBool(b);
-        endMember();
-    }
-
-    template<class T>
-    inline void writeNumberMember(const char *name, T n) {
-        beginMember(name);
-        writeNumber(n);
-        endMember();
-    }
-};
-
-#endif /* _JSON_HPP_ */
diff --git a/os.hpp b/os.hpp
deleted file mode 100644 (file)
index 8e487b5..0000000
--- a/os.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Simple OS abstraction layer.
- */
-
-#ifndef _OS_HPP_
-#define _OS_HPP_
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf
-#endif
-#define PATH_SEP '\\'
-#else /* !_WIN32 */
-#define PATH_SEP '/'
-#endif /* !_WIN32 */
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024
-#endif
-
-namespace OS {
-
-void AcquireMutex(void);
-
-void ReleaseMutex(void);
-
-bool GetProcessName(char *str, size_t size);
-bool GetCurrentDir(char *str, size_t size);
-
-void DebugMessage(const char *format, ...)
-#ifdef __GNUC__
-    __attribute__ ((format (printf, 1, 2)))
-#endif
-;
-
-#if defined _WIN32 || defined __CYGWIN__
-  /* We always use .def files on windows for now */
-  #if 0
-  #define PUBLIC __declspec(dllexport)
-  #else
-  #define PUBLIC
-  #endif
-  #define PRIVATE
-#else
-  #if __GNUC__ >= 4
-    #define PUBLIC __attribute__ ((visibility("default")))
-    #define PRIVATE __attribute__ ((visibility("hidden")))
-  #else
-    #define PUBLIC
-    #define PRIVATE
-  #endif
-#endif
-
-/**
- * Get the current time in microseconds from an unknown base.
- */
-long long GetTime(void);
-
-void Abort(void);
-
-void SetExceptionCallback(void (*callback)(void));
-void ResetExceptionCallback(void);
-
-} /* namespace OS */
-
-#endif /* _OS_HPP_ */
diff --git a/os_posix.cpp b/os_posix.cpp
deleted file mode 100644 (file)
index 991ad0e..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010-2011 VMware, Inc.
- * 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 <assert.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <unistd.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#ifdef __APPLE__
-#include <mach-o/dyld.h>
-#endif
-
-#include "os.hpp"
-
-
-namespace OS {
-
-
-static pthread_mutex_t 
-mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-void
-AcquireMutex(void)
-{
-    pthread_mutex_lock(&mutex);
-}
-
-
-void
-ReleaseMutex(void)
-{
-    pthread_mutex_unlock(&mutex);
-}
-
-
-bool
-GetProcessName(char *str, size_t size)
-{
-    char szProcessPath[PATH_MAX + 1];
-    char *lpProcessName;
-
-    // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
-#ifdef __APPLE__
-    uint32_t len = sizeof szProcessPath;
-    if (_NSGetExecutablePath(szProcessPath, &len) != 0) {
-        *str = 0;
-        return false;
-    }
-#else
-    ssize_t len;
-    len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1);
-    if (len == -1) {
-        // /proc/self/exe is not available on setuid processes, so fallback to
-        // /proc/self/cmdline.
-        int fd = open("/proc/self/cmdline", O_RDONLY);
-        if (fd >= 0) {
-            len = read(fd, szProcessPath, sizeof(szProcessPath) - 1);
-            close(fd);
-        }
-    }
-    if (len <= 0) {
-        snprintf(str, size, "%i", (int)getpid());
-        return true;
-    }
-#endif
-    szProcessPath[len] = 0;
-
-    lpProcessName = strrchr(szProcessPath, '/');
-    lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
-
-    strncpy(str, lpProcessName, size);
-    if (size)
-        str[size - 1] = 0;
-
-    return true;
-}
-
-bool
-GetCurrentDir(char *str, size_t size)
-{
-    char *ret;
-    ret = getcwd(str, size);
-    str[size - 1] = 0;
-    return ret ? true : false;
-}
-
-void
-DebugMessage(const char *format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-    fflush(stdout);
-    vfprintf(stderr, format, ap);
-    va_end(ap);
-}
-
-long long GetTime(void)
-{
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return tv.tv_usec + tv.tv_sec*1000000LL;
-}
-
-void
-Abort(void)
-{
-    exit(0);
-}
-
-
-static void (*gCallback)(void) = NULL;
-
-#define NUM_SIGNALS 16
-
-struct sigaction old_actions[NUM_SIGNALS];
-
-static void signal_handler(int sig, siginfo_t *info, void *context)
-{
-    static int recursion_count = 0;
-
-    fprintf(stderr, "signal_handler: sig = %i\n", sig);
-
-    if (recursion_count) {
-        fprintf(stderr, "recursion with sig %i\n", sig);
-    } else {
-        if (gCallback) {
-            ++recursion_count;
-            gCallback();
-            --recursion_count;
-        }
-    }
-
-    struct sigaction *old_action;
-    if (sig >= NUM_SIGNALS) {
-        /* This should never happen */
-        fprintf(stderr, "Unexpected signal %i\n", sig);
-        raise(SIGKILL);
-    }
-    old_action = &old_actions[sig];
-
-    if (old_action->sa_flags & SA_SIGINFO) {
-        // Handler is in sa_sigaction
-        old_action->sa_sigaction(sig, info, context);
-    } else {
-        if (old_action->sa_handler == SIG_DFL) {
-            fprintf(stderr, "taking default action for signal %i\n", sig);
-
-#if 1
-            struct sigaction dfl_action;
-            dfl_action.sa_handler = SIG_DFL;
-            sigemptyset (&dfl_action.sa_mask);
-            dfl_action.sa_flags = 0;
-            sigaction(sig, &dfl_action, NULL);
-
-            raise(sig);
-#else
-            raise(SIGKILL);
-#endif
-        } else if (old_action->sa_handler == SIG_IGN) {
-            /* ignore */
-        } else {
-            /* dispatch to handler */
-            old_action->sa_handler(sig);
-        }
-    }
-}
-
-void
-SetExceptionCallback(void (*callback)(void))
-{
-    assert(!gCallback);
-    if (!gCallback) {
-        gCallback = callback;
-
-        struct sigaction new_action;
-        new_action.sa_sigaction = signal_handler;
-        sigemptyset(&new_action.sa_mask);
-        new_action.sa_flags = SA_SIGINFO | SA_RESTART;
-
-
-        for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
-            // SIGKILL and SIGSTOP can't be handled
-            if (sig != SIGKILL && sig != SIGSTOP) {
-                if (sigaction(sig,  NULL, &old_actions[sig]) >= 0) {
-                    sigaction(sig,  &new_action, NULL);
-                }
-            }
-        }
-    }
-}
-
-void
-ResetExceptionCallback(void)
-{
-    gCallback = NULL;
-}
-
-} /* namespace OS */
-
diff --git a/os_win32.cpp b/os_win32.cpp
deleted file mode 100644 (file)
index 587503c..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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 <windows.h>
-#include <assert.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "os.hpp"
-
-
-namespace OS {
-
-
-/* 
- * Trick from http://locklessinc.com/articles/pthreads_on_windows/
- */
-static CRITICAL_SECTION
-CriticalSection = {
-    (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
-};
-
-
-void
-AcquireMutex(void)
-{
-    EnterCriticalSection(&CriticalSection); 
-}
-
-
-void
-ReleaseMutex(void)
-{
-    LeaveCriticalSection(&CriticalSection); 
-}
-
-
-bool
-GetProcessName(char *str, size_t size)
-{
-    char szProcessPath[PATH_MAX];
-    char *lpProcessName;
-    char *lpProcessExt;
-
-    GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
-
-    lpProcessName = strrchr(szProcessPath, '\\');
-    lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
-
-    lpProcessExt = strrchr(lpProcessName, '.');
-    if (lpProcessExt) {
-        *lpProcessExt = '\0';
-    }
-
-    strncpy(str, lpProcessName, size);
-
-    return true;
-}
-
-bool
-GetCurrentDir(char *str, size_t size)
-{
-    DWORD ret;
-    ret = GetCurrentDirectoryA(size, str);
-    str[size - 1] = 0;
-    return ret == 0 ? false : true;
-}
-
-void
-DebugMessage(const char *format, ...)
-{
-    char buf[4096];
-
-    va_list ap;
-    va_start(ap, format);
-    fflush(stdout);
-    vsnprintf(buf, sizeof buf, format, ap);
-    va_end(ap);
-
-    OutputDebugStringA(buf);
-
-    /*
-     * Also write the message to stderr, when a debugger is not present (to
-     * avoid duplicate messages in command line debuggers).
-     */
-#if _WIN32_WINNT > 0x0400
-    if (!IsDebuggerPresent()) {
-        fflush(stdout);
-        fputs(buf, stderr);
-        fflush(stderr);
-    }
-#endif
-}
-
-long long GetTime(void)
-{
-    static LARGE_INTEGER frequency;
-    LARGE_INTEGER counter;
-    if (!frequency.QuadPart)
-        QueryPerformanceFrequency(&frequency);
-    QueryPerformanceCounter(&counter);
-    return counter.QuadPart*1000000LL/frequency.QuadPart;
-}
-
-void
-Abort(void)
-{
-#ifndef NDEBUG
-    DebugBreak();
-#else
-    ExitProcess(0);
-#endif
-}
-
-
-static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
-static void (*gCallback)(void) = NULL;
-
-static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
-{
-    if (gCallback) {
-        gCallback();
-    }
-
-       if (prevExceptionFilter) {
-               return prevExceptionFilter(pExceptionInfo);
-    } else {
-               return EXCEPTION_CONTINUE_SEARCH;
-    }
-}
-
-void
-SetExceptionCallback(void (*callback)(void))
-{
-    assert(!gCallback);
-
-    if (!gCallback) {
-        gCallback = callback;
-
-        assert(!prevExceptionFilter);
-        prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
-    }
-}
-
-void
-ResetExceptionCallback(void)
-{
-    gCallback = NULL;
-}
-
-
-} /* namespace OS */
diff --git a/scripts/README b/scripts/README
deleted file mode 100644 (file)
index 576e48f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory contains several utilitarian scripts for common development
-tasks using apitrace tools.
-
-See their code for more details about their usage.
diff --git a/scripts/highlight.py b/scripts/highlight.py
new file mode 100644 (file)
index 0000000..986bd1d
--- /dev/null
@@ -0,0 +1,194 @@
+##########################################################################
+#
+# Copyright 2011 Jose Fonseca
+# Copyright 2008-2009 VMware, Inc.
+# 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.
+#
+##########################################################################/
+
+
+import sys
+import platform
+
+
+class PlainHighlighter:
+    '''Plain formatter'''
+
+    black = None
+    red = None
+    green = None
+    yellow = None
+    blue = None
+    magenta = None
+    cyan = None
+    white = None
+
+    def __init__(self, stream):
+        self.stream = stream
+
+    def write(self, text):
+        self.stream.write(text)
+
+    def flush(self):
+        self.stream.flush()
+
+    def normal(self):
+        pass
+
+    def color(self, color):
+        pass
+
+    def bold(self):
+        pass
+
+    def italic(self):
+        pass
+
+
+class AnsiHighlighter(PlainHighlighter):
+    '''Highlighter for plain-text files which outputs ANSI escape codes. See
+    http://en.wikipedia.org/wiki/ANSI_escape_code for more information
+    concerning ANSI escape codes.
+    '''
+
+    _csi = '\33['
+
+    _normal = '0m'
+    _bold = '1m'
+    _italic = '3m'
+
+    black = 0
+    red = 1
+    green = 2
+    yellow = 3
+    blue = 4
+    magenta = 5
+    cyan = 6
+    white = 7
+
+    def __init__(self, stream):
+        PlainHighlighter.__init__(self, stream)
+        self.isatty = stream.isatty()
+
+    def _escape(self, code):
+        if self.isatty:
+            self.stream.write(self._csi + code)
+
+    def normal(self):
+        self._escape(self._normal)
+
+    def color(self, color):
+        self._escape(str(30 + color) + 'm')
+
+    def bold(self):
+        self._escape(self._bold)
+
+    def italic(self):
+        self._escape(self._italic)
+
+
+class WindowsConsoleHighlighter(PlainHighlighter):
+    '''Highlighter for the Windows Console. See 
+    http://code.activestate.com/recipes/496901/ for more information.
+    '''
+
+    INVALID_HANDLE_VALUE = -1
+    STD_INPUT_HANDLE  = -10
+    STD_OUTPUT_HANDLE = -11
+    STD_ERROR_HANDLE  = -12
+
+    FOREGROUND_BLUE      = 0x01
+    FOREGROUND_GREEN     = 0x02
+    FOREGROUND_RED       = 0x04
+    FOREGROUND_INTENSITY = 0x08
+    BACKGROUND_BLUE      = 0x10
+    BACKGROUND_GREEN     = 0x20
+    BACKGROUND_RED       = 0x40
+    BACKGROUND_INTENSITY = 0x80
+
+    COMMON_LVB_LEADING_BYTE = 0x0100
+    COMMON_LVB_TRAILING_BYTE = 0x0200
+    COMMON_LVB_GRID_HORIZONTAL = 0x0400
+    COMMON_LVB_GRID_LVERTICAL = 0x0800
+    COMMON_LVB_GRID_RVERTICAL = 0x1000
+    COMMON_LVB_REVERSE_VIDEO = 0x4000
+    COMMON_LVB_UNDERSCORE = 0x8000
+
+    _normal = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+    _bold   = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+    _italic = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+
+    black   = 0
+    red     =                                      FOREGROUND_RED
+    green   =                   FOREGROUND_GREEN                 
+    blue    = FOREGROUND_BLUE                                    
+    white   = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+
+    def __init__(self, stream):
+        PlainHighlighter.__init__(self, stream)
+
+        if stream is sys.stdin:
+            nStdHandle = self.STD_INPUT_HANDLE
+        elif stream is sys.stdout:
+            nStdHandle = self.STD_OUTPUT_HANDLE
+        elif stream is sys.stderr:
+            nStdHandle = self.STD_ERROR_HANDLE
+        else:
+            nStdHandle = None
+
+        if nStdHandle is not None:
+            import ctypes
+            self._handle = ctypes.windll.kernel32.GetStdHandle(nStdHandle)
+        else:
+            self._handle = INVALID_HANDLE_VALUE
+
+        self._attribute = self.white
+
+    def _setAttribute(self, attr):
+        if self._handle != INVALID_HANDLE_VALUE:
+            import ctypes
+            ctypes.windll.kernel32.SetConsoleTextAttribute(self._handle, attr)
+        self._attribute = attr
+
+    def normal(self):
+        self._setAttribute(self._normal)
+
+    def color(self, color):
+        intensity = self._attribute & FOREGROUND_INTENSITY
+        self._setAttribute(color | intensity)
+
+    def bold(self):
+        self._setAttribute(self._attribute | FOREGROUND_INTENSITY)
+
+    def italic(self):
+        pass
+
+
+def Highlighter(stream = sys.stdout):
+    if platform.system() == 'Windows':
+        return WindowsConsoleHighlighter(stream)
+    else:
+        return AnsiHighlighter(stream)
+
+
+__all__ = [
+    'Highlighter',
+]
index b4bad08db73588b93237cfc6b494ad0f24dbd8a5..0b6a3b09f5713402b8ae8d249891ed31c7d76b5c 100755 (executable)
 
 import optparse
 import os.path
-import re
-import shutil
 import subprocess
 import platform
 import sys
-import tempfile
+
+from PIL import Image
 
 from snapdiff import Comparer
+from highlight import Highlighter
 import jsondiff
 
 
@@ -54,10 +54,10 @@ class Setup:
         self.args = args
         self.env = env
 
-    def retrace(self, snapshot_dir):
+    def retrace(self):
         cmd = [
             options.retrace,
-            '-s', snapshot_dir + os.path.sep,
+            '-s', '-',
             '-S', options.snapshot_frequency,
         ] + self.args
         p = subprocess.Popen(cmd, env=self.env, stdout=subprocess.PIPE, stderr=NULL)
@@ -73,16 +73,38 @@ class Setup:
         p = subprocess.Popen(cmd, env=self.env, stdout=subprocess.PIPE, stderr=NULL)
         state = jsondiff.load(p.stdout)
         p.wait()
-        return state
+        return state.get('parameters', {})
+
+    def diff_state(self, ref_call_no, src_call_no):
+        '''Compare the state between two calls.'''
+
+        ref_state = self.dump_state(ref_call_no)
+        src_state = self.dump_state(src_call_no)
 
+        sys.stdout.flush()
+        differ = jsondiff.Differ(sys.stdout)
+        differ.visit(ref_state, src_state)
+        sys.stdout.write('\n')
 
-def diff_state(setup, ref_call_no, src_call_no):
-    ref_state = setup.dump_state(ref_call_no)
-    src_state = setup.dump_state(src_call_no)
-    sys.stdout.flush()
-    differ = jsondiff.Differ(sys.stdout)
-    differ.visit(ref_state, src_state)
-    sys.stdout.write('\n')
+
+def read_pnm(stream):
+    '''Read a PNM from the stream, and return the image object, and the comment.'''
+
+    magic = stream.readline()
+    if not magic:
+        return None, None
+    assert magic.rstrip() == 'P6'
+    comment = ''
+    line = stream.readline()
+    while line.startswith('#'):
+        comment += line[1:]
+        line = stream.readline()
+    width, height = map(int, line.strip().split())
+    maximum = int(stream.readline().strip())
+    assert maximum == 255
+    data = stream.read(height * width * 3)
+    image = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', 0, 1)
+    return image, comment
 
 
 def parse_env(optparser, entries):
@@ -115,15 +137,15 @@ def main():
     optparser.add_option(
         '--ref-env', metavar='NAME=VALUE',
         type='string', action='append', dest='ref_env', default=[],
-        help='reference environment variable')
+        help='add variable to reference environment')
     optparser.add_option(
         '--src-env', metavar='NAME=VALUE',
         type='string', action='append', dest='src_env', default=[],
-        help='reference environment variable')
+        help='add variable to source environment')
     optparser.add_option(
         '--diff-prefix', metavar='PATH',
         type='string', dest='diff_prefix', default='.',
-        help='reference environment variable')
+        help='prefix for the difference images')
     optparser.add_option(
         '-t', '--threshold', metavar='BITS',
         type="float", dest="threshold", default=12.0,
@@ -131,7 +153,7 @@ def main():
     optparser.add_option(
         '-S', '--snapshot-frequency', metavar='FREQUENCY',
         type="string", dest="snapshot_frequency", default='draw',
-        help="snapshot frequency  [default: %default]")
+        help="snapshot frequency: frame, framebuffer, or draw  [default: %default]")
 
     (options, args) = optparser.parse_args(sys.argv[1:])
     ref_env = parse_env(optparser, options.ref_env)
@@ -142,62 +164,64 @@ def main():
     ref_setup = Setup(args, ref_env)
     src_setup = Setup(args, src_env)
 
-    image_re = re.compile('^Wrote (.*\.png)$')
+    highligher = Highlighter(sys.stdout)
+
+    highligher.write('call\tprecision\n')
 
-    last_good = -1
     last_bad = -1
-    ref_snapshot_dir = tempfile.mkdtemp()
+    last_good = 0
+    ref_proc = ref_setup.retrace()
     try:
-        src_snapshot_dir = tempfile.mkdtemp()
+        src_proc = src_setup.retrace()
         try:
-            ref_proc = ref_setup.retrace(ref_snapshot_dir)
-            try:
-                src_proc = src_setup.retrace(src_snapshot_dir)
-                try:
-                    for ref_line in ref_proc.stdout:
-                        # Get the reference image
-                        ref_line = ref_line.rstrip()
-                        mo = image_re.match(ref_line)
-                        if mo:
-                            ref_image = mo.group(1)
-                            for src_line in src_proc.stdout:
-                                # Get the source image
-                                src_line = src_line.rstrip()
-                                mo = image_re.match(src_line)
-                                if mo:
-                                    src_image = mo.group(1)
-                                    
-                                    root, ext = os.path.splitext(os.path.basename(src_image))
-                                    call_no = int(root)
-
-                                    # Compare the two images
-                                    comparer = Comparer(ref_image, src_image)
-                                    precision = comparer.precision()
-
-                                    sys.stdout.write('%u %f\n' % (call_no, precision))
-                                    
-                                    if precision < options.threshold:
-                                        if options.diff_prefix:
-                                            comparer.write_diff(os.path.join(options.diff_prefix, root + '.diff.png'))
-                                        if last_bad < last_good:
-                                            diff_state(src_setup, last_good, call_no)
-                                        last_bad = call_no
-                                    else:
-                                        last_good = call_no
-
-                                    sys.stdout.flush()
-                                   
-                                    os.unlink(src_image)
-                                    break
-                            os.unlink(ref_image)
-                finally:
-                    src_proc.terminate()
-            finally:
-                ref_proc.terminate()
+            while True:
+                # Get the reference image
+                ref_image, ref_comment = read_pnm(ref_proc.stdout)
+                if ref_image is None:
+                    break
+
+                # Get the source image
+                src_image, src_comment = read_pnm(src_proc.stdout)
+                if src_image is None:
+                    break
+
+                assert ref_comment == src_comment
+
+                call_no = int(ref_comment.strip())
+
+                # Compare the two images
+                comparer = Comparer(ref_image, src_image)
+                precision = comparer.precision()
+
+                mismatch = precision < options.threshold
+
+                if mismatch:
+                    highligher.color(highligher.red)
+                    highligher.bold()
+                highligher.write('%u\t%f\n' % (call_no, precision))
+                if mismatch:
+                    highligher.normal()
+
+                if mismatch:
+                    if options.diff_prefix:
+                        prefix = os.path.join(options.diff_prefix, '%010u' % call_no)
+                        prefix_dir = os.path.dirname(prefix)
+                        if not os.path.isdir(prefix_dir):
+                            os.makedirs(prefix_dir)
+                        ref_image.save(prefix + '.ref.png')
+                        src_image.save(prefix + '.src.png')
+                        comparer.write_diff(prefix + '.diff.png')
+                    if last_bad < last_good:
+                        src_setup.diff_state(last_good, call_no)
+                    last_bad = call_no
+                else:
+                    last_good = call_no
+
+                highligher.flush()
         finally:
-            shutil.rmtree(ref_snapshot_dir)
+            src_proc.terminate()
     finally:
-        shutil.rmtree(src_snapshot_dir)
+        ref_proc.terminate()
 
 
 if __name__ == '__main__':
index 60d9ae97ca740b26b5820f76567a4d414c6055d3..0ed3937a8f8e669accf577c4b06d6472784e3c57 100755 (executable)
@@ -48,8 +48,15 @@ class Comparer:
     '''Image comparer.'''
 
     def __init__(self, ref_image, src_image, alpha = False):
-        self.ref_im = Image.open(ref_image)
-        self.src_im = Image.open(src_image)
+        if isinstance(ref_image, basestring):
+            self.ref_im = Image.open(ref_image)
+        else:
+            self.ref_im = ref_image
+
+        if isinstance(src_image, basestring):
+            self.src_im = Image.open(src_image)
+        else:
+            self.src_im = src_image
 
         # Ignore
         if not alpha:
index 555e6709ce0ec3a4b74408582861146637b4e6e1..09400215bac24305048da1f6738b0c99a1094e9c 100644 (file)
@@ -6,7 +6,7 @@ extern "C" {
 #endif
 
 /*
-** Copyright (c) 2007-2010 The Khronos Group Inc.
+** Copyright (c) 2007-2011 The Khronos Group Inc.
 ** 
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
@@ -29,9 +29,9 @@ extern "C" {
 */
 
 /* Header file version number, required by OpenGL ABI for Linux */
-/* glext.h last updated $Date: 2011-06-06 12:06:38 -0700 (Mon, 06 Jun 2011) $ */
+/* glext.h last updated $Date: 2011-08-08 00:34:29 -0700 (Mon, 08 Aug 2011) $ */
 /* Current version at http://www.opengl.org/registry/ */
-#define GL_GLEXT_VERSION 70
+#define GL_GLEXT_VERSION 72
 /* Function declaration macros - to move into glplatform.h */
 
 #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
@@ -1047,6 +1047,124 @@ extern "C" {
 /* reuse GL_UNDEFINED_VERTEX */
 #endif
 
+#ifndef GL_VERSION_4_2
+/* Reuse tokens from ARB_base_instance (none) */
+/* Reuse tokens from ARB_shading_language_420pack (none) */
+/* Reuse tokens from ARB_transform_feedback_instanced (none) */
+/* Reuse tokens from ARB_compressed_texture_pixel_storage */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */
+/* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */
+/* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */
+/* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */
+/* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */
+/* Reuse tokens from ARB_conservative_depth (none) */
+/* Reuse tokens from ARB_internalformat_query */
+/* reuse GL_NUM_SAMPLE_COUNTS */
+/* Reuse tokens from ARB_map_buffer_alignment */
+/* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */
+/* Reuse tokens from ARB_shader_atomic_counters */
+/* reuse GL_ATOMIC_COUNTER_BUFFER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_START */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */
+/* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */
+/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */
+/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */
+/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */
+/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */
+/* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */
+/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */
+/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */
+/* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */
+/* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */
+/* Reuse tokens from ARB_shader_image_load_store */
+/* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */
+/* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */
+/* reuse GL_UNIFORM_BARRIER_BIT */
+/* reuse GL_TEXTURE_FETCH_BARRIER_BIT */
+/* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */
+/* reuse GL_COMMAND_BARRIER_BIT */
+/* reuse GL_PIXEL_BUFFER_BARRIER_BIT */
+/* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */
+/* reuse GL_BUFFER_UPDATE_BARRIER_BIT */
+/* reuse GL_FRAMEBUFFER_BARRIER_BIT */
+/* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */
+/* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */
+/* reuse GL_ALL_BARRIER_BITS */
+/* reuse GL_MAX_IMAGE_UNITS */
+/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */
+/* reuse GL_IMAGE_BINDING_NAME */
+/* reuse GL_IMAGE_BINDING_LEVEL */
+/* reuse GL_IMAGE_BINDING_LAYERED */
+/* reuse GL_IMAGE_BINDING_LAYER */
+/* reuse GL_IMAGE_BINDING_ACCESS */
+/* reuse GL_IMAGE_1D */
+/* reuse GL_IMAGE_2D */
+/* reuse GL_IMAGE_3D */
+/* reuse GL_IMAGE_2D_RECT */
+/* reuse GL_IMAGE_CUBE */
+/* reuse GL_IMAGE_BUFFER */
+/* reuse GL_IMAGE_1D_ARRAY */
+/* reuse GL_IMAGE_2D_ARRAY */
+/* reuse GL_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_INT_IMAGE_1D */
+/* reuse GL_INT_IMAGE_2D */
+/* reuse GL_INT_IMAGE_3D */
+/* reuse GL_INT_IMAGE_2D_RECT */
+/* reuse GL_INT_IMAGE_CUBE */
+/* reuse GL_INT_IMAGE_BUFFER */
+/* reuse GL_INT_IMAGE_1D_ARRAY */
+/* reuse GL_INT_IMAGE_2D_ARRAY */
+/* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_INT_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_1D */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D */
+/* reuse GL_UNSIGNED_INT_IMAGE_3D */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */
+/* reuse GL_UNSIGNED_INT_IMAGE_CUBE */
+/* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */
+/* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_MAX_IMAGE_SAMPLES */
+/* reuse GL_IMAGE_BINDING_FORMAT */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */
+/* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */
+/* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */
+/* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */
+/* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */
+/* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */
+/* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */
+/* Reuse tokens from ARB_shading_language_packing (none) */
+/* Reuse tokens from ARB_texture_storage */
+/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
+#endif
+
 #ifndef GL_ARB_multitexture
 #define GL_TEXTURE0_ARB                   0x84C0
 #define GL_TEXTURE1_ARB                   0x84C1
@@ -2140,6 +2258,143 @@ extern "C" {
 #ifndef GL_ARB_shader_stencil_export
 #endif
 
+#ifndef GL_ARB_base_instance
+#endif
+
+#ifndef GL_ARB_shading_language_420pack
+#endif
+
+#ifndef GL_ARB_transform_feedback_instanced
+#endif
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH  0x9127
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH  0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE   0x912A
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH    0x912B
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT   0x912C
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH    0x912D
+#define GL_PACK_COMPRESSED_BLOCK_SIZE     0x912E
+#endif
+
+#ifndef GL_ARB_conservative_depth
+#endif
+
+#ifndef GL_ARB_internalformat_query
+#define GL_NUM_SAMPLE_COUNTS              0x9380
+#endif
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_MIN_MAP_BUFFER_ALIGNMENT       0x90BC
+#endif
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ATOMIC_COUNTER_BUFFER          0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING  0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_START    0x92C2
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE     0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS     0x92D2
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS   0x92D5
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS   0x92D6
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS   0x92D7
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS  0x92D9
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER    0x92DB
+#endif
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT      0x00000002
+#define GL_UNIFORM_BARRIER_BIT            0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT      0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_COMMAND_BARRIER_BIT            0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT       0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT     0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT      0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT        0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT     0x00001000
+#define GL_ALL_BARRIER_BITS               0xFFFFFFFF
+#define GL_MAX_IMAGE_UNITS                0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_IMAGE_BINDING_NAME             0x8F3A
+#define GL_IMAGE_BINDING_LEVEL            0x8F3B
+#define GL_IMAGE_BINDING_LAYERED          0x8F3C
+#define GL_IMAGE_BINDING_LAYER            0x8F3D
+#define GL_IMAGE_BINDING_ACCESS           0x8F3E
+#define GL_IMAGE_1D                       0x904C
+#define GL_IMAGE_2D                       0x904D
+#define GL_IMAGE_3D                       0x904E
+#define GL_IMAGE_2D_RECT                  0x904F
+#define GL_IMAGE_CUBE                     0x9050
+#define GL_IMAGE_BUFFER                   0x9051
+#define GL_IMAGE_1D_ARRAY                 0x9052
+#define GL_IMAGE_2D_ARRAY                 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY           0x9054
+#define GL_IMAGE_2D_MULTISAMPLE           0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY     0x9056
+#define GL_INT_IMAGE_1D                   0x9057
+#define GL_INT_IMAGE_2D                   0x9058
+#define GL_INT_IMAGE_3D                   0x9059
+#define GL_INT_IMAGE_2D_RECT              0x905A
+#define GL_INT_IMAGE_CUBE                 0x905B
+#define GL_INT_IMAGE_BUFFER               0x905C
+#define GL_INT_IMAGE_1D_ARRAY             0x905D
+#define GL_INT_IMAGE_2D_ARRAY             0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY       0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE       0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D          0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D          0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D          0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT     0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE        0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER      0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY    0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY    0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_MAX_IMAGE_SAMPLES              0x906D
+#define GL_IMAGE_BINDING_FORMAT           0x906E
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS      0x90CA
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS    0x90CD
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS    0x90CE
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS    0x90CF
+#endif
+
+#ifndef GL_ARB_shading_language_packing
+#endif
+
+#ifndef GL_ARB_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT       0x912F
+#endif
+
 #ifndef GL_EXT_abgr
 #define GL_ABGR_EXT                       0x8000
 #endif
@@ -5053,6 +5308,11 @@ extern "C" {
 #ifndef GL_AMD_multi_draw_indirect
 #endif
 
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_SCALED_RESOLVE_FASTEST_EXT     0x90BA
+#define GL_SCALED_RESOLVE_NICEST_EXT      0x90BB
+#endif
+
 
 /*************************************************************/
 
@@ -5912,7 +6172,7 @@ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB,
 
 #ifndef GL_VERSION_4_1
 #define GL_VERSION_4_1 1
-/* OpenGL 4.1 also reuses entry points from these extensions: */
+/* OpenGL 4.1 reuses entry points from these extensions: */
 /* ARB_ES2_compatibility */
 /* ARB_get_program_binary */
 /* ARB_separate_shader_objects */
@@ -5921,6 +6181,22 @@ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB,
 /* ARB_viewport_array */
 #endif
 
+#ifndef GL_VERSION_4_2
+#define GL_VERSION_4_2 1
+/* OpenGL 4.2 reuses entry points from these extensions: */
+/* ARB_base_instance */
+/* ARB_shading_language_420pack (no entry points) */
+/* ARB_transform_feedback_instanced */
+/* ARB_compressed_texture_pixel_storage (no entry points) */
+/* ARB_conservative_depth (no entry points) */
+/* ARB_internalformat_query */
+/* ARB_map_buffer_alignment (no entry points) */
+/* ARB_shader_atomic_counters */
+/* ARB_shader_image_load_store */
+/* ARB_shading_language_packing (no entry points) */
+/* ARB_texture_storage */
+#endif
+
 #ifndef GL_ARB_multitexture
 #define GL_ARB_multitexture 1
 #ifdef GL_GLEXT_PROTOTYPES
@@ -6846,6 +7122,10 @@ typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum
 typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
 #endif
 
+#ifndef GL_ARB_shader_bit_encoding
+#define GL_ARB_shader_bit_encoding 1
+#endif
+
 #ifndef GL_ARB_texture_rgb10_a2ui
 #define GL_ARB_texture_rgb10_a2ui 1
 #endif
@@ -7352,6 +7632,92 @@ typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint locati
 #define GL_ARB_shader_stencil_export 1
 #endif
 
+#ifndef GL_ARB_base_instance
+#define GL_ARB_base_instance 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
+#endif
+
+#ifndef GL_ARB_shading_language_420pack
+#define GL_ARB_shading_language_420pack 1
+#endif
+
+#ifndef GL_ARB_transform_feedback_instanced
+#define GL_ARB_transform_feedback_instanced 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount);
+GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei primcount);
+#endif
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_ARB_compressed_texture_pixel_storage 1
+#endif
+
+#ifndef GL_ARB_conservative_depth
+#define GL_ARB_conservative_depth 1
+#endif
+
+#ifndef GL_ARB_internalformat_query
+#define GL_ARB_internalformat_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+#endif
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_ARB_map_buffer_alignment 1
+#endif
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ARB_shader_atomic_counters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_ARB_shader_image_load_store 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
+#endif
+
+#ifndef GL_ARB_shading_language_packing
+#define GL_ARB_shading_language_packing 1
+#endif
+
+#ifndef GL_ARB_texture_storage
+#define GL_ARB_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
 #ifndef GL_EXT_abgr
 #define GL_EXT_abgr 1
 #endif
@@ -11110,6 +11476,10 @@ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const
 typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
 #endif
 
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_EXT_framebuffer_multisample_blit_scaled 1
+#endif
+
 
 #ifdef __cplusplus
 }
diff --git a/trace_file.cpp b/trace_file.cpp
deleted file mode 100644 (file)
index e206858..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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 "trace_file.hpp"
-
-#include "trace_snappyfile.hpp"
-
-#include <assert.h>
-#include <string.h>
-
-#include <zlib.h>
-
-#include "os.hpp"
-
-#include <iostream>
-
-using namespace Trace;
-
-
-File::File(const std::string &filename,
-           File::Mode mode)
-    : m_filename(filename),
-      m_mode(mode),
-      m_isOpened(false)
-{
-    if (!m_filename.empty()) {
-        open(m_filename, m_mode);
-    }
-}
-
-File::~File()
-{
-    close();
-}
-
-bool File::isZLibCompressed(const std::string &filename)
-{
-    std::fstream stream(filename.c_str(),
-                        std::fstream::binary | std::fstream::in);
-    if (!stream.is_open())
-        return false;
-
-    unsigned char byte1, byte2;
-    stream >> byte1;
-    stream >> byte2;
-    stream.close();
-
-    return (byte1 == 0x1f && byte2 == 0x8b);
-}
-
-
-bool File::isSnappyCompressed(const std::string &filename)
-{
-    std::fstream stream(filename.c_str(),
-                        std::fstream::binary | std::fstream::in);
-    if (!stream.is_open())
-        return false;
-
-    unsigned char byte1, byte2;
-    stream >> byte1;
-    stream >> byte2;
-    stream.close();
-
-    return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
-}
-
-
-ZLibFile::ZLibFile(const std::string &filename,
-                   File::Mode mode)
-    : File(filename, mode),
-      m_gzFile(NULL)
-{
-}
-
-ZLibFile::~ZLibFile()
-{
-}
-
-bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
-{
-    m_gzFile = gzopen(filename.c_str(),
-                      (mode == File::Write) ? "wb" : "rb");
-    return m_gzFile != NULL;
-}
-
-bool ZLibFile::rawWrite(const void *buffer, int length)
-{
-    return gzwrite(m_gzFile, buffer, length) != -1;
-}
-
-bool ZLibFile::rawRead(void *buffer, int length)
-{
-    return gzread(m_gzFile, buffer, length) != -1;
-}
-
-int ZLibFile::rawGetc()
-{
-    return gzgetc(m_gzFile);
-}
-
-void ZLibFile::rawClose()
-{
-    if (m_gzFile) {
-        gzclose(m_gzFile);
-        m_gzFile = NULL;
-    }
-}
-
-void ZLibFile::rawFlush()
-{
-    gzflush(m_gzFile, Z_SYNC_FLUSH);
-}
diff --git a/trace_file.hpp b/trace_file.hpp
deleted file mode 100644 (file)
index 5a98f60..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#ifndef TRACE_FILE_HPP
-#define TRACE_FILE_HPP
-
-#include <string>
-#include <fstream>
-
-namespace Trace {
-
-class File {
-public:
-    enum Mode {
-        Read,
-        Write
-    };
-public:
-    static bool isZLibCompressed(const std::string &filename);
-    static bool isSnappyCompressed(const std::string &filename);
-public:
-    File(const std::string &filename = std::string(),
-         File::Mode mode = File::Read);
-    virtual ~File();
-
-    bool isOpened() const;
-    File::Mode mode() const;
-
-    std::string filename() const;
-
-    bool open(const std::string &filename, File::Mode mode);
-    bool write(const void *buffer, int length);
-    bool read(void *buffer, int length);
-    void close();
-    void flush(void);
-    int getc();
-
-protected:
-    virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0;
-    virtual bool rawWrite(const void *buffer, int length) = 0;
-    virtual bool rawRead(void *buffer, int length) = 0;
-    virtual int rawGetc() = 0;
-    virtual void rawClose() = 0;
-    virtual void rawFlush() = 0;
-
-protected:
-    std::string m_filename;
-    File::Mode m_mode;
-    bool m_isOpened;
-};
-
-inline bool File::isOpened() const
-{
-    return m_isOpened;
-}
-
-inline File::Mode File::mode() const
-{
-    return m_mode;
-}
-
-inline std::string File::filename() const
-{
-    return m_filename;
-}
-
-inline bool File::open(const std::string &filename, File::Mode mode)
-{
-    if (m_isOpened) {
-        close();
-    }
-    m_isOpened = rawOpen(filename, mode);
-    m_mode = mode;
-
-    return m_isOpened;
-}
-
-inline bool File::write(const void *buffer, int length)
-{
-    if (!m_isOpened || m_mode != File::Write) {
-        return false;
-    }
-    return rawWrite(buffer, length);
-}
-
-inline bool File::read(void *buffer, int length)
-{
-    if (!m_isOpened || m_mode != File::Read) {
-        return false;
-    }
-    return rawRead(buffer, length);
-}
-
-inline void File::close()
-{
-    if (m_isOpened) {
-        rawClose();
-        m_isOpened = false;
-    }
-}
-
-inline void File::flush(void)
-{
-    rawFlush();
-}
-
-inline int File::getc()
-{
-    if (!m_isOpened || m_mode != File::Read) {
-        return -1;
-    }
-    return rawGetc();
-}
-
-class ZLibFile : public File {
-public:
-    ZLibFile(const std::string &filename = std::string(),
-             File::Mode mode = File::Read);
-    virtual ~ZLibFile();
-
-protected:
-    virtual bool rawOpen(const std::string &filename, File::Mode mode);
-    virtual bool rawWrite(const void *buffer, int length);
-    virtual bool rawRead(void *buffer, int length);
-    virtual int rawGetc();
-    virtual void rawClose();
-    virtual void rawFlush();
-private:
-    void *m_gzFile;
-};
-
-}
-
-#endif
diff --git a/trace_format.hpp b/trace_format.hpp
deleted file mode 100644 (file)
index a8ee5eb..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace binary format.
- *
- * Grammar:
- *
- *   trace = event* EOF
- *
- *   event = EVENT_ENTER call_sig call_detail+
- *         | EVENT_LEAVE call_no call_detail+
- *
- *   call_sig = sig_id ( name arg_names )?
- *
- *   call_detail = ARG index value
- *               | RET value
- *               | END
- *
- *   value = NULL
- *         | FALSE
- *         | TRUE
- *         | SINT int
- *         | UINT int
- *         | FLOAT float
- *         | DOUBLE double
- *         | STRING string
- *         | BLOB string
- *         | ENUM enum_sig
- *         | BITMASK bitmask_sig value
- *         | ARRAY length value+
- *         | STRUCT struct_sig value+
- *         | OPAQUE int
- *
- *   call_sig = id name arg_name*
- *            | id
- *
- *   enum_sig = id name value
- *            | id
- *
- *   bitmask_sig = id count (name value)+
- *               | id
- *
- *   string = length (BYTE)*
- *
- */
-
-#ifndef _TRACE_FORMAT_HPP_
-#define _TRACE_FORMAT_HPP_
-
-namespace Trace {
-
-#define TRACE_VERSION 1
-
-enum Event {
-    EVENT_ENTER = 0,
-    EVENT_LEAVE,
-};
-
-enum CallDetail {
-    CALL_END = 0,
-    CALL_ARG,
-    CALL_RET,
-    CALL_THREAD,
-};
-
-enum Type {
-    TYPE_NULL = 0,
-    TYPE_FALSE,
-    TYPE_TRUE,
-    TYPE_SINT,
-    TYPE_UINT,
-    TYPE_FLOAT,
-    TYPE_DOUBLE,
-    TYPE_STRING, // Null terminated, human readible string
-    TYPE_BLOB, // Block of bytes
-    TYPE_ENUM,
-    TYPE_BITMASK,
-    TYPE_ARRAY,
-    TYPE_STRUCT,
-    TYPE_OPAQUE,
-};
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_FORMAT_HPP_ */
diff --git a/trace_local_writer.cpp b/trace_local_writer.cpp
deleted file mode 100644 (file)
index ea6c111..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007-2011 VMware, Inc.
- * 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 <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "os.hpp"
-#include "trace_file.hpp"
-#include "trace_writer.hpp"
-#include "trace_format.hpp"
-
-
-namespace Trace {
-
-
-static void exceptionCallback(void)
-{
-    OS::DebugMessage("apitrace: flushing trace due to an exception\n");
-    localWriter.flush();
-}
-
-
-LocalWriter::LocalWriter() :
-    acquired(0)
-{}
-
-LocalWriter::~LocalWriter()
-{
-    OS::ResetExceptionCallback();
-}
-
-void
-LocalWriter::open(void) {
-
-    static unsigned dwCounter = 0;
-
-    const char *szExtension = "trace";
-    char szFileName[PATH_MAX];
-    const char *lpFileName;
-
-    lpFileName = getenv("TRACE_FILE");
-    if (lpFileName) {
-        strncpy(szFileName, lpFileName, PATH_MAX);
-    }
-    else {
-        char szProcessName[PATH_MAX];
-        char szCurrentDir[PATH_MAX];
-        OS::GetProcessName(szProcessName, PATH_MAX);
-        OS::GetCurrentDir(szCurrentDir, PATH_MAX);
-
-        for (;;) {
-            FILE *file;
-
-            if (dwCounter)
-                snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
-            else
-                snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
-
-            file = fopen(szFileName, "rb");
-            if (file == NULL)
-                break;
-
-            fclose(file);
-
-            ++dwCounter;
-        }
-    }
-
-    OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
-
-    Writer::open(szFileName);
-
-    OS::SetExceptionCallback(exceptionCallback);
-
-#if 0
-    // For debugging the exception handler
-    *((int *)0) = 0;
-#endif
-}
-
-unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
-    OS::AcquireMutex();
-    ++acquired;
-
-    if (!m_file->isOpened()) {
-        open();
-    }
-
-    return Writer::beginEnter(sig);
-}
-
-void LocalWriter::endEnter(void) {
-    Writer::endEnter();
-    --acquired;
-    OS::ReleaseMutex();
-}
-
-void LocalWriter::beginLeave(unsigned call) {
-    OS::AcquireMutex();
-    ++acquired;
-    Writer::beginLeave(call);
-}
-
-void LocalWriter::endLeave(void) {
-    Writer::endLeave();
-    --acquired;
-    OS::ReleaseMutex();
-}
-
-void LocalWriter::flush(void) {
-    /*
-     * Do nothing if the mutex is already acquired (e.g., if a segfault happen
-     * while writing the file) to prevent dead-lock.
-     */
-
-    if (!acquired) {
-        OS::AcquireMutex();
-        if (m_file->isOpened()) {
-            m_file->flush();
-        }
-        OS::ReleaseMutex();
-    }
-}
-
-
-LocalWriter localWriter;
-
-
-} /* namespace Trace */
-
diff --git a/trace_model.cpp b/trace_model.cpp
deleted file mode 100644 (file)
index 25dc4bb..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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 "formatter.hpp"
-#include "trace_model.hpp"
-
-
-namespace Trace {
-
-
-Call::~Call() {
-    for (unsigned i = 0; i < args.size(); ++i) {
-        delete args[i];
-    }
-
-    if (ret) {
-        delete ret;
-    }
-}
-
-
-Struct::~Struct() {
-    for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
-        delete *it;
-    }
-}
-
-
-Array::~Array() {
-    for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
-        delete *it;
-    }
-}
-
-Blob::~Blob() {
-    // Blobs are often bound and referred during many calls, so we can't delete
-    // them here in that case.
-    //
-    // Once bound there is no way to know when they were unbound, which
-    // effectively means we have to leak them.  A better solution would be to
-    // keep a list of bound pointers, and defer the destruction to when the
-    // trace in question has been fully processed.
-    if (!bound) {
-        delete [] buf;
-    }
-}
-
-
-// bool cast
-bool Null   ::toBool(void) const { return false; }
-bool Bool   ::toBool(void) const { return value; }
-bool SInt   ::toBool(void) const { return value != 0; }
-bool UInt   ::toBool(void) const { return value != 0; }
-bool Float  ::toBool(void) const { return value != 0; }
-bool String ::toBool(void) const { return true; }
-bool Enum   ::toBool(void) const { return sig->value != 0; }
-bool Struct ::toBool(void) const { return true; }
-bool Array  ::toBool(void) const { return true; }
-bool Blob   ::toBool(void) const { return true; }
-bool Pointer::toBool(void) const { return value != 0; }
-
-
-// signed integer cast
-signed long long Value  ::toSInt(void) const { assert(0); return 0; }
-signed long long Null   ::toSInt(void) const { return 0; }
-signed long long Bool   ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long SInt   ::toSInt(void) const { return value; }
-signed long long UInt   ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
-signed long long Float  ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long Enum   ::toSInt(void) const { return sig->value; }
-
-
-// unsigned integer cast
-unsigned long long Value  ::toUInt(void) const { assert(0); return 0; }
-unsigned long long Null   ::toUInt(void) const { return 0; }
-unsigned long long Bool   ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long SInt   ::toUInt(void) const { assert(value >= 0); return static_cast<signed long long>(value); }
-unsigned long long UInt   ::toUInt(void) const { return value; }
-unsigned long long Float  ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long Enum   ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
-
-
-// floating point cast
-float Value  ::toFloat(void) const { assert(0); return 0; }
-float Null   ::toFloat(void) const { return 0; }
-float Bool   ::toFloat(void) const { return static_cast<float>(value); }
-float SInt   ::toFloat(void) const { return static_cast<float>(value); }
-float UInt   ::toFloat(void) const { return static_cast<float>(value); }
-float Float  ::toFloat(void) const { return value; }
-float Enum   ::toFloat(void) const { return static_cast<float>(sig->value); }
-
-
-// floating point cast
-double Value  ::toDouble(void) const { assert(0); return 0; }
-double Null   ::toDouble(void) const { return 0; }
-double Bool   ::toDouble(void) const { return static_cast<double>(value); }
-double SInt   ::toDouble(void) const { return static_cast<double>(value); }
-double UInt   ::toDouble(void) const { return static_cast<double>(value); }
-double Float  ::toDouble(void) const { return value; }
-double Enum   ::toDouble(void) const { return static_cast<double>(sig->value); }
-
-
-// pointer cast
-void * Value  ::toPointer(void) const { assert(0); return NULL; }
-void * Null   ::toPointer(void) const { return NULL; }
-void * Blob   ::toPointer(void) const { return buf; }
-void * Pointer::toPointer(void) const { return (void *)value; }
-
-void * Value  ::toPointer(bool bind) { assert(0); return NULL; }
-void * Null   ::toPointer(bool bind) { return NULL; }
-void * Blob   ::toPointer(bool bind) { if (bind) bound = true; return buf; }
-void * Pointer::toPointer(bool bind) { return (void *)value; }
-
-
-// pointer cast
-unsigned long long Value  ::toUIntPtr(void) const { assert(0); return 0; }
-unsigned long long Null   ::toUIntPtr(void) const { return 0; }
-unsigned long long Pointer::toUIntPtr(void) const { return value; }
-
-
-// string cast
-const char * Value ::toString(void) const { assert(0); return NULL; }
-const char * Null  ::toString(void) const { return NULL; }
-const char * String::toString(void) const { return value; }
-
-
-// virtual Value::visit()
-void Null   ::visit(Visitor &visitor) { visitor.visit(this); }
-void Bool   ::visit(Visitor &visitor) { visitor.visit(this); }
-void SInt   ::visit(Visitor &visitor) { visitor.visit(this); }
-void UInt   ::visit(Visitor &visitor) { visitor.visit(this); }
-void Float  ::visit(Visitor &visitor) { visitor.visit(this); }
-void String ::visit(Visitor &visitor) { visitor.visit(this); }
-void Enum   ::visit(Visitor &visitor) { visitor.visit(this); }
-void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
-void Struct ::visit(Visitor &visitor) { visitor.visit(this); }
-void Array  ::visit(Visitor &visitor) { visitor.visit(this); }
-void Blob   ::visit(Visitor &visitor) { visitor.visit(this); }
-void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
-
-
-void Visitor::visit(Null *) { assert(0); }
-void Visitor::visit(Bool *) { assert(0); }
-void Visitor::visit(SInt *) { assert(0); }
-void Visitor::visit(UInt *) { assert(0); }
-void Visitor::visit(Float *) { assert(0); }
-void Visitor::visit(String *) { assert(0); }
-void Visitor::visit(Enum *node) { assert(0); }
-void Visitor::visit(Bitmask *node) { visit(static_cast<UInt *>(node)); }
-void Visitor::visit(Struct *) { assert(0); }
-void Visitor::visit(Array *) { assert(0); }
-void Visitor::visit(Blob *) { assert(0); }
-void Visitor::visit(Pointer *) { assert(0); }
-
-
-class Dumper : public Visitor
-{
-protected:
-    std::ostream &os;
-    Formatter::Formatter *formatter;
-    Formatter::Attribute *normal;
-    Formatter::Attribute *bold;
-    Formatter::Attribute *italic;
-    Formatter::Attribute *red;
-    Formatter::Attribute *pointer;
-    Formatter::Attribute *literal;
-
-public:
-    Dumper(std::ostream &_os, bool color) : os(_os) {
-        formatter = Formatter::defaultFormatter(color);
-        normal = formatter->normal();
-        bold = formatter->bold();
-        italic = formatter->italic();
-        red = formatter->color(Formatter::RED);
-        pointer = formatter->color(Formatter::GREEN);
-        literal = formatter->color(Formatter::BLUE);
-    }
-
-    ~Dumper() {
-        delete normal;
-        delete bold;
-        delete italic;
-        delete red;
-        delete pointer;
-        delete literal;
-        delete formatter;
-    }
-
-    void visit(Null *) {
-        os << "NULL";
-    }
-
-    void visit(Bool *node) {
-        os << literal << (node->value ? "true" : "false") << normal;
-    }
-
-    void visit(SInt *node) {
-        os << literal << node->value << normal;
-    }
-
-    void visit(UInt *node) {
-        os << literal << node->value << normal;
-    }
-
-    void visit(Float *node) {
-        os << literal << node->value << normal;
-    }
-
-    void visit(String *node) {
-        os << literal << "\"";
-        for (const char *it = node->value; *it; ++it) {
-            unsigned char c = (unsigned char) *it;
-            if (c == '\"')
-                os << "\\\"";
-            else if (c == '\\')
-                os << "\\\\";
-            else if (c >= 0x20 && c <= 0x7e)
-                os << c;
-            else if (c == '\t') {
-                os << "\t";
-            } else if (c == '\r') {
-                // Ignore carriage-return
-            } else if (c == '\n') {
-                // Reset formatting so that it looks correct with 'less -R'
-                os << normal << '\n' << literal;
-            } else {
-                unsigned octal0 = c & 0x7;
-                unsigned octal1 = (c >> 3) & 0x7;
-                unsigned octal2 = (c >> 3) & 0x7;
-                os << "\\";
-                if (octal2)
-                    os << octal2;
-                if (octal1)
-                    os << octal1;
-                os << octal0;
-            }
-        }
-        os << "\"" << normal;
-    }
-
-    void visit(Enum *node) {
-        os << literal << node->sig->name << normal;
-    }
-
-    void visit(Bitmask *bitmask) {
-        unsigned long long value = bitmask->value;
-        const BitmaskSig *sig = bitmask->sig;
-        bool first = true;
-        for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) {
-            if ((it->value && (value & it->value) == it->value) ||
-                (!it->value && value == 0)) {
-                if (!first) {
-                    os << " | ";
-                }
-                os << literal << it->name << normal;
-                value &= ~it->value;
-                first = false;
-            }
-        }
-        if (value || first) {
-            if (!first) {
-                os << " | ";
-            }
-            os << literal << "0x" << std::hex << value << std::dec << normal;
-        }
-    }
-
-    void visit(Struct *s) {
-        const char *sep = "";
-        os << "{";
-        for (unsigned i = 0; i < s->members.size(); ++i) {
-            os << sep << italic << s->sig->member_names[i] << normal << " = ";
-            _visit(s->members[i]);
-            sep = ", ";
-        }
-        os << "}";
-    }
-
-    void visit(Array *array) {
-        if (array->values.size() == 1) {
-            os << "&";
-            _visit(array->values[0]);
-        }
-        else {
-            const char *sep = "";
-            os << "{";
-            for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
-                os << sep;
-                _visit(*it);
-                sep = ", ";
-            }
-            os << "}";
-        }
-    }
-
-    void visit(Blob *blob) {
-        os << pointer << "blob(" << blob->size << ")" << normal;
-    }
-
-    void visit(Pointer *p) {
-        os << pointer << "0x" << std::hex << p->value << std::dec << normal;
-    }
-
-    void visit(Call *call) {
-        const char *sep = "";
-        os << bold << call->sig->name << normal << "(";
-        for (unsigned i = 0; i < call->args.size(); ++i) {
-            os << sep << italic << call->sig->arg_names[i] << normal << " = ";
-            if (call->args[i]) {
-                _visit(call->args[i]);
-            } else {
-               os << "?";
-            }
-            sep = ", ";
-        }
-        os << ")";
-        if (call->ret) {
-            os << " = ";
-            _visit(call->ret);
-        }
-        os << "\n";
-    }
-};
-
-
-void Value::dump(std::ostream &os, bool color) {
-    Dumper d(os, color);
-    visit(d);
-}
-
-
-static Null null;
-
-const Value & Value::operator[](size_t index) const {
-    const Array *array = dynamic_cast<const Array *>(this);
-    if (array) {
-        if (index < array->values.size()) {
-            return *array->values[index];
-        }
-    }
-    return null;
-}
-
-void Call::dump(std::ostream &os, bool color) {
-    Dumper d(os, color);
-    os << no << " ";
-    d.visit(this);
-}
-
-
-} /* namespace Trace */
diff --git a/trace_model.hpp b/trace_model.hpp
deleted file mode 100644 (file)
index a284754..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Object hierarchy for describing the traces in memory.
- */
-
-#ifndef _TRACE_MODEL_HPP_
-#define _TRACE_MODEL_HPP_
-
-
-#include <assert.h>
-
-#include <map>
-#include <vector>
-#include <iostream>
-
-
-namespace Trace {
-
-
-typedef unsigned Id;
-
-
-struct FunctionSig {
-    Id id;
-    const char *name;
-    unsigned num_args;
-    const char **arg_names;
-};
-
-
-struct StructSig {
-    Id id;
-    const char *name;
-    unsigned num_members;
-    const char **member_names;
-};
-
-
-struct EnumSig {
-    Id id;
-    const char *name;
-    signed long long value;
-};
-
-
-struct BitmaskFlag {
-    const char *name;
-    unsigned long long value;
-};
-
-
-struct BitmaskSig {
-    Id id;
-    unsigned num_flags;
-    const BitmaskFlag *flags;
-};
-
-
-class Visitor;
-
-
-class Value
-{
-public:
-    virtual ~Value() {}
-    virtual void visit(Visitor &visitor) = 0;
-
-    virtual bool toBool(void) const = 0;
-    virtual signed long long toSInt(void) const;
-    virtual unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-
-    virtual void *toPointer(void) const;
-    virtual void *toPointer(bool bind);
-    virtual unsigned long long toUIntPtr(void) const;
-    virtual const char *toString(void) const;
-
-    const Value & operator[](size_t index) const;
-
-    void dump(std::ostream &os, bool color=true);
-};
-
-
-class Null : public Value
-{
-public:
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void *toPointer(void) const;
-    void *toPointer(bool bind);
-    unsigned long long toUIntPtr(void) const;
-    const char *toString(void) const;
-    void visit(Visitor &visitor);
-};
-
-
-class Bool : public Value
-{
-public:
-    Bool(bool _value) : value(_value) {}
-
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void visit(Visitor &visitor);
-
-    bool value;
-};
-
-
-class SInt : public Value
-{
-public:
-    SInt(signed long long _value) : value(_value) {}
-
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void visit(Visitor &visitor);
-
-    signed long long value;
-};
-
-
-class UInt : public Value
-{
-public:
-    UInt(unsigned long long _value) : value(_value) {}
-
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void visit(Visitor &visitor);
-
-    unsigned long long value;
-};
-
-
-class Float : public Value
-{
-public:
-    Float(double _value) : value(_value) {}
-
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void visit(Visitor &visitor);
-
-    double value;
-};
-
-
-class String : public Value
-{
-public:
-    String(const char * _value) : value(_value) {}
-
-    bool toBool(void) const;
-    const char *toString(void) const;
-    void visit(Visitor &visitor);
-
-    const char * value;
-};
-
-
-class Enum : public Value
-{
-public:
-    Enum(const EnumSig *_sig) : sig(_sig) {}
-
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
-    void visit(Visitor &visitor);
-
-    const EnumSig *sig;
-};
-
-
-class Bitmask : public UInt
-{
-public:
-    Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}
-
-    void visit(Visitor &visitor);
-
-    const BitmaskSig *sig;
-};
-
-
-class Struct : public Value
-{
-public:
-    Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { }
-    ~Struct();
-
-    bool toBool(void) const;
-    void visit(Visitor &visitor);
-
-    const StructSig *sig;
-    std::vector<Value *> members;
-};
-
-
-class Array : public Value
-{
-public:
-    Array(size_t len) : values(len) {}
-    ~Array();
-
-    bool toBool(void) const;
-    void visit(Visitor &visitor);
-
-    std::vector<Value *> values;
-};
-
-
-class Blob : public Value
-{
-public:
-    Blob(size_t _size) {
-        size = _size;
-        buf = new char[_size];
-        bound = false;
-    }
-
-    ~Blob();
-
-    bool toBool(void) const;
-    void *toPointer(void) const;
-    void *toPointer(bool bind);
-    void visit(Visitor &visitor);
-
-    size_t size;
-    char *buf;
-    bool bound;
-};
-
-
-class Pointer : public UInt
-{
-public:
-    Pointer(unsigned long long value) : UInt(value) {}
-
-    bool toBool(void) const;
-    void *toPointer(void) const;
-    void *toPointer(bool bind);
-    unsigned long long toUIntPtr(void) const;
-    void visit(Visitor &visitor);
-};
-
-
-class Visitor
-{
-public:
-    virtual void visit(Null *);
-    virtual void visit(Bool *);
-    virtual void visit(SInt *);
-    virtual void visit(UInt *);
-    virtual void visit(Float *);
-    virtual void visit(String *);
-    virtual void visit(Enum *);
-    virtual void visit(Bitmask *);
-    virtual void visit(Struct *);
-    virtual void visit(Array *);
-    virtual void visit(Blob *);
-    virtual void visit(Pointer *);
-
-protected:
-    inline void _visit(Value *value) {
-        if (value) { 
-            value->visit(*this); 
-        }
-    }
-};
-
-
-inline std::ostream & operator <<(std::ostream &os, Value *value) {
-    if (value) {
-        value->dump(os);
-    }
-    return os;
-}
-
-
-class Call
-{
-public:
-    unsigned no;
-    const FunctionSig *sig;
-    std::vector<Value *> args;
-    Value *ret;
-
-    Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
-    ~Call();
-
-    inline const char * name(void) const {
-        return sig->name;
-    }
-
-    inline Value & arg(unsigned index) {
-        assert(index < args.size());
-        return *(args[index]);
-    }
-
-    void dump(std::ostream &os, bool color=true);
-};
-
-
-inline std::ostream & operator <<(std::ostream &os, Call &call) {
-    call.dump(os);
-    return os;
-}
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_MODEL_HPP_ */
diff --git a/trace_model_writer.cpp b/trace_model_writer.cpp
deleted file mode 100644 (file)
index dcfcf86..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * 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 "trace_writer.hpp"
-
-
-namespace Trace {
-
-
-class ModelWriter : public Visitor
-{
-protected:
-    Writer &writer;
-
-public:
-    ModelWriter(Writer &_writer) :
-        writer(_writer) {
-    }
-
-    void visit(Null *) {
-        writer.writeNull();
-    }
-
-    void visit(Bool *node) {
-        writer.writeBool(node->value);
-    }
-
-    void visit(SInt *node) {
-        writer.writeSInt(node->value);
-    }
-
-    void visit(UInt *node) {
-        writer.writeUInt(node->value);
-    }
-
-    void visit(Float *node) {
-        writer.writeFloat(node->value);
-    }
-
-    void visit(String *node) {
-        writer.writeString(node->value);
-    }
-
-    void visit(Enum *node) {
-        writer.writeEnum(node->sig);
-    }
-
-    void visit(Bitmask *node) {
-        writer.writeBitmask(node->sig, node->value);
-    }
-
-    void visit(Struct *node) {
-        writer.beginStruct(node->sig);
-        for (unsigned i = 0; i < node->sig->num_members; ++i) {
-            _visit(node->members[i]);
-        }
-        writer.endStruct();
-    }
-
-    void visit(Array *node) {
-        writer.beginArray(node->values.size());
-        for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
-            _visit(*it);
-        }
-        writer.endArray();
-    }
-
-    void visit(Blob *node) {
-        writer.writeBlob(node->buf, node->size);
-    }
-
-    void visit(Pointer *node) {
-        writer.writeOpaque((const void *) (size_t) node->value);
-    }
-
-    void visit(Call *call) {
-        unsigned call_no = writer.beginEnter(call->sig);
-        for (unsigned i = 0; i < call->args.size(); ++i) {
-            if (call->args[i]) {
-                writer.beginArg(i);
-                _visit(call->args[i]);
-                writer.endArg();
-            }
-        }
-        writer.endEnter();
-        writer.beginLeave(call_no);
-        if (call->ret) {
-            writer.beginReturn();
-            _visit(call->ret);
-            writer.endReturn();
-        }
-        writer.endLeave();
-    }
-};
-
-
-void Writer::writeCall(Call *call) {
-    ModelWriter visitor(*this);
-    visitor.visit(call);
-}
-
-
-} /* namespace Trace */
-
diff --git a/trace_parser.cpp b/trace_parser.cpp
deleted file mode 100644 (file)
index 44d1786..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2010 VMware, Inc.
- * 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 <assert.h>
-#include <stdlib.h>
-
-#include "trace_file.hpp"
-#include "trace_snappyfile.hpp"
-#include "trace_parser.hpp"
-
-
-#define TRACE_VERBOSE 0
-
-
-namespace Trace {
-
-
-Parser::Parser() {
-    file = NULL;
-    next_call_no = 0;
-    version = 0;
-}
-
-
-Parser::~Parser() {
-    close();
-}
-
-
-bool Parser::open(const char *filename) {
-    assert(!file);
-    if (File::isZLibCompressed(filename)) {
-        file = new ZLibFile;
-    } else {
-        file = new SnappyFile;
-    }
-
-    if (!file->open(filename, File::Read)) {
-        return false;
-    }
-
-    version = read_uint();
-    if (version > TRACE_VERSION) {
-        std::cerr << "error: unsupported trace format version " << version << "\n";
-        return false;
-    }
-
-    return true;
-}
-
-template <typename Iter>
-inline void
-deleteAll(Iter begin, Iter end)
-{
-    while (begin != end) {
-        delete *begin;
-        ++begin;
-    }
-}
-
-template <typename Container>
-inline void
-deleteAll(Container &c)
-{
-    deleteAll(c.begin(), c.end());
-    c.clear();
-}
-
-void Parser::close(void) {
-    if (file) {
-        file->close();
-        delete file;
-        file = NULL;
-    }
-
-    deleteAll(calls);
-    deleteAll(functions);
-    deleteAll(structs);
-    deleteAll(enums);
-    deleteAll(bitmasks);
-}
-
-
-Call *Parser::parse_call(void) {
-    do {
-        int c = read_byte();
-        switch(c) {
-        case Trace::EVENT_ENTER:
-            parse_enter();
-            break;
-        case Trace::EVENT_LEAVE:
-            return parse_leave();
-        default:
-            std::cerr << "error: unknown event " << c << "\n";
-            exit(1);
-        case -1:
-            for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
-                std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
-                std::cerr << **it << "\n";
-            }
-            return NULL;
-        }
-    } while(true);
-}
-
-
-/**
- * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
- */
-template<class T>
-T *lookup(std::vector<T *> &map, size_t index) {
-    if (index >= map.size()) {
-        map.resize(index + 1);
-        return NULL;
-    } else {
-        return map[index];
-    }
-}
-
-
-void Parser::parse_enter(void) {
-    size_t id = read_uint();
-
-    FunctionSig *sig = lookup(functions, id);
-    if (!sig) {
-        sig = new FunctionSig;
-        sig->id = id;
-        sig->name = read_string();
-        sig->num_args = read_uint();
-        const char **arg_names = new const char *[sig->num_args];
-        for (unsigned i = 0; i < sig->num_args; ++i) {
-            arg_names[i] = read_string();
-        }
-        sig->arg_names = arg_names;
-        functions[id] = sig;
-    }
-    assert(sig);
-
-    Call *call = new Call(sig);
-    call->no = next_call_no++;
-
-    if (parse_call_details(call)) {
-        calls.push_back(call);
-    } else {
-        delete call;
-    }
-}
-
-
-Call *Parser::parse_leave(void) {
-    unsigned call_no = read_uint();
-    Call *call = NULL;
-    for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
-        if ((*it)->no == call_no) {
-            call = *it;
-            calls.erase(it);
-            break;
-        }
-    }
-    if (!call) {
-        return NULL;
-    }
-
-    if (parse_call_details(call)) {
-        return call;
-    } else {
-        delete call;
-        return NULL;
-    }
-}
-
-
-bool Parser::parse_call_details(Call *call) {
-    do {
-        int c = read_byte();
-        switch(c) {
-        case Trace::CALL_END:
-            return true;
-        case Trace::CALL_ARG:
-            parse_arg(call);
-            break;
-        case Trace::CALL_RET:
-            call->ret = parse_value();
-            break;
-        default:
-            std::cerr << "error: ("<<call->name()<< ") unknown call detail "
-                      << c << "\n";
-            exit(1);
-        case -1:
-            return false;
-        }
-    } while(true);
-}
-
-
-void Parser::parse_arg(Call *call) {
-    unsigned index = read_uint();
-    Value *value = parse_value();
-    if (index >= call->args.size()) {
-        call->args.resize(index + 1);
-    }
-    call->args[index] = value;
-}
-
-
-Value *Parser::parse_value(void) {
-    int c;
-    Value *value;
-    c = read_byte();
-    switch(c) {
-    case Trace::TYPE_NULL:
-        value = new Null;
-        break;
-    case Trace::TYPE_FALSE:
-        value = new Bool(false);
-        break;
-    case Trace::TYPE_TRUE:
-        value = new Bool(true);
-        break;
-    case Trace::TYPE_SINT:
-        value = parse_sint();
-        break;
-    case Trace::TYPE_UINT:
-        value = parse_uint();
-        break;
-    case Trace::TYPE_FLOAT:
-        value = parse_float();
-        break;
-    case Trace::TYPE_DOUBLE:
-        value = parse_double();
-        break;
-    case Trace::TYPE_STRING:
-        value = parse_string();
-        break;
-    case Trace::TYPE_ENUM:
-        value = parse_enum();
-        break;
-    case Trace::TYPE_BITMASK:
-        value = parse_bitmask();
-        break;
-    case Trace::TYPE_ARRAY:
-        value = parse_array();
-        break;
-    case Trace::TYPE_STRUCT:
-        value = parse_struct();
-        break;
-    case Trace::TYPE_BLOB:
-        value = parse_blob();
-        break;
-    case Trace::TYPE_OPAQUE:
-        value = parse_opaque();
-        break;
-    default:
-        std::cerr << "error: unknown type " << c << "\n";
-        exit(1);
-    case -1:
-        value = NULL;
-        break;
-    }
-#if TRACE_VERBOSE
-    if (value) {
-        std::cerr << "\tVALUE " << value << "\n";
-    }
-#endif
-    return value;
-}
-
-
-Value *Parser::parse_sint() {
-    return new SInt(-(signed long long)read_uint());
-}
-
-
-Value *Parser::parse_uint() {
-    return new UInt(read_uint());
-}
-
-
-Value *Parser::parse_float() {
-    float value;
-    file->read(&value, sizeof value);
-    return new Float(value);
-}
-
-
-Value *Parser::parse_double() {
-    double value;
-    file->read(&value, sizeof value);
-    return new Float(value);
-}
-
-
-Value *Parser::parse_string() {
-    return new String(read_string());
-}
-
-
-Value *Parser::parse_enum() {
-    size_t id = read_uint();
-    EnumSig *sig = lookup(enums, id);
-    if (!sig) {
-        sig = new EnumSig;
-        sig->id = id;
-        sig->name = read_string();
-        Value *value = parse_value();
-        sig->value = value->toSInt();
-        delete value;
-        enums[id] = sig;
-    }
-    assert(sig);
-    return new Enum(sig);
-}
-
-
-Value *Parser::parse_bitmask() {
-    size_t id = read_uint();
-    BitmaskSig *sig = lookup(bitmasks, id);
-    if (!sig) {
-        sig = new BitmaskSig;
-        sig->id = id;
-        sig->num_flags = read_uint();
-        BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
-        for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
-            it->name = read_string();
-            it->value = read_uint();
-            if (it->value == 0 && it != flags) {
-                std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
-            }
-        }
-        sig->flags = flags;
-        bitmasks[id] = sig;
-    }
-    assert(sig);
-
-    unsigned long long value = read_uint();
-
-    return new Bitmask(sig, value);
-}
-
-
-Value *Parser::parse_array(void) {
-    size_t len = read_uint();
-    Array *array = new Array(len);
-    for (size_t i = 0; i < len; ++i) {
-        array->values[i] = parse_value();
-    }
-    return array;
-}
-
-
-Value *Parser::parse_blob(void) {
-    size_t size = read_uint();
-    Blob *blob = new Blob(size);
-    if (size) {
-        file->read(blob->buf, (unsigned)size);
-    }
-    return blob;
-}
-
-
-Value *Parser::parse_struct() {
-    size_t id = read_uint();
-
-    StructSig *sig = lookup(structs, id);
-    if (!sig) {
-        sig = new StructSig;
-        sig->id = id;
-        sig->name = read_string();
-        sig->num_members = read_uint();
-        const char **member_names = new const char *[sig->num_members];
-        for (unsigned i = 0; i < sig->num_members; ++i) {
-            member_names[i] = read_string();
-        }
-        sig->member_names = member_names;
-        structs[id] = sig;
-    }
-    assert(sig);
-
-    Struct *value = new Struct(sig);
-
-    for (size_t i = 0; i < sig->num_members; ++i) {
-        value->members[i] = parse_value();
-    }
-
-    return value;
-}
-
-
-Value *Parser::parse_opaque() {
-    unsigned long long addr;
-    addr = read_uint();
-    return new Pointer(addr);
-}
-
-
-const char * Parser::read_string(void) {
-    size_t len = read_uint();
-    char * value = new char[len + 1];
-    if (len) {
-        file->read(value, (unsigned)len);
-    }
-    value[len] = 0;
-#if TRACE_VERBOSE
-    std::cerr << "\tSTRING \"" << value << "\"\n";
-#endif
-    return value;
-}
-
-
-unsigned long long Parser::read_uint(void) {
-    unsigned long long value = 0;
-    int c;
-    unsigned shift = 0;
-    do {
-        c = file->getc();
-        if (c == -1) {
-            break;
-        }
-        value |= (unsigned long long)(c & 0x7f) << shift;
-        shift += 7;
-    } while(c & 0x80);
-#if TRACE_VERBOSE
-    std::cerr << "\tUINT " << value << "\n";
-#endif
-    return value;
-}
-
-
-inline int Parser::read_byte(void) {
-    int c = file->getc();
-#if TRACE_VERBOSE
-    if (c < 0)
-        std::cerr << "\tEOF" << "\n";
-    else
-        std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
-#endif
-    return c;
-}
-
-
-} /* namespace Trace */
diff --git a/trace_parser.hpp b/trace_parser.hpp
deleted file mode 100644 (file)
index 4fff9ad..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-#ifndef _TRACE_PARSER_HPP_
-#define _TRACE_PARSER_HPP_
-
-
-#include <iostream>
-#include <list>
-
-#include "trace_format.hpp"
-#include "trace_model.hpp"
-
-
-namespace Trace {
-
-class File;
-
-class Parser
-{
-protected:
-    File *file;
-
-    typedef std::list<Call *> CallList;
-    CallList calls;
-
-    typedef std::vector<FunctionSig *> FunctionMap;
-    FunctionMap functions;
-
-    typedef std::vector<StructSig *> StructMap;
-    StructMap structs;
-
-    typedef std::vector<EnumSig *> EnumMap;
-    EnumMap enums;
-
-    typedef std::vector<BitmaskSig *> BitmaskMap;
-    BitmaskMap bitmasks;
-
-    unsigned next_call_no;
-
-public:
-    unsigned long long version;
-
-    Parser();
-
-    ~Parser();
-
-    bool open(const char *filename);
-
-    void close(void);
-
-    Call *parse_call(void);
-
-protected:
-    void parse_enter(void);
-
-    Call *parse_leave(void);
-
-    bool parse_call_details(Call *call);
-
-    void parse_arg(Call *call);
-
-    Value *parse_value(void);
-
-    Value *parse_sint();
-
-    Value *parse_uint();
-
-    Value *parse_float();
-
-    Value *parse_double();
-
-    Value *parse_string();
-
-    Value *parse_enum();
-
-    Value *parse_bitmask();
-
-    Value *parse_array(void);
-
-    Value *parse_blob(void);
-
-    Value *parse_struct();
-
-    Value *parse_opaque();
-
-    const char * read_string(void);
-
-    unsigned long long read_uint(void);
-
-    inline int read_byte(void);
-};
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_PARSER_HPP_ */
diff --git a/trace_snappyfile.cpp b/trace_snappyfile.cpp
deleted file mode 100644 (file)
index ad0a577..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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 "trace_snappyfile.hpp"
-
-#include <snappy.h>
-
-#include <assert.h>
-#include <string.h>
-
-using namespace Trace;
-
-/*
- * Snappy file format.
- * -------------------
- *
- * Snappy at its core is just a compressoin algorithm so we're
- * creating a new file format which uses snappy compression
- * to hold the trace data.
- *
- * The file is composed of a number of chunks, they are:
- * chunk {
- *     uint32 - specifying the length of the compressed data
- *     compressed data
- * }
- * File can contain any number of such chunks.
- * The default size of an uncompressed chunk is specified in
- * SNAPPY_CHUNK_SIZE.
- *
- * Note:
- * Currently the default size for a a to-be-compressed data is
- * 1mb, meaning that the compressed data will be <= 1mb.
- * The reason it's 1mb is because it seems
- * to offer a pretty good compression/disk io speed ratio
- * but that might change.
- *
- */
-
-SnappyFile::SnappyFile(const std::string &filename,
-                              File::Mode mode)
-    : File(),
-      m_cache(0),
-      m_cachePtr(0),
-      m_cacheSize(0)
-{
-    m_compressedCache = new char[SNAPPY_CHUNK_SIZE];
-}
-
-SnappyFile::~SnappyFile()
-{
-    delete [] m_compressedCache;
-}
-
-bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
-{
-    std::ios_base::openmode fmode = std::fstream::binary;
-    if (mode == File::Write) {
-        fmode |= (std::fstream::out | std::fstream::trunc);
-        createCache(SNAPPY_CHUNK_SIZE);
-    } else if (mode == File::Read) {
-        fmode |= std::fstream::in;
-    }
-
-    m_stream.open(filename.c_str(), fmode);
-
-    //read in the initial buffer if we're reading
-    if (m_stream.is_open() && mode == File::Read) {
-        // read the snappy file identifier
-        unsigned char byte1, byte2;
-        m_stream >> byte1;
-        m_stream >> byte2;
-        assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
-
-        flushCache();
-    } else if (m_stream.is_open() && mode == File::Write) {
-        // write the snappy file identifier
-        m_stream << SNAPPY_BYTE1;
-        m_stream << SNAPPY_BYTE2;
-    }
-    return m_stream.is_open();
-}
-
-bool SnappyFile::rawWrite(const void *buffer, int length)
-{
-    if (freeCacheSize() > length) {
-        memcpy(m_cachePtr, buffer, length);
-        m_cachePtr += length;
-    } else if (freeCacheSize() == length) {
-        memcpy(m_cachePtr, buffer, length);
-        m_cachePtr += length;
-        flushCache();
-    } else {
-        int sizeToWrite = length;
-
-        while (sizeToWrite >= freeCacheSize()) {
-            int endSize = freeCacheSize();
-            int offset = length - sizeToWrite;
-            memcpy(m_cachePtr, (char*)buffer + offset, endSize);
-            sizeToWrite -= endSize;
-            m_cachePtr += endSize;
-            flushCache();
-        }
-        if (sizeToWrite) {
-            int offset = length - sizeToWrite;
-            memcpy(m_cachePtr, (char*)buffer + offset, sizeToWrite);
-            m_cachePtr += sizeToWrite;
-        }
-    }
-
-    return true;
-}
-
-bool SnappyFile::rawRead(void *buffer, int length)
-{
-    if (endOfData()) {
-        return false;
-    }
-
-    if (freeCacheSize() >= length) {
-        memcpy(buffer, m_cachePtr, length);
-        m_cachePtr += length;
-    } else {
-        int sizeToRead = length;
-        int offset = 0;
-        while (sizeToRead) {
-            int chunkSize = std::min(freeCacheSize(), sizeToRead);
-            offset = length - sizeToRead;
-            memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
-            m_cachePtr += chunkSize;
-            sizeToRead -= chunkSize;
-            if (sizeToRead > 0)
-                flushCache();
-            if (!m_cacheSize)
-                break;
-        }
-    }
-
-    return true;
-}
-
-int SnappyFile::rawGetc()
-{
-    int c = 0;
-    if (!rawRead(&c, 1))
-        return -1;
-    return c;
-}
-
-void SnappyFile::rawClose()
-{
-    flushCache();
-    m_stream.close();
-    delete [] m_cache;
-    m_cache = NULL;
-    m_cachePtr = NULL;
-}
-
-void SnappyFile::rawFlush()
-{
-    flushCache();
-    m_stream.flush();
-}
-
-void SnappyFile::flushCache()
-{
-    if (m_mode == File::Write) {
-        size_t compressedLength;
-
-        ::snappy::RawCompress(m_cache, SNAPPY_CHUNK_SIZE - freeCacheSize(),
-                              m_compressedCache, &compressedLength);
-
-        writeCompressedLength(compressedLength);
-        m_stream.write(m_compressedCache, compressedLength);
-        m_cachePtr = m_cache;
-    } else if (m_mode == File::Read) {
-        if (m_stream.eof())
-            return;
-        //assert(m_cachePtr == m_cache + m_cacheSize);
-        size_t compressedLength;
-        compressedLength = readCompressedLength();
-        m_stream.read((char*)m_compressedCache, compressedLength);
-        /*
-         * The reason we peek here is because the last read will
-         * read all the way until the last character, but that will not
-         * trigger m_stream.eof() to be set, so by calling peek
-         * we assure that if we in fact have read the entire stream
-         * then the m_stream.eof() is always set.
-         */
-        m_stream.peek();
-        ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
-                                        &m_cacheSize);
-        if (m_cache)
-            delete [] m_cache;
-        createCache(m_cacheSize);
-        ::snappy::RawUncompress(m_compressedCache, compressedLength,
-                                m_cache);
-    }
-}
-
-void SnappyFile::createCache(size_t size)
-{
-    m_cache = new char[size];
-    m_cachePtr = m_cache;
-    m_cacheSize = size;
-}
-
-void SnappyFile::writeCompressedLength(uint32_t value)
-{
-    m_stream.write((const char*)&value, sizeof value);
-}
-
-uint32_t SnappyFile::readCompressedLength()
-{
-    uint32_t len;
-    m_stream.read((char*)&len, sizeof len);
-    return len;
-}
diff --git a/trace_snappyfile.hpp b/trace_snappyfile.hpp
deleted file mode 100644 (file)
index c8c415b..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#ifndef TRACE_SNAPPYFILE_HPP
-#define TRACE_SNAPPYFILE_HPP
-
-#include "trace_file.hpp"
-
-#include <string>
-#include <fstream>
-
-#include <stdint.h>
-
-namespace snappy {
-    class File;
-}
-
-namespace Trace {
-
-#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024)
-
-#define SNAPPY_BYTE1 'a'
-#define SNAPPY_BYTE2 't'
-
-
-class SnappyFile : public File {
-public:
-    SnappyFile(const std::string &filename = std::string(),
-               File::Mode mode = File::Read);
-    virtual ~SnappyFile();
-
-protected:
-    virtual bool rawOpen(const std::string &filename, File::Mode mode);
-    virtual bool rawWrite(const void *buffer, int length);
-    virtual bool rawRead(void *buffer, int length);
-    virtual int rawGetc();
-    virtual void rawClose();
-    virtual void rawFlush();
-
-private:
-    inline int freeCacheSize() const
-    {
-        if (m_cacheSize > 0)
-            return m_cacheSize - (m_cachePtr - m_cache);
-        else
-            return 0;
-    }
-    inline bool endOfData() const
-    {
-        return m_stream.eof() && freeCacheSize() == 0;
-    }
-    void flushCache();
-    void createCache(size_t size);
-    void writeCompressedLength(uint32_t  num);
-    uint32_t readCompressedLength();
-private:
-    std::fstream m_stream;
-    char *m_cache;
-    char *m_cachePtr;
-    size_t m_cacheSize;
-
-    char *m_compressedCache;
-};
-
-}
-
-#endif // TRACE_SNAPPYFILE_HPP
diff --git a/trace_writer.cpp b/trace_writer.cpp
deleted file mode 100644 (file)
index 5a5f1f7..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007-2009 VMware, Inc.
- * 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 <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "os.hpp"
-#include "trace_writer.hpp"
-#include "trace_snappyfile.hpp"
-#include "trace_format.hpp"
-
-
-namespace Trace {
-
-
-Writer::Writer() :
-    call_no(0)
-{
-    m_file = new Trace::SnappyFile;
-    close();
-}
-
-Writer::~Writer()
-{
-    close();
-    delete m_file;
-    m_file = NULL;
-}
-
-void
-Writer::close(void) {
-    m_file->close();
-}
-
-bool
-Writer::open(const char *filename) {
-    close();
-
-    if (!m_file->open(filename, File::Write)) {
-        return false;
-    }
-
-    call_no = 0;
-    functions.clear();
-    structs.clear();
-    enums.clear();
-    bitmasks.clear();
-
-    _writeUInt(TRACE_VERSION);
-
-    return true;
-}
-
-void inline
-Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
-    m_file->write(sBuffer, dwBytesToWrite);
-}
-
-void inline
-Writer::_writeByte(char c) {
-    _write(&c, 1);
-}
-
-void inline
-Writer::_writeUInt(unsigned long long value) {
-    char buf[2 * sizeof value];
-    unsigned len;
-
-    len = 0;
-    do {
-        assert(len < sizeof buf);
-        buf[len] = 0x80 | (value & 0x7f);
-        value >>= 7;
-        ++len;
-    } while (value);
-
-    assert(len);
-    buf[len - 1] &= 0x7f;
-
-    _write(buf, len);
-}
-
-void inline
-Writer::_writeFloat(float value) {
-    assert(sizeof value == 4);
-    _write((const char *)&value, sizeof value);
-}
-
-void inline
-Writer::_writeDouble(double value) {
-    assert(sizeof value == 8);
-    _write((const char *)&value, sizeof value);
-}
-
-void inline
-Writer::_writeString(const char *str) {
-    size_t len = strlen(str);
-    _writeUInt(len);
-    _write(str, len);
-}
-
-inline bool lookup(std::vector<bool> &map, size_t index) {
-    if (index >= map.size()) {
-        map.resize(index + 1);
-        return false;
-    } else {
-        return map[index];
-    }
-}
-
-unsigned Writer::beginEnter(const FunctionSig *sig) {
-    _writeByte(Trace::EVENT_ENTER);
-    _writeUInt(sig->id);
-    if (!lookup(functions, sig->id)) {
-        _writeString(sig->name);
-        _writeUInt(sig->num_args);
-        for (unsigned i = 0; i < sig->num_args; ++i) {
-            _writeString(sig->arg_names[i]);
-        }
-        functions[sig->id] = true;
-    }
-
-    return call_no++;
-}
-
-void Writer::endEnter(void) {
-    _writeByte(Trace::CALL_END);
-}
-
-void Writer::beginLeave(unsigned call) {
-    _writeByte(Trace::EVENT_LEAVE);
-    _writeUInt(call);
-}
-
-void Writer::endLeave(void) {
-    _writeByte(Trace::CALL_END);
-}
-
-void Writer::beginArg(unsigned index) {
-    _writeByte(Trace::CALL_ARG);
-    _writeUInt(index);
-}
-
-void Writer::beginReturn(void) {
-    _writeByte(Trace::CALL_RET);
-}
-
-void Writer::beginArray(size_t length) {
-    _writeByte(Trace::TYPE_ARRAY);
-    _writeUInt(length);
-}
-
-void Writer::beginStruct(const StructSig *sig) {
-    _writeByte(Trace::TYPE_STRUCT);
-    _writeUInt(sig->id);
-    if (!lookup(structs, sig->id)) {
-        _writeString(sig->name);
-        _writeUInt(sig->num_members);
-        for (unsigned i = 0; i < sig->num_members; ++i) {
-            _writeString(sig->member_names[i]);
-        }
-        structs[sig->id] = true;
-    }
-}
-
-void Writer::writeBool(bool value) {
-    _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
-}
-
-void Writer::writeSInt(signed long long value) {
-    if (value < 0) {
-        _writeByte(Trace::TYPE_SINT);
-        _writeUInt(-value);
-    } else {
-        _writeByte(Trace::TYPE_UINT);
-        _writeUInt(value);
-    }
-}
-
-void Writer::writeUInt(unsigned long long value) {
-    _writeByte(Trace::TYPE_UINT);
-    _writeUInt(value);
-}
-
-void Writer::writeFloat(float value) {
-    _writeByte(Trace::TYPE_FLOAT);
-    _writeFloat(value);
-}
-
-void Writer::writeDouble(double value) {
-    _writeByte(Trace::TYPE_DOUBLE);
-    _writeDouble(value);
-}
-
-void Writer::writeString(const char *str) {
-    if (!str) {
-        Writer::writeNull();
-        return;
-    }
-    _writeByte(Trace::TYPE_STRING);
-    _writeString(str);
-}
-
-void Writer::writeString(const char *str, size_t len) {
-    if (!str) {
-        Writer::writeNull();
-        return;
-    }
-    _writeByte(Trace::TYPE_STRING);
-    _writeUInt(len);
-    _write(str, len);
-}
-
-void Writer::writeWString(const wchar_t *str) {
-    if (!str) {
-        Writer::writeNull();
-        return;
-    }
-    _writeByte(Trace::TYPE_STRING);
-    _writeString("<wide-string>");
-}
-
-void Writer::writeBlob(const void *data, size_t size) {
-    if (!data) {
-        Writer::writeNull();
-        return;
-    }
-    _writeByte(Trace::TYPE_BLOB);
-    _writeUInt(size);
-    if (size) {
-        _write(data, size);
-    }
-}
-
-void Writer::writeEnum(const EnumSig *sig) {
-    _writeByte(Trace::TYPE_ENUM);
-    _writeUInt(sig->id);
-    if (!lookup(enums, sig->id)) {
-        _writeString(sig->name);
-        Writer::writeSInt(sig->value);
-        enums[sig->id] = true;
-    }
-}
-
-void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
-    _writeByte(Trace::TYPE_BITMASK);
-    _writeUInt(sig->id);
-    if (!lookup(bitmasks, sig->id)) {
-        _writeUInt(sig->num_flags);
-        for (unsigned i = 0; i < sig->num_flags; ++i) {
-            if (i != 0 && sig->flags[i].value == 0) {
-                OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
-            }
-            _writeString(sig->flags[i].name);
-            _writeUInt(sig->flags[i].value);
-        }
-        bitmasks[sig->id] = true;
-    }
-    _writeUInt(value);
-}
-
-void Writer::writeNull(void) {
-    _writeByte(Trace::TYPE_NULL);
-}
-
-void Writer::writeOpaque(const void *addr) {
-    if (!addr) {
-        Writer::writeNull();
-        return;
-    }
-    _writeByte(Trace::TYPE_OPAQUE);
-    _writeUInt((size_t)addr);
-}
-
-
-} /* namespace Trace */
-
diff --git a/trace_writer.hpp b/trace_writer.hpp
deleted file mode 100644 (file)
index dfb76b2..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace writing functions.
- */
-
-#ifndef _TRACE_WRITER_HPP_
-#define _TRACE_WRITER_HPP_
-
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "trace_model.hpp"
-
-
-namespace Trace {
-    class File;
-
-    class Writer {
-    protected:
-        File *m_file;
-        unsigned call_no;
-
-        std::vector<bool> functions;
-        std::vector<bool> structs;
-        std::vector<bool> enums;
-        std::vector<bool> bitmasks;
-
-    public:
-        Writer();
-        ~Writer();
-
-        bool open(const char *filename);
-        void close(void);
-
-        unsigned beginEnter(const FunctionSig *sig);
-        void endEnter(void);
-
-        void beginLeave(unsigned call);
-        void endLeave(void);
-
-        void beginArg(unsigned index);
-        inline void endArg(void) {}
-
-        void beginReturn(void);
-        inline void endReturn(void) {}
-
-        void beginArray(size_t length);
-        inline void endArray(void) {}
-
-        inline void beginElement(void) {}
-        inline void endElement(void) {}
-
-        void beginStruct(const StructSig *sig);
-        inline void endStruct(void) {}
-
-        void writeBool(bool value);
-        void writeSInt(signed long long value);
-        void writeUInt(unsigned long long value);
-        void writeFloat(float value);
-        void writeDouble(double value);
-        void writeString(const char *str);
-        void writeString(const char *str, size_t size);
-        void writeWString(const wchar_t *str);
-        void writeBlob(const void *data, size_t size);
-        void writeEnum(const EnumSig *sig);
-        void writeBitmask(const BitmaskSig *sig, unsigned long long value);
-        void writeNull(void);
-        void writeOpaque(const void *ptr);
-
-        void writeCall(Call *call);
-
-    protected:
-        void inline _write(const void *sBuffer, size_t dwBytesToWrite);
-        void inline _writeByte(char c);
-        void inline _writeUInt(unsigned long long value);
-        void inline _writeFloat(float value);
-        void inline _writeDouble(double value);
-        void inline _writeString(const char *str);
-
-    };
-
-    /**
-     * A specialized Writer class, mean to trace the current process.
-     *
-     * In particular:
-     * - it creates a trace file based on the current process name
-     * - uses mutexes to allow tracing from multiple threades
-     * - flushes the output to ensure the last call is traced in event of
-     *   abnormal termination
-     */
-    class LocalWriter : public Writer {
-    protected:
-        int acquired;
-
-    public:
-        /**
-         * Should never called directly -- use localWriter singleton below instead.
-         */
-        LocalWriter();
-        ~LocalWriter();
-
-        void open(void);
-
-        unsigned beginEnter(const FunctionSig *sig);
-        void endEnter(void);
-
-        void beginLeave(unsigned call);
-        void endLeave(void);
-
-        void flush(void);
-    };
-
-    /**
-     * Singleton.
-     */
-    extern LocalWriter localWriter;
-}
-
-#endif /* _TRACE_WRITER_HPP_ */