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
--- /dev/null
+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
+
+
##############################################################################
# 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
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
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
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
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
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)
glstate_params.cpp
retrace.cpp
${glws}
- image.cpp
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
)
##############################################################################
# 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")
--- /dev/null
+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).
+
+
--- /dev/null
+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.
* 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
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
\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
=====
* Plug memory leaks.
-* Allow to retrace with two libGL.so in parallel, and output differences in
- rendered frames / draw calls.
-
* D3D support.
* 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:
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
+
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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);
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+#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*>();
+}
--- /dev/null
+#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
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
+
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
+
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
--- /dev/null
+/**************************************************************************
+ *
+ * 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));
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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
--- /dev/null
+/**************************************************************************
+ *
+ * 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 */
+
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
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)
from winapi import *
from d3d8types import *
from d3d8caps import *
-from trace import DllTracer
HRESULT = Enum("HRESULT", [
"D3D_OK",
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)
-
--- /dev/null
+##########################################################################
+#
+# 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)
+
from winapi import *
from d3d9types import *
from d3d9caps import *
-from trace import DllTracer
+
D3DSHADER9 = Opaque("const DWORD *")
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)
-
--- /dev/null
+##########################################################################
+#
+# 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)
+
"""ddraw.h"""
from winapi import *
-from trace import DllTracer
DirectDrawOptSurfaceDescFlags = Flags(DWORD, [
"DDOSD_GUID",
--- /dev/null
+##########################################################################
+#
+# 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)
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
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")]),
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),
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")]),
# 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")]),
# 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")]),
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")]),
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")]),
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")]),
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),
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),
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")]),
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")]),
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
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")]),
])
# Shorthands for the types
-X = None # To be determined
+X = None # To be determined, merely an enum
B = GLboolean
I = GLint
I64 = GLint64
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
("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
("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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
("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
("", 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
("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
("", 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
("", 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
("", 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
("", 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
("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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
("", 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
]
void snapshot(unsigned call_no);
void frame_complete(unsigned call_no);
+void updateDrawable(int width, int height);
} /* namespace glretrace */
"glMultiModeDrawElementsIBM",
])
+ draw_indirect_function_names = set([
+ "glDrawArraysIndirect",
+ "glDrawElementsIndirect",
+ ])
+
misc_draw_function_names = set([
"glClear",
"glEnd",
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 ' }'
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)
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);'
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;'
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 ' }'
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
#include "glproc.hpp"
#include "glretrace.hpp"
+#include "glstate.hpp"
'''
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 ||
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);
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;
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__
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);
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)
GLmap = Handle("map", OpaquePointer(GLvoid))
GLpipeline = Handle("pipeline", GLuint)
GLsampler = Handle("sampler", GLuint)
+GLfeedback = Handle("feedback", GLuint)
GLsync_ = Opaque("GLsync")
GLsync = Handle("sync", GLsync_)
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
+])
+
# 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")]),
glsledit.cpp
imageviewer.cpp
jumpwidget.cpp
- loaderthread.cpp
mainwindow.cpp
main.cpp
retracer.cpp
settingsdialog.cpp
shaderssourcewidget.cpp
tracedialog.cpp
+ traceloader.cpp
traceprocess.cpp
vertexdatainterpreter.cpp
)
//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);
{
QByteArray dataArray = QByteArray::fromBase64(base64);
m_image.loadFromData(dataArray, "png");
- m_image = m_image.mirrored();
m_thumb = m_image.scaled(64, 64, Qt::KeepAspectRatio);
}
#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;
bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
ApiTrace::FrameMarker marker)
{
- if (!call)
+ if (!call) {
return false;
+ }
switch (marker) {
case FrameMarker_SwapBuffers:
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;
}
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;
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)
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();
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;
}
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)
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()
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"
#include <QObject>
#include <QSet>
-class LoaderThread;
+class TraceLoader;
class SaverThread;
+class QThread;
class ApiTrace : public QObject
{
FrameMarker_Finish,
FrameMarker_Clear
};
+ enum SearchResult {
+ SearchResult_NotFound,
+ SearchResult_Found,
+ SearchResult_Wrapped
+ };
+
static bool isCallAFrameMarker(const ApiTraceCall *call,
FrameMarker marker);
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;
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;
bool m_needsSaving;
QSet<ApiTraceCall*> m_errors;
- QHash<QString, ApiTraceCallSignature*> m_signatures;
+ QList< QPair<ApiTraceFrame*, ApiTraceError> > m_queuedErrors;
};
#endif
#include "apitracecall.h"
#include "apitrace.h"
+#include "traceloader.h"
#include "trace_model.hpp"
#include <QDebug>
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)
// 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);
}
}
-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
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);
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;
}
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()
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),
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) {
m_binaryDataIndex = i;
}
}
+ m_argValues.squeeze();
}
ApiTraceCall::~ApiTraceCall()
void ApiTraceCall::setError(const QString &msg)
{
if (m_error != msg) {
- ApiTrace *trace = parentTrace();
m_error = msg;
m_richText = QString();
- if (trace)
- trace->callError(this);
}
}
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();
}
}
-QVariantList ApiTraceCall::editedValues() const
+QVector<QVariant> ApiTraceCall::editedValues() const
{
return m_editedValues;
}
void ApiTraceCall::revert()
{
- setEditedValues(QVariantList());
+ setEditedValues(QVector<QVariant>());
}
void ApiTraceCall::setHelpUrl(const QUrl &url)
return m_signature->argNames();
}
-QVariantList ApiTraceCall::arguments() const
+QVector<QVariant> ApiTraceCall::arguments() const
{
if (m_editedValues.isEmpty())
return m_argValues;
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(
.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 +=
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) {
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
if (m_staticText && !m_staticText->text().isEmpty())
return *m_staticText;
- QString richText;
+ QString richText = QObject::tr(
+ "<span style=\"font-weight:bold\">Frame %1</span>"
+ " "
+ "<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 %1</span>"
+ "%1"
"<span style=\"font-style:italic;\">"
" (%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)
}
}
-QList<ApiTraceCall*> ApiTraceFrame::calls() const
+QVector<ApiTraceCall*> ApiTraceFrame::calls() const
{
return m_calls;
}
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);
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;
+ }
+}
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);
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);
{
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);
const QList<ApiTexture> & textures() const;
const QList<ApiFramebuffer> & framebuffers() const;
+ ApiFramebuffer colorBuffer() const;
private:
QVariantMap m_parameters;
QMap<QString, QString> m_shaderSources;
{
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;
};
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);
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;
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*);
}
}
-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
{
void setFilterRegexp(const QRegExp ®exp);
QRegExp filterRegexp() const;
- QModelIndex callIndex(int callNum) const;
QModelIndex indexForCall(ApiTraceCall *call) const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
#include "apitracemodel.h"
#include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "trace_parser.hpp"
+#include <QBuffer>
#include <QDebug>
#include <QImage>
#include <QVariant>
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) <b>%2</b>")
.arg(call->index())
.arg(call->name());
.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) Frame ")
- .arg(frame->number);
- int binaryDataSize = frame->binaryDataSize() / 1024;
- if (frame->state().isEmpty())
- return QObject::tr(
- "<b>%1 </b>(binary data size = %2kB)")
- .arg(text)
- .arg(binaryDataSize);
- else
- return QObject::tr(
- "<b>%1 (binary data size = %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:
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
}
}
-QModelIndex ApiTraceModel::callIndex(int callNum) const
-{
- ApiTraceCall *call = m_trace->callWithIndex(callNum);
- return indexForCall(call);
-}
-
QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const
{
if (!call) {
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"
#include <QAbstractItemModel>
#include <QModelIndex>
+#include <QSet>
#include <QVariant>
class ApiTrace;
class ApiTraceCall;
class ApiTraceEvent;
+class ApiTraceFrame;
class ApiTraceModel : public QAbstractItemModel
{
const ApiTrace *apiTrace() const;
void stateSetOnEvent(ApiTraceEvent *event);
- QModelIndex callIndex(int callNum) const;
QModelIndex indexForCall(ApiTraceCall *call) const;
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:
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
{
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
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;
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) {
}
}
-void ArgumentsEditor::setupShaderEditor(const QList<QVariant> &sources)
+void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources)
{
m_ui.selectStringCB->clear();
m_ui.glslEdit->clear();
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;
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();
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;
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;
+++ /dev/null
-#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"
+++ /dev/null
-#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
#include "mainwindow.h"
+#include "apitrace.h"
#include "apitracecall.h"
#include <QApplication>
#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();
void MainWindow::createTrace()
{
- TraceDialog dialog;
-
if (!m_traceProcess->canTrace()) {
QMessageBox::warning(
this,
return;
}
+ TraceDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
qDebug()<< "App : " <<dialog.applicationPath();
qDebug()<< " Arguments: "<<dialog.arguments();
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);
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")) {
} 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);
+ }
}
}
}
} 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()
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);
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);
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;
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()
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];
}
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) {
}
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);
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;
}
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;
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);
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)
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);
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);
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 =
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 =
{
QTreeWidget *tree = m_ui.surfacesTreeWidget;
QTreeWidgetItem *item = tree->itemAt(pos);
- if (!item)
+ if (!item) {
return;
+ }
QMenu menu(tr("Surfaces"), this);
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);
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();
{
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()),
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()));
this, SLOT(slotErrorSelected(QTreeWidgetItem*)));
}
-void MainWindow::replayStateFound(const ApiTraceState &state)
+void MainWindow::replayStateFound(ApiTraceState *state)
{
m_stateEvent->setState(state);
m_model->stateSetOnEvent(m_stateEvent);
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)
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)
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;
}
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) {
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) {
}
}
-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);
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) {
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());
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"
#include "ui_mainwindow.h"
+#include "apitrace.h"
+
#include <QMainWindow>
#include <QProcess>
class QProgressBar;
class QTreeWidgetItem;
class QUrl;
-struct RetraceError;
+struct ApiTraceError;
class Retracer;
class SearchWidget;
class ShadersSourceWidget;
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();
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();
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;
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();
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 {
}
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);
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()));
#ifndef RETRACER_H
#define RETRACER_H
+#include "apitracecall.h"
+
#include <QThread>
#include <QProcess>
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
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();
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();
#include "saverthread.h"
#include "trace_writer.hpp"
+#include "trace_model.hpp"
+#include "trace_parser.hpp"
#include <QFile>
#include <QHash>
#include <QDebug>
-
+#if 0
static Trace::FunctionSig *
createFunctionSig(ApiTraceCall *call, 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();
}
}
}
+#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();
#include "apitrace.h"
#include <QThread>
-#include <QList>
+#include <QVector>
class ApiTraceCall;
class ApiTraceFrame;
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();
virtual void run();
private:
- QString m_fileName;
- QList<ApiTraceCall*> m_calls;
+ QString m_readFileName;
+ QString m_writeFileName;
+ QSet<ApiTraceCall*> m_editedCalls;
};
--- /dev/null
+#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"
--- /dev/null
+#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
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
-
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-This directory contains several utilitarian scripts for common development
-tasks using apitrace tools.
-
-See their code for more details about their usage.
--- /dev/null
+##########################################################################
+#
+# 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',
+]
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
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)
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):
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,
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)
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__':
'''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:
#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
*/
/* 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__)
/* 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
#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
#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
+
/*************************************************************/
#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 */
/* 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
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
#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
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
}
+++ /dev/null
-/**************************************************************************
- *
- * 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);
-}
+++ /dev/null
-/**************************************************************************
- *
- * 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
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
-
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
-
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */
+++ /dev/null
-/**************************************************************************
- *
- * 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;
-}
+++ /dev/null
-/**************************************************************************
- *
- * 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
+++ /dev/null
-/**************************************************************************
- *
- * 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 */
-
+++ /dev/null
-/**************************************************************************
- *
- * 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_ */