summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jose.r.fonseca@gmail.com>2011-09-23 08:33:13 +0100
committerJosé Fonseca <jose.r.fonseca@gmail.com>2011-09-23 08:33:13 +0100
commitae2b4d32ed56e3ac193cc7205aeb58082c448ce8 (patch)
tree7225d26bd1400dacb64ed680fd1514611f6cf025
parentaf7d231ddf7f7fef342782932e85479044de1757 (diff)
parent892cad6f24175221d2e7bdf3c7fe6c34b64ee50a (diff)
Merge branch 'master' into d3d10
Conflicts: CMakeLists.txt
-rw-r--r--.gitignore9
-rw-r--r--BUGS.markdown115
-rwxr-xr-xCMakeLists.txt70
-rw-r--r--INSTALL.markdown69
-rw-r--r--NEWS.markdown34
-rw-r--r--README.markdown258
-rw-r--r--TODO.markdown8
-rw-r--r--common/formatter.hpp (renamed from formatter.hpp)0
-rw-r--r--common/image.cpp (renamed from image.cpp)0
-rw-r--r--common/image.hpp (renamed from image.hpp)6
-rw-r--r--common/image_bmp.cpp (renamed from image_bmp.cpp)0
-rw-r--r--common/image_png.cpp (renamed from image_png.cpp)0
-rw-r--r--common/image_pnm.cpp112
-rw-r--r--common/json.hpp (renamed from json.hpp)0
-rw-r--r--common/os.hpp (renamed from os.hpp)0
-rw-r--r--common/os_posix.cpp (renamed from os_posix.cpp)6
-rw-r--r--common/os_win32.cpp (renamed from os_win32.cpp)0
-rw-r--r--common/trace_file.cpp (renamed from trace_file.cpp)57
-rw-r--r--common/trace_file.hpp (renamed from trace_file.hpp)101
-rw-r--r--common/trace_format.hpp (renamed from trace_format.hpp)0
-rw-r--r--common/trace_loader.cpp139
-rw-r--r--common/trace_loader.hpp65
-rw-r--r--common/trace_local_writer.cpp (renamed from trace_local_writer.cpp)10
-rw-r--r--common/trace_model.cpp (renamed from trace_model.cpp)5
-rw-r--r--common/trace_model.hpp (renamed from trace_model.hpp)1
-rw-r--r--common/trace_model_writer.cpp (renamed from trace_model_writer.cpp)0
-rw-r--r--common/trace_parser.cpp (renamed from trace_parser.cpp)400
-rw-r--r--common/trace_parser.hpp (renamed from trace_parser.hpp)104
-rw-r--r--common/trace_snappyfile.cpp (renamed from trace_snappyfile.cpp)188
-rw-r--r--common/trace_snappyfile.hpp (renamed from trace_snappyfile.hpp)38
-rw-r--r--common/trace_writer.cpp (renamed from trace_writer.cpp)0
-rw-r--r--common/trace_writer.hpp (renamed from trace_writer.hpp)0
-rw-r--r--d3d.py52
-rw-r--r--d3d8.py25
-rw-r--r--d3d8trace.py52
-rw-r--r--d3d9.py25
-rw-r--r--d3d9trace.py51
-rw-r--r--ddraw.py1
-rw-r--r--ddrawtrace.py81
-rw-r--r--glapi.py123
-rw-r--r--glparams.py284
-rw-r--r--glretrace.hpp1
-rw-r--r--glretrace.py50
-rw-r--r--glretrace_main.cpp35
-rw-r--r--glsize.hpp4
-rw-r--r--glstate.cpp4
-rw-r--r--glstate.py13
-rw-r--r--gltypes.py19
-rw-r--r--glxapi.py4
-rw-r--r--gui/CMakeLists.txt2
-rw-r--r--gui/apicalldelegate.cpp2
-rw-r--r--gui/apisurface.cpp1
-rw-r--r--gui/apitrace.cpp381
-rw-r--r--gui/apitrace.h68
-rw-r--r--gui/apitracecall.cpp275
-rw-r--r--gui/apitracecall.h113
-rw-r--r--gui/apitracefilter.cpp6
-rw-r--r--gui/apitracefilter.h1
-rw-r--r--gui/apitracemodel.cpp131
-rw-r--r--gui/apitracemodel.h8
-rw-r--r--gui/argumentseditor.cpp20
-rw-r--r--gui/argumentseditor.h2
-rw-r--r--gui/loaderthread.cpp112
-rw-r--r--gui/loaderthread.h34
-rw-r--r--gui/main.cpp8
-rw-r--r--gui/mainwindow.cpp450
-rw-r--r--gui/mainwindow.h22
-rw-r--r--gui/retracer.cpp18
-rw-r--r--gui/retracer.h16
-rw-r--r--gui/saverthread.cpp180
-rw-r--r--gui/saverthread.h12
-rw-r--r--gui/traceloader.cpp496
-rw-r--r--gui/traceloader.h101
-rw-r--r--image_pnm.cpp67
-rw-r--r--scripts/README4
-rw-r--r--scripts/highlight.py194
-rwxr-xr-xscripts/retracediff.py158
-rwxr-xr-xscripts/snapdiff.py11
-rw-r--r--thirdparty/glext/glext.h378
79 files changed, 4569 insertions, 1321 deletions
diff --git a/.gitignore b/.gitignore
index b2dda42..ed1ea5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,11 +27,10 @@ CMakeCache.txt
CMakeFiles
Makefile
build
-d3d10.cpp
-d3d10_1.cpp
-d3d8.cpp
-d3d9.cpp
-ddraw.cpp
+d3d10trace.cpp
+d3d8trace.cpp
+d3d9trace.cpp
+ddrawtrace.cpp
dxsdk
glproc.hpp
glretrace
diff --git a/BUGS.markdown b/BUGS.markdown
new file mode 100644
index 0000000..2b8483d
--- /dev/null
+++ b/BUGS.markdown
@@ -0,0 +1,115 @@
+Reporting bugs
+==============
+
+Please report any issues on
+[github](https://github.com/apitrace/apitrace/issues).
+
+Always include the following information:
+
+* operating system name and version
+
+* OpenGL/D3D driver name and version
+
+
+Proprietary/confidential applications
+=====================================
+
+Issues should be preferably filed on github to facilitate collaborative
+development and for future reference.
+
+Access to applications source code is not required -- binaries are sufficient.
+
+If the bug happens with a proprietary application, and you don't want to
+publicly release the application and/or any data collected from it, then
+alternatively you can provide the necessary application and/or data via e-mail,
+to *jose dot r dot fonseca at gmail dot com*.
+
+If it is not technically/legally feasible for you to provide application and/or
+data at all, then you must be either:
+
+* develop and provide a test application, stripped-down of all
+ proprietary/confidential data, but that can reproduce the issue;
+
+* be willing/able to do the investigation of the issue, namely to identify the
+ root cause of the issue (e.g., which OpenGL call is not properly handled and
+ why), using all necessary tools (such as debuggers).
+
+Failure to do so will render the apitrace authors powerless to address the
+issue.
+
+
+Attachments
+===========
+
+github issue tracker doesn't support attachments.
+
+Please attach long logs to https://gist.github.com/ and paste the URL into the
+issue description.
+
+For big attachments, such as traces, please upload it temporarily to a web
+server you control, or use a file upload service such as
+http://www.megaupload.com/ or http://dropbox.com/ and paste the URL into the
+issue description.
+
+Trace files are only slightly compressed (for performance reasons). You can
+further reduce their size when attaching/uploading by compressing with
+[XZ](http://tukaani.org/xz/) or [7-Zip](http://www.7-zip.org/).
+
+
+Bugs on tracing
+===============
+
+For bugs that happen while tracing (e.g., crashes while tracing the
+application, or incorrect traces) please:
+
+* provide information on how to obtain the application;
+
+* describe how you were using it when the issue happened.
+
+
+Bugs on retracing/GUI
+=====================
+
+For bugs on retracing (e.g. crashes when retracing the application,
+incorrect inconsistent rendering, or viewing with the GUI) please:
+
+* provide the trace file;
+
+* describe the results you got, and what results you were expecting.
+
+
+Obtaining stack back-traces
+===========================
+
+
+Linux/MacOSX
+------------
+
+Please rebuild apitrace with debugging information, by passing
+`-DCMAKE_BUILD_TYPE=Debug` to cmake.
+
+To obtain a stack back-trace, run the application with gdb from a terminal:
+
+ $ gdb --args application arg1 arg2 ...
+ (gdb) run
+ ...
+ (gdb) bt
+
+
+See also more detailed and Distro specific instructions:
+
+* http://wiki.debian.org/HowToGetABacktrace
+
+* https://wiki.ubuntu.com/Backtrace
+
+* http://fedoraproject.org/wiki/StackTraces
+
+* http://live.gnome.org/GettingTraces
+
+
+Windows
+-------
+
+WRITEME
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 82a4a31..c9b740c 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -163,7 +163,10 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty)
##############################################################################
# Common libraries / utilities
-include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+include_directories (
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/common
+)
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
@@ -180,18 +183,19 @@ else (WIN32)
endif (WIN32)
add_library (common
- trace_file.cpp
- trace_snappyfile.cpp
- trace_model.cpp
- trace_parser.cpp
- trace_writer.cpp
- trace_local_writer.cpp
- trace_model_writer.cpp
- image.cpp
- image_bmp.cpp
- image_pnm.cpp
- image_png.cpp
- ${os}
+ common/trace_file.cpp
+ common/trace_snappyfile.cpp
+ common/trace_model.cpp
+ common/trace_parser.cpp
+ common/trace_writer.cpp
+ common/trace_local_writer.cpp
+ common/trace_model_writer.cpp
+ common/trace_loader.cpp
+ common/image.cpp
+ common/image_bmp.cpp
+ common/image_pnm.cpp
+ common/image_png.cpp
+ common/${os}
)
set_target_properties (common PROPERTIES
@@ -213,11 +217,11 @@ if (WIN32)
if (DirectX_D3D_INCLUDE_DIR)
include_directories (SYSTEM ${DirectX_D3D_INCLUDE_DIR})
add_custom_command (
- OUTPUT ddraw.cpp
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d.py > ${CMAKE_CURRENT_BINARY_DIR}/ddraw.cpp
- DEPENDS d3d.py d3dtypes.py d3dcaps.py ddraw.py trace.py winapi.py stdapi.py
+ OUTPUT ddrawtrace.cpp
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/ddrawtrace.py > ${CMAKE_CURRENT_BINARY_DIR}/ddrawtrace.cpp
+ DEPENDS ddrawtrace.py d3d.py d3dtypes.py d3dcaps.py ddraw.py trace.py winapi.py stdapi.py
)
- add_library (ddraw MODULE ddraw.def ddraw.cpp)
+ add_library (ddraw MODULE ddraw.def ddrawtrace.cpp)
set_target_properties (ddraw
PROPERTIES PREFIX ""
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -230,11 +234,11 @@ if (WIN32)
if (DirectX_D3D8_INCLUDE_DIR AND DirectX_D3DX9_INCLUDE_DIR)
include_directories (SYSTEM ${DirectX_D3D8_INCLUDE_DIR} ${DirectX_D3DX9_INCLUDE_DIR})
add_custom_command (
- OUTPUT d3d8.cpp
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d8.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d8.cpp
- DEPENDS d3d8.py trace.py d3d8types.py d3d8caps.py winapi.py stdapi.py
+ OUTPUT d3d8trace.cpp
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d8trace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d8trace.cpp
+ DEPENDS d3d8trace.py d3d8.py trace.py d3d8types.py d3d8caps.py winapi.py stdapi.py
)
- add_library (d3d8 MODULE d3d8.def d3d8.cpp d3dshader.cpp)
+ add_library (d3d8 MODULE d3d8.def d3d8trace.cpp d3dshader.cpp)
set_target_properties (d3d8
PROPERTIES PREFIX ""
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -247,11 +251,11 @@ if (WIN32)
if (DirectX_D3DX9_INCLUDE_DIR)
include_directories (SYSTEM ${DirectX_D3DX9_INCLUDE_DIR})
add_custom_command (
- OUTPUT d3d9.cpp
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d9.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d9.cpp
- DEPENDS d3d9.py trace.py d3d9types.py d3d9caps.py winapi.py stdapi.py
+ OUTPUT d3d9trace.cpp
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d9trace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d9trace.cpp
+ DEPENDS d3d9trace.py d3d9.py trace.py d3d9types.py d3d9caps.py winapi.py stdapi.py
)
- add_library (d3d9 MODULE d3d9.def d3d9.cpp d3dshader.cpp)
+ add_library (d3d9 MODULE d3d9.def d3d9trace.cpp d3dshader.cpp)
set_target_properties (d3d9
PROPERTIES PREFIX ""
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/wrappers
@@ -264,11 +268,11 @@ if (WIN32)
if (DirectX_D3D10_INCLUDE_DIR)
include_directories (SYSTEM ${DirectX_D3D10_INCLUDE_DIR})
add_custom_command (
- OUTPUT d3d10.cpp
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d10misc.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d10.cpp
+ OUTPUT d3d10trace.cpp
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3d10misc.py > ${CMAKE_CURRENT_BINARY_DIR}/d3d10trace.cpp
DEPENDS d3d10misc.py d3d10.py winapi.py stdapi.py
)
- add_library (d3d10 MODULE d3d10.def d3d10.cpp)
+ add_library (d3d10 MODULE d3d10.def d3d10trace.cpp)
set_target_properties (d3d10 PROPERTIES PREFIX "")
install (TARGETS d3d10 LIBRARY DESTINATION wrappers)
endif (DirectX_D3D10_INCLUDE_DIR)
@@ -383,7 +387,6 @@ add_executable (glretrace
glstate_params.cpp
retrace.cpp
${glws}
- image.cpp
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
)
@@ -425,7 +428,14 @@ endif ()
##############################################################################
# Packaging
-install (FILES LICENSE README.markdown TODO.markdown DESTINATION doc)
+install (
+ FILES
+ BUGS.markdown
+ LICENSE
+ NEWS.markdown
+ README.markdown
+ TODO.markdown
+ DESTINATION doc)
set (CPACK_PACKAGE_VERSION_MAJOR "1")
set (CPACK_PACKAGE_VERSION_MINOR "0")
diff --git a/INSTALL.markdown b/INSTALL.markdown
new file mode 100644
index 0000000..b50fb78
--- /dev/null
+++ b/INSTALL.markdown
@@ -0,0 +1,69 @@
+Building from source
+====================
+
+
+Requirements common for all platforms:
+
+* Python (requires version 2.6)
+
+* CMake (tested with version 2.8)
+
+Requirements to build the GUI (optional):
+
+* Qt (tested with version 4.7)
+
+* QJSON (tested with version 0.7.1)
+
+
+Linux / Mac OS X
+----------------
+
+Build as:
+
+ cmake -H. -Bbuild
+ make -C build
+
+You can also build the 32bit GL wrapper on 64bit distro with a multilib gcc by
+doing:
+
+ cmake -H. -Bbuild32 -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_EXE_LINKER_FLAGS=-m32
+ make -C build32 glxtrace
+
+
+Windows
+-------
+
+Additional requirements:
+
+* Microsoft Visual Studio (tested with 2008 version) or MinGW (tested with gcc version 4.4)
+
+* Microsoft DirectX SDK (tested with August 2007 release)
+
+To build with Visual Studio first invoke CMake GUI as:
+
+ cmake-gui -H. -B%cd%\build
+
+and press the _Configure_ button.
+
+It will try to detect most required/optional dependencies automatically. When
+not found automatically, you can manually specify the location of the
+dependencies from the GUI.
+
+If you are building with GUI support (i.e, with QT and QJSON), it should detect
+the official QT sdk automatically, but you will need to build QJSON yourself
+and also set the `QJSON_INCLUDE_DIR` and `QJSON_LIBRARIES` variables in the
+generated `CMakeCache.txt` when building apitrace and repeat the above
+sequence.
+
+After you've succesfully configured, you can start the build by opening the
+generated `build\apitrace.sln` solution file, or invoking `cmake` as:
+
+ cmake --build build --config MinSizeRel
+
+The steps to build 64bit version are similar, but choosing _Visual Studio 9
+2008 Win64_ instead of _Visual Studio 9 2008_.
+
+It's also possible to instruct `cmake` build Windows binaries on Linux with
+[MinGW cross compilers](http://www.cmake.org/Wiki/CmakeMingw).
+
+
diff --git a/NEWS.markdown b/NEWS.markdown
new file mode 100644
index 0000000..7cf9e38
--- /dev/null
+++ b/NEWS.markdown
@@ -0,0 +1,34 @@
+This file lists the major user visible improvments. For a full list of changes
+and their authors see the git history.
+
+
+Recent developments
+===================
+
+* Flush/sync trace file only when there is an uncaught signal/exception,
+ yielding a 5x speed up while tracing.
+
+* Employ [snappy compression library](http://code.google.com/p/snappy/) instead
+ of zlib, yielding a 2x speed up while tracing.
+
+* Implement and advertise `GL_GREMEDY_string_marker` and
+ `GL_GREMEDY_frame_terminator` extensions.
+
+* Mac OS X support.
+
+* Support up-to OpenGL 4.2 calls.
+
+* Better GUI performance with very large traces, by loading frames from disk on
+ demand.
+
+
+Version 1.0
+===========
+
+* Qt GUI, capable of visualizing the calls, the state, and editing the state.
+
+
+Pre-history
+===========
+
+* OpenGL retrace support.
diff --git a/README.markdown b/README.markdown
index 5b34dec..c388042 100644
--- a/README.markdown
+++ b/README.markdown
@@ -7,80 +7,13 @@ About **apitrace**
* retrace OpenGL calls from a file;
-* visualize trace files, and inspect state.
+* inspect OpenGL state at any call while retracing;
+* visualize and edit trace files.
-Building from source
-====================
-
-Requirements common for all platforms:
-
-* Python (requires version 2.6)
-
-* CMake (tested with version 2.8)
-
-Requirements to build the GUI (optional):
-
-* Qt (tested with version 4.7)
-
-* QJSON (tested with version 0.7.1)
-
-
-Linux / Mac OS X
-----------------
-
-Build as:
-
- cmake -H. -Bbuild
- make -C build
-
-You can also build the 32bit GL wrapper on 64bit distro with a multilib gcc by
-doing:
-
- cmake -H. -Bbuild32 -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_EXE_LINKER_FLAGS=-m32
- make -C build32 glxtrace
-
-
-Windows
--------
-
-Additional requirements:
-
-* Microsoft Visual Studio (tested with 2008 version) or MinGW (tested with gcc version 4.4)
-
-* Microsoft DirectX SDK (tested with August 2007 release)
-
-To build with Visual Studio first invoke CMake GUI as:
-
- cmake-gui -H. -B%cd%\build
-
-and press the _Configure_ button.
-
-It will try to detect most required/optional dependencies automatically. When
-not found automatically, you can manually specify the location of the
-dependencies from the GUI.
-
-If you are building with GUI support (i.e, with QT and QJSON), it should detect
-the official QT sdk automatically, but you will need to build QJSON yourself
-and also set the `QJSON_INCLUDE_DIR` and `QJSON_LIBRARIES` variables in the
-generated `CMakeCache.txt` when building apitrace and repeat the above
-sequence.
-
-After you've succesfully configured, you can start the build by opening the
-generated `build\apitrace.sln` solution file, or invoking `cmake` as:
-
- cmake --build build --config MinSizeRel
-
-The steps to build 64bit version are similar, but choosing _Visual Studio 9
-2008 Win64_ instead of _Visual Studio 9 2008_.
-
-It's also possible to instruct `cmake` build Windows binaries on Linux with
-[MinGW cross compilers](http://www.cmake.org/Wiki/CmakeMingw).
-
-
-Usage
-=====
+Basic usage
+===========
Linux
@@ -129,11 +62,6 @@ to trace by using `glxtrace.so` as an ordinary `libGL.so` and injecting into
See the `ld.so` man page for more information about `LD_PRELOAD` and
`LD_LIBRARY_PATH` environment flags.
-You can make a video of the output by doing
-
- /path/to/glretrace -s - application.trace \
- | ffmpeg -r 30 -f image2pipe -vcodec ppm -i pipe: -vcodec mpeg4 -y output.mp4
-
Mac OS X
@@ -167,6 +95,184 @@ Windows
\path\to\glretrace application.trace
+Advanced command line usage
+===========================
+
+
+Emitting annotations to the trace from GL applications
+------------------------------------------------------
+
+You can emit string and frame annotations through the
+[`GL_GREMEDY_string_marker`](http://www.opengl.org/registry/specs/GREMEDY/string_marker.txt)
+and
+[`GL_GREMEDY_frame_terminator`](http://www.opengl.org/registry/specs/GREMEDY/frame_terminator.txt)
+GL extensions.
+
+**apitrace** will advertise and intercept these GL extensions independently of
+the GL implementation. So all you have to do is to use these extensions when
+available.
+
+For example, if you use [GLEW](http://glew.sourceforge.net/) to dynamically
+detect and use GL extensions, you could easily accomplish this by doing:
+
+ void foo() {
+
+ if (GLEW_GREMEDY_string_marker) {
+ glStringMarkerGREMEDY(0, __FUNCTION__ ": enter");
+ }
+
+ ...
+
+ if (GLEW_GREMEDY_string_marker) {
+ glStringMarkerGREMEDY(0, __FUNCTION__ ": leave");
+ }
+
+ }
+
+This has the added advantage of working equally well with gDEBugger.
+
+
+Dump GL state at a particular call
+----------------------------------
+
+You can get a dump of the bound GL state at call 12345 by doing:
+
+ /path/to/glretrace -D 12345 application.trace > 12345.json
+
+This is precisely the mechanism the GUI obtains its own state.
+
+You can compare two state dumps with the jsondiff.py script:
+
+ ./scripts/jsondiff.py 12345.json 67890.json
+
+
+Comparing two traces side by side
+---------------------------------
+
+ ./scripts/tracediff.sh trace1.trace trace2.trace
+
+This works only on Unices, and it will truncate the traces due to performance
+limitations.
+
+
+Recording a video with FFmpeg
+-----------------------------
+
+You can make a video of the output by doing
+
+ /path/to/glretrace -s - application.trace \
+ | ffmpeg -r 30 -f image2pipe -vcodec ppm -i pipe: -vcodec mpeg4 -y output.mp4
+
+
+Advanced usage for OpenGL implementors
+======================================
+
+There are several advanced usage examples meant for OpenGL implementors.
+
+
+Regression testing
+------------------
+
+These are the steps to create a regression test-suite around **apitrace**:
+
+* obtain a trace
+
+* obtain reference snapshots, by doing:
+
+ mkdir /path/to/snapshots/
+ /path/to/glretrace -s /path/to/reference/snapshots/ application.trace
+
+ on reference system.
+
+* prune the snapshots which are not interesting
+
+* to do a regression test, do:
+
+ /path/to/glretrace -c /path/to/reference/snapshots/ application.trace
+
+ Alternatively, for a HTML summary, use the snapdiff script:
+
+ /path/to/glretrace -s /path/to/current/snapshots/ application.trace
+ ./scripts/snapdiff.py --output summary.html /path/to/reference/snapshots/ /path/to/current/snapshots/
+
+
+Automated git-bisection
+-----------------------
+
+With tracecheck.py it is possible to automate git bisect and pinpoint the
+commit responsible for a regression.
+
+Below is an example of using tracecheck.py to bisect a regression in the
+Mesa-based Intel 965 driver. But the procedure could be applied to any GL
+driver hosted on a git repository.
+
+First, create a build script, named build-script.sh, containing:
+
+ #!/bin/sh
+ set -e
+ export PATH=/usr/lib/ccache:$PATH
+ export CFLAGS='-g'
+ export CXXFLAGS='-g'
+ ./autogen.sh --disable-egl --disable-gallium --disable-glut --disable-glu --disable-glw --with-dri-drivers=i965
+ make clean
+ make "$@"
+
+It is important that builds are both robust, and efficient. Due to broken
+dependency discovery in Mesa's makefile system, it was necessary invoke `make
+clean` in every iteration step. `ccache` should be installed to avoid
+recompiling unchanged source files.
+
+Then do:
+
+ cd /path/to/mesa
+ export LIBGL_DEBUG=verbose
+ export LD_LIBRARY_PATH=$PWD/lib
+ export LIBGL_DRIVERS_DIR=$PWD/lib
+ git bisect start \
+ 6491e9593d5cbc5644eb02593a2f562447efdcbb 71acbb54f49089b03d3498b6f88c1681d3f649ac \
+ -- src/mesa/drivers/dri/intel src/mesa/drivers/dri/i965/
+ git bisect run /path/to/tracecheck.py \
+ --precision-threshold 8.0 \
+ --build /path/to/build-script.sh \
+ --gl-renderer '.*Mesa.*Intel.*' \
+ --retrace=/path/to/glretrace \
+ -c /path/to/reference/snapshots/ \
+ topogun-1.06-orc-84k.trace
+
+The trace-check.py script will skip automatically when there are build
+failures.
+
+The `--gl-renderer` option will also cause a commit to be skipped if the
+`GL_RENDERER` is unexpected (e.g., when a software renderer or another GL
+driver is unintentionally loaded due to missing symbol in the DRI driver, or
+another runtime fault).
+
+
+Side by side retracing
+----------------------
+
+In order to determine which draw call a regression first manifests one could
+generate snapshots for every draw call, using the `-S` option. That is, however,
+very inefficient for big traces with many draw calls.
+
+A faster approach is to run both the bad and a good GL driver side-by-side.
+The latter can be either a previously known good build of the GL driver, or a
+reference software renderer.
+
+This can be achieved with retracediff.py script, which invokes glretrace with
+different environments, allowing to choose the desired GL driver by
+manipulating variables such as `LD_LIBRARY_PATH` or `LIBGL_DRIVERS_DIR`.
+
+For example:
+
+ ./scripts/retracediff.py \
+ --ref-env LD_LIBRARY_PATH=/path/to/reference/GL/implementation \
+ -r ./glretrace \
+ --diff-prefix=/path/to/output/diffs \
+ application.trace
+
+
+
Links
=====
diff --git a/TODO.markdown b/TODO.markdown
index fb44766..b54cf65 100644
--- a/TODO.markdown
+++ b/TODO.markdown
@@ -50,9 +50,6 @@ Retracing
* Plug memory leaks.
-* Allow to retrace with two libGL.so in parallel, and output differences in
- rendered frames / draw calls.
-
* D3D support.
@@ -64,12 +61,11 @@ GUI
* Visualize meshes in draw commands.
-Other:
+Other
+-----
* Side-by-side trace diffing; either as a separate tool on or the GUI.
-* Side-by-side state diffing.
-
* Ability to extract just a single frame from a trace, and all previous calls
that contributed to it:
diff --git a/formatter.hpp b/common/formatter.hpp
index 181e2d1..181e2d1 100644
--- a/formatter.hpp
+++ b/common/formatter.hpp
diff --git a/image.cpp b/common/image.cpp
index 4da9c13..4da9c13 100644
--- a/image.cpp
+++ b/common/image.cpp
diff --git a/image.hpp b/common/image.hpp
index 44fc4f4..dc53ec9 100644
--- a/image.hpp
+++ b/common/image.hpp
@@ -83,14 +83,14 @@ public:
bool writeBMP(const char *filename) const;
- void writePNM(std::ostream &os) const;
+ void writePNM(std::ostream &os, const char *comment = NULL) const;
- inline bool writePNM(const char *filename) 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);
+ writePNM(os, comment);
return true;
}
diff --git a/image_bmp.cpp b/common/image_bmp.cpp
index 346f39a..346f39a 100644
--- a/image_bmp.cpp
+++ b/common/image_bmp.cpp
diff --git a/image_png.cpp b/common/image_png.cpp
index fd22213..fd22213 100644
--- a/image_png.cpp
+++ b/common/image_png.cpp
diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp
new file mode 100644
index 0000000..5397a1a
--- /dev/null
+++ b/common/image_pnm.cpp
@@ -0,0 +1,112 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+/**
+ * http://en.wikipedia.org/wiki/Netpbm_format
+ * http://netpbm.sourceforge.net/doc/ppm.html
+ */
+void
+Image::writePNM(std::ostream &os, const char *comment) const {
+ assert(channels == 1 || channels >= 3);
+
+ os << (channels == 1 ? "P5" : "P6") << "\n";
+ if (comment) {
+ os << "#" << comment << "\n";
+ }
+ os << width << " " << height << "\n";
+ os << "255" << "\n";
+
+ const unsigned char *row;
+
+ if (channels == 1 || channels == 3) {
+ for (row = start(); row != end(); row += stride()) {
+ os.write((const char *)row, width*channels);
+ }
+ } else {
+ unsigned char *tmp = new unsigned char[width*3];
+ if (channels == 4) {
+ for (row = start(); row != end(); row += stride()) {
+ const uint32_t *src = (const uint32_t *)row;
+ uint32_t *dst = (uint32_t *)tmp;
+ unsigned x;
+ for (x = 0; x + 4 <= width; x += 4) {
+ /*
+ * It's much faster to access dwords than bytes.
+ *
+ * FIXME: Big-endian version.
+ */
+
+ uint32_t rgba0 = *src++ & 0xffffff;
+ uint32_t rgba1 = *src++ & 0xffffff;
+ uint32_t rgba2 = *src++ & 0xffffff;
+ uint32_t rgba3 = *src++ & 0xffffff;
+ uint32_t rgb0 = rgba0
+ | (rgba1 << 24);
+ uint32_t rgb1 = (rgba1 >> 8)
+ | (rgba2 << 16);
+ uint32_t rgb2 = (rgba2 >> 16)
+ | (rgba3 << 8);
+ *dst++ = rgb0;
+ *dst++ = rgb1;
+ *dst++ = rgb2;
+ }
+ for (; x < width; ++x) {
+ tmp[x*3 + 0] = row[x*4 + 0];
+ tmp[x*3 + 1] = row[x*4 + 1];
+ tmp[x*3 + 2] = row[x*4 + 2];
+ }
+ os.write((const char *)tmp, width*3);
+ }
+ } else if (channels == 2) {
+ for (row = start(); row != end(); row += stride()) {
+ const unsigned char *src = row;
+ unsigned char *dst = tmp;
+ for (unsigned x = 0; x < width; ++x) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = 0;
+ }
+ os.write((const char *)tmp, width*3);
+ }
+ } else {
+ assert(0);
+ }
+ delete [] tmp;
+ }
+}
+
+
+} /* namespace Image */
diff --git a/json.hpp b/common/json.hpp
index 9e6b960..9e6b960 100644
--- a/json.hpp
+++ b/common/json.hpp
diff --git a/os.hpp b/common/os.hpp
index 8e487b5..8e487b5 100644
--- a/os.hpp
+++ b/common/os.hpp
diff --git a/os_posix.cpp b/common/os_posix.cpp
index 991ad0e..98a790b 100644
--- a/os_posix.cpp
+++ b/common/os_posix.cpp
@@ -145,6 +145,12 @@ static void (*gCallback)(void) = NULL;
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;
diff --git a/os_win32.cpp b/common/os_win32.cpp
index 587503c..587503c 100644
--- a/os_win32.cpp
+++ b/common/os_win32.cpp
diff --git a/trace_file.cpp b/common/trace_file.cpp
index e206858..f48c1aa 100644
--- a/trace_file.cpp
+++ b/common/trace_file.cpp
@@ -42,12 +42,11 @@ using namespace Trace;
File::File(const std::string &filename,
File::Mode mode)
- : m_filename(filename),
- m_mode(mode),
+ : m_mode(mode),
m_isOpened(false)
{
- if (!m_filename.empty()) {
- open(m_filename, m_mode);
+ if (!filename.empty()) {
+ open(filename, m_mode);
}
}
@@ -56,6 +55,12 @@ 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(),
@@ -87,6 +92,12 @@ bool File::isSnappyCompressed(const std::string &filename)
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)
@@ -103,15 +114,28 @@ 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, int length)
+bool ZLibFile::rawWrite(const void *buffer, size_t length)
{
return gzwrite(m_gzFile, buffer, length) != -1;
}
-bool ZLibFile::rawRead(void *buffer, int length)
+bool ZLibFile::rawRead(void *buffer, size_t length)
{
return gzread(m_gzFile, buffer, length) != -1;
}
@@ -133,3 +157,24 @@ void ZLibFile::rawFlush()
{
gzflush(m_gzFile, Z_SYNC_FLUSH);
}
+
+File::Offset ZLibFile::currentOffset()
+{
+ return File::Offset(gztell(m_gzFile));
+}
+
+bool ZLibFile::supportsOffsets() const
+{
+ return false;
+}
+
+bool ZLibFile::rawSkip(size_t)
+{
+ return false;
+}
+
+int ZLibFile::rawPercentRead()
+{
+ gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+ return 100 * (ftell(stream->file) / m_endOffset);
+}
diff --git a/trace_file.hpp b/common/trace_file.hpp
index 5a98f60..4b1b70d 100644
--- a/trace_file.hpp
+++ b/common/trace_file.hpp
@@ -29,6 +29,7 @@
#include <string>
#include <fstream>
+#include <stdint.h>
namespace Trace {
@@ -38,6 +39,15 @@ public:
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);
@@ -49,25 +59,29 @@ public:
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);
+ 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, int length) = 0;
- virtual bool rawRead(void *buffer, int length) = 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:
- std::string m_filename;
File::Mode m_mode;
bool m_isOpened;
};
@@ -82,11 +96,6 @@ 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) {
@@ -98,7 +107,7 @@ inline bool File::open(const std::string &filename, File::Mode mode)
return m_isOpened;
}
-inline bool File::write(const void *buffer, int length)
+inline bool File::write(const void *buffer, size_t length)
{
if (!m_isOpened || m_mode != File::Write) {
return false;
@@ -106,7 +115,7 @@ inline bool File::write(const void *buffer, int length)
return rawWrite(buffer, length);
}
-inline bool File::read(void *buffer, int length)
+inline bool File::read(void *buffer, size_t length)
{
if (!m_isOpened || m_mode != File::Read) {
return false;
@@ -114,6 +123,14 @@ inline bool File::read(void *buffer, int length)
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) {
@@ -124,7 +141,9 @@ inline void File::close()
inline void File::flush(void)
{
- rawFlush();
+ if (m_mode == File::Write) {
+ rawFlush();
+ }
}
inline int File::getc()
@@ -135,23 +154,71 @@ inline int File::getc()
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, int length);
- virtual bool rawRead(void *buffer, int length);
+ virtual bool rawWrite(const void *buffer, size_t length);
+ virtual bool rawRead(void *buffer, size_t length);
virtual int rawGetc();
virtual void rawClose();
virtual void rawFlush();
+ virtual bool rawSkip(size_t length);
+ virtual int rawPercentRead();
private:
void *m_gzFile;
+ double m_endOffset;
};
+inline bool
+operator<(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk < two.chunk ||
+ (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk);
+}
+
+inline bool
+operator==(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk == two.chunk &&
+ one.offsetInChunk == two.offsetInChunk;
+}
+
+inline bool
+operator>=(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk > two.chunk ||
+ (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk);
+}
+
+inline bool
+operator>(const File::Offset &one, const File::Offset &two)
+{
+ return two < one;
+}
+
+inline bool
+operator<=(const File::Offset &one, const File::Offset &two)
+{
+ return two >= one;
+}
+
+
}
#endif
diff --git a/trace_format.hpp b/common/trace_format.hpp
index a8ee5eb..a8ee5eb 100644
--- a/trace_format.hpp
+++ b/common/trace_format.hpp
diff --git a/common/trace_loader.cpp b/common/trace_loader.cpp
new file mode 100644
index 0000000..c14d815
--- /dev/null
+++ b/common/trace_loader.cpp
@@ -0,0 +1,139 @@
+#include "trace_loader.hpp"
+
+
+using namespace Trace;
+
+Loader::Loader()
+ : m_frameMarker(FrameMarker_SwapBuffers)
+{
+}
+
+Loader::~Loader()
+{
+ close();
+}
+
+Loader::FrameMarker Loader::frameMarker() const
+{
+ return m_frameMarker;
+}
+
+void Loader::setFrameMarker(Loader::FrameMarker marker)
+{
+ m_frameMarker = marker;
+}
+
+int Loader::numberOfFrames() const
+{
+ return m_frameBookmarks.size();
+}
+
+int Loader::numberOfCallsInFrame(int frameIdx) const
+{
+ if (frameIdx > m_frameBookmarks.size()) {
+ return 0;
+ }
+ FrameBookmarks::const_iterator itr =
+ m_frameBookmarks.find(frameIdx);
+ return itr->second.numberOfCalls;
+}
+
+bool Loader::open(const char *filename)
+{
+ if (!m_parser.open(filename)) {
+ std::cerr << "error: failed to open " << filename << "\n";
+ return false;
+ }
+ if (!m_parser.supportsOffsets()) {
+ std::cerr << "error: " <<filename<< " doesn't support seeking "
+ << "\n";
+ return false;
+ }
+
+ Trace::Call *call;
+ ParseBookmark startBookmark;
+ int numOfFrames = 0;
+ int numOfCalls = 0;
+ int lastPercentReport = 0;
+
+ m_parser.getBookmark(startBookmark);
+
+ while ((call = m_parser.scan_call())) {
+ ++numOfCalls;
+
+ if (isCallAFrameMarker(call)) {
+ FrameBookmark frameBookmark(startBookmark);
+ frameBookmark.numberOfCalls = numOfCalls;
+
+ m_frameBookmarks[numOfFrames] = frameBookmark;
+ ++numOfFrames;
+
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ std::cerr << "\tPercent scanned = "
+ << m_parser.percentRead()
+ << "..."<<std::endl;
+ lastPercentReport = m_parser.percentRead();
+ }
+
+ m_parser.getBookmark(startBookmark);
+ numOfCalls = 0;
+ }
+ //call->dump(std::cout, color);
+ delete call;
+ }
+ return true;
+}
+
+void Loader::close()
+{
+ m_parser.close();
+}
+
+bool Loader::isCallAFrameMarker(const Trace::Call *call) const
+{
+ std::string name = call->name();
+
+ switch (m_frameMarker) {
+ case FrameMarker_SwapBuffers:
+ return name.find("SwapBuffers") != std::string::npos ||
+ name == "CGLFlushDrawable" ||
+ name == "glFrameTerminatorGREMEDY";
+ break;
+ case FrameMarker_Flush:
+ return name == "glFlush";
+ break;
+ case FrameMarker_Finish:
+ return name == "glFinish";
+ break;
+ case FrameMarker_Clear:
+ return name == "glClear";
+ break;
+ }
+ return false;
+}
+
+std::vector<Trace::Call *> Loader::frame(int idx)
+{
+ int numOfCalls = numberOfCallsInFrame(idx);
+ if (numOfCalls) {
+ const FrameBookmark &frameBookmark = m_frameBookmarks[idx];
+ std::vector<Trace::Call*> calls(numOfCalls);
+ m_parser.setBookmark(frameBookmark.start);
+
+ Trace::Call *call;
+ int parsedCalls = 0;
+ while ((call = m_parser.parse_call())) {
+
+ calls[parsedCalls] = call;
+ ++parsedCalls;
+
+ if (isCallAFrameMarker(call)) {
+ break;
+ }
+
+ }
+ assert(parsedCalls == numOfCalls);
+ return calls;
+ }
+ return std::vector<Trace::Call*>();
+}
diff --git a/common/trace_loader.hpp b/common/trace_loader.hpp
new file mode 100644
index 0000000..9f74a9b
--- /dev/null
+++ b/common/trace_loader.hpp
@@ -0,0 +1,65 @@
+#ifndef TRACE_LOADER_HPP
+#define TRACE_LOADER_HPP
+
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <string>
+#include <map>
+#include <queue>
+#include <vector>
+
+namespace Trace {
+
+class Frame;
+
+class Loader
+{
+public:
+ enum FrameMarker {
+ FrameMarker_SwapBuffers,
+ FrameMarker_Flush,
+ FrameMarker_Finish,
+ FrameMarker_Clear
+ };
+public:
+ Loader();
+ ~Loader();
+
+ Loader::FrameMarker frameMarker() const;
+ void setFrameMarker(Loader::FrameMarker marker);
+
+ int numberOfFrames() const;
+ int numberOfCallsInFrame(int frameIdx) const;
+
+ bool open(const char *filename);
+ void close();
+
+ std::vector<Trace::Call*> frame(int idx);
+
+private:
+ struct FrameBookmark {
+ FrameBookmark()
+ : numberOfCalls(0)
+ {}
+ FrameBookmark(const ParseBookmark &s)
+ : start(s),
+ numberOfCalls(0)
+ {}
+
+ ParseBookmark start;
+ int numberOfCalls;
+ };
+ bool isCallAFrameMarker(const Trace::Call *call) const;
+
+private:
+ Trace::Parser m_parser;
+ FrameMarker m_frameMarker;
+
+ typedef std::map<int, FrameBookmark> FrameBookmarks;
+ FrameBookmarks m_frameBookmarks;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
diff --git a/trace_local_writer.cpp b/common/trace_local_writer.cpp
index ea6c111..e625f2e 100644
--- a/trace_local_writer.cpp
+++ b/common/trace_local_writer.cpp
@@ -41,14 +41,17 @@ namespace Trace {
static void exceptionCallback(void)
{
- OS::DebugMessage("apitrace: flushing trace due to an exception\n");
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()
{
@@ -96,8 +99,6 @@ LocalWriter::open(void) {
Writer::open(szFileName);
- OS::SetExceptionCallback(exceptionCallback);
-
#if 0
// For debugging the exception handler
*((int *)0) = 0;
@@ -142,6 +143,7 @@ void LocalWriter::flush(void) {
if (!acquired) {
OS::AcquireMutex();
if (m_file->isOpened()) {
+ OS::DebugMessage("apitrace: flushing trace due to an exception\n");
m_file->flush();
}
OS::ReleaseMutex();
diff --git a/trace_model.cpp b/common/trace_model.cpp
index 25dc4bb..306b9e7 100644
--- a/trace_model.cpp
+++ b/common/trace_model.cpp
@@ -42,6 +42,11 @@ Call::~Call() {
}
+String::~String() {
+ delete [] value;
+}
+
+
Struct::~Struct() {
for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
delete *it;
diff --git a/trace_model.hpp b/common/trace_model.hpp
index a284754..a74508e 100644
--- a/trace_model.hpp
+++ b/common/trace_model.hpp
@@ -190,6 +190,7 @@ class String : public Value
{
public:
String(const char * _value) : value(_value) {}
+ ~String();
bool toBool(void) const;
const char *toString(void) const;
diff --git a/trace_model_writer.cpp b/common/trace_model_writer.cpp
index dcfcf86..dcfcf86 100644
--- a/trace_model_writer.cpp
+++ b/common/trace_model_writer.cpp
diff --git a/trace_parser.cpp b/common/trace_parser.cpp
index 44d1786..d7b20d2 100644
--- a/trace_parser.cpp
+++ b/common/trace_parser.cpp
@@ -98,22 +98,83 @@ void Parser::close(void) {
}
deleteAll(calls);
- deleteAll(functions);
- deleteAll(structs);
- deleteAll(enums);
- deleteAll(bitmasks);
+
+ // 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();
}
-Call *Parser::parse_call(void) {
+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();
+ parse_enter(mode);
break;
case Trace::EVENT_LEAVE:
- return parse_leave();
+ return parse_leave(mode);
default:
std::cerr << "error: unknown event " << c << "\n";
exit(1);
@@ -142,12 +203,14 @@ T *lookup(std::vector<T *> &map, size_t index) {
}
-void Parser::parse_enter(void) {
+FunctionSig *Parser::parse_function_sig(void) {
size_t id = read_uint();
- FunctionSig *sig = lookup(functions, id);
+ FunctionSigState *sig = lookup(functions, id);
+
if (!sig) {
- sig = new FunctionSig;
+ /* parse the signature */
+ sig = new FunctionSigState;
sig->id = id;
sig->name = read_string();
sig->num_args = read_uint();
@@ -156,14 +219,123 @@ void Parser::parse_enter(void) {
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)) {
+ if (parse_call_details(call, mode)) {
calls.push_back(call);
} else {
delete call;
@@ -171,7 +343,7 @@ void Parser::parse_enter(void) {
}
-Call *Parser::parse_leave(void) {
+Call *Parser::parse_leave(Mode mode) {
unsigned call_no = read_uint();
Call *call = NULL;
for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
@@ -185,7 +357,7 @@ Call *Parser::parse_leave(void) {
return NULL;
}
- if (parse_call_details(call)) {
+ if (parse_call_details(call, mode)) {
return call;
} else {
delete call;
@@ -194,17 +366,17 @@ Call *Parser::parse_leave(void) {
}
-bool Parser::parse_call_details(Call *call) {
+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);
+ parse_arg(call, mode);
break;
case Trace::CALL_RET:
- call->ret = parse_value();
+ call->ret = parse_value(mode);
break;
default:
std::cerr << "error: ("<<call->name()<< ") unknown call detail "
@@ -217,13 +389,15 @@ bool Parser::parse_call_details(Call *call) {
}
-void Parser::parse_arg(Call *call) {
+void Parser::parse_arg(Call *call, Mode mode) {
unsigned index = read_uint();
- Value *value = parse_value();
- if (index >= call->args.size()) {
- call->args.resize(index + 1);
+ Value *value = parse_value(mode);
+ if (value) {
+ if (index >= call->args.size()) {
+ call->args.resize(index + 1);
+ }
+ call->args[index] = value;
}
- call->args[index] = value;
}
@@ -290,16 +464,75 @@ Value *Parser::parse_value(void) {
}
+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);
@@ -307,6 +540,11 @@ Value *Parser::parse_float() {
}
+void Parser::scan_float() {
+ file->skip(sizeof(float));
+}
+
+
Value *Parser::parse_double() {
double value;
file->read(&value, sizeof value);
@@ -314,47 +552,34 @@ Value *Parser::parse_double() {
}
+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() {
- 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);
+ EnumSig *sig = parse_enum_sig();
return new Enum(sig);
}
+void Parser::scan_enum() {
+ parse_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);
+ BitmaskSig *sig = parse_bitmask_sig();
unsigned long long value = read_uint();
@@ -362,6 +587,12 @@ Value *Parser::parse_bitmask() {
}
+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);
@@ -372,6 +603,14 @@ Value *Parser::parse_array(void) {
}
+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);
@@ -382,24 +621,16 @@ Value *Parser::parse_blob(void) {
}
-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;
+void Parser::scan_blob(void) {
+ size_t size = read_uint();
+ if (size) {
+ file->skip(size);
}
- assert(sig);
+}
+
+Value *Parser::parse_struct() {
+ StructSig *sig = parse_struct_sig();
Struct *value = new Struct(sig);
for (size_t i = 0; i < sig->num_members; ++i) {
@@ -410,6 +641,14 @@ Value *Parser::parse_struct() {
}
+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();
@@ -417,6 +656,11 @@ Value *Parser::parse_opaque() {
}
+void Parser::scan_opaque() {
+ skip_uint();
+}
+
+
const char * Parser::read_string(void) {
size_t len = read_uint();
char * value = new char[len + 1];
@@ -431,6 +675,12 @@ const char * Parser::read_string(void) {
}
+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;
@@ -450,6 +700,17 @@ unsigned long long Parser::read_uint(void) {
}
+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
@@ -462,4 +723,9 @@ inline int Parser::read_byte(void) {
}
+inline void Parser::skip_byte(void) {
+ file->skip(1);
+}
+
+
} /* namespace Trace */
diff --git a/trace_parser.hpp b/common/trace_parser.hpp
index 4fff9ad..3aaa6d3 100644
--- a/trace_parser.hpp
+++ b/common/trace_parser.hpp
@@ -30,32 +30,58 @@
#include <iostream>
#include <list>
+#include "trace_file.hpp"
#include "trace_format.hpp"
#include "trace_model.hpp"
namespace Trace {
-class File;
+
+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;
- typedef std::vector<FunctionSig *> FunctionMap;
- FunctionMap functions;
+ // 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;
- typedef std::vector<StructSig *> StructMap;
+ FunctionMap functions;
StructMap structs;
-
- typedef std::vector<EnumSig *> EnumMap;
EnumMap enums;
-
- typedef std::vector<BitmaskSig *> BitmaskMap;
BitmaskMap bitmasks;
unsigned next_call_no;
@@ -71,46 +97,98 @@ public:
void close(void);
- Call *parse_call(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:
- void parse_enter(void);
+ 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(void);
+ Call *parse_leave(Mode mode);
- bool parse_call_details(Call *call);
+ bool parse_call_details(Call *call, Mode mode);
- void parse_arg(Call *call);
+ 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);
};
diff --git a/trace_snappyfile.cpp b/common/trace_snappyfile.cpp
index ad0a577..4dbe42d 100644
--- a/trace_snappyfile.cpp
+++ b/common/trace_snappyfile.cpp
@@ -28,6 +28,8 @@
#include <snappy.h>
+#include <iostream>
+
#include <assert.h>
#include <string.h>
@@ -44,7 +46,7 @@ using namespace Trace;
* The file is composed of a number of chunks, they are:
* chunk {
* uint32 - specifying the length of the compressed data
- * 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
@@ -66,12 +68,15 @@ SnappyFile::SnappyFile(const std::string &filename,
m_cachePtr(0),
m_cacheSize(0)
{
- m_compressedCache = new char[SNAPPY_CHUNK_SIZE];
+ 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)
@@ -88,13 +93,17 @@ bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
//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);
- flushCache();
+ flushReadCache();
} else if (m_stream.is_open() && mode == File::Write) {
// write the snappy file identifier
m_stream << SNAPPY_BYTE1;
@@ -103,7 +112,7 @@ bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
return m_stream.is_open();
}
-bool SnappyFile::rawWrite(const void *buffer, int length)
+bool SnappyFile::rawWrite(const void *buffer, size_t length)
{
if (freeCacheSize() > length) {
memcpy(m_cachePtr, buffer, length);
@@ -111,21 +120,21 @@ bool SnappyFile::rawWrite(const void *buffer, int length)
} else if (freeCacheSize() == length) {
memcpy(m_cachePtr, buffer, length);
m_cachePtr += length;
- flushCache();
+ flushWriteCache();
} else {
int sizeToWrite = length;
while (sizeToWrite >= freeCacheSize()) {
int endSize = freeCacheSize();
int offset = length - sizeToWrite;
- memcpy(m_cachePtr, (char*)buffer + offset, endSize);
+ memcpy(m_cachePtr, (const char*)buffer + offset, endSize);
sizeToWrite -= endSize;
m_cachePtr += endSize;
- flushCache();
+ flushWriteCache();
}
if (sizeToWrite) {
int offset = length - sizeToWrite;
- memcpy(m_cachePtr, (char*)buffer + offset, sizeToWrite);
+ memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite);
m_cachePtr += sizeToWrite;
}
}
@@ -133,7 +142,7 @@ bool SnappyFile::rawWrite(const void *buffer, int length)
return true;
}
-bool SnappyFile::rawRead(void *buffer, int length)
+bool SnappyFile::rawRead(void *buffer, size_t length)
{
if (endOfData()) {
return false;
@@ -143,18 +152,20 @@ bool SnappyFile::rawRead(void *buffer, int length)
memcpy(buffer, m_cachePtr, length);
m_cachePtr += length;
} else {
- int sizeToRead = length;
- int offset = 0;
+ size_t sizeToRead = length;
+ size_t offset = 0;
while (sizeToRead) {
- int chunkSize = std::min(freeCacheSize(), 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)
- flushCache();
- if (!m_cacheSize)
+ if (sizeToRead > 0) {
+ flushReadCache();
+ }
+ if (!m_cacheSize) {
break;
+ }
}
}
@@ -171,7 +182,9 @@ int SnappyFile::rawGetc()
void SnappyFile::rawClose()
{
- flushCache();
+ if (m_mode == File::Write) {
+ flushWriteCache();
+ }
m_stream.close();
delete [] m_cache;
m_cache = NULL;
@@ -180,61 +193,146 @@ void SnappyFile::rawClose()
void SnappyFile::rawFlush()
{
- flushCache();
+ assert(m_mode == File::Write);
+ flushWriteCache();
m_stream.flush();
}
-void SnappyFile::flushCache()
+void SnappyFile::flushWriteCache()
{
- if (m_mode == File::Write) {
+ size_t inputLength = usedCacheSize();
+
+ if (inputLength) {
size_t compressedLength;
- ::snappy::RawCompress(m_cache, SNAPPY_CHUNK_SIZE - freeCacheSize(),
+ ::snappy::RawCompress(m_cache, inputLength,
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();
+ }
+ 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);
- /*
- * 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);
+ if (skipLength < m_cacheSize) {
+ ::snappy::RawUncompress(m_compressedCache, compressedLength,
+ m_cache);
+ }
+ } else {
+ createCache(0);
}
}
void SnappyFile::createCache(size_t size)
{
- m_cache = new char[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(uint32_t value)
+void SnappyFile::writeCompressedLength(size_t length)
{
- m_stream.write((const char*)&value, sizeof value);
+ 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;
}
-uint32_t SnappyFile::readCompressedLength()
+int SnappyFile::rawPercentRead()
{
- uint32_t len;
- m_stream.read((char*)&len, sizeof len);
- return len;
+ return 100 * (double(m_stream.tellg()) / double(m_endPos));
}
diff --git a/trace_snappyfile.hpp b/common/trace_snappyfile.hpp
index c8c415b..33159ec 100644
--- a/trace_snappyfile.hpp
+++ b/common/trace_snappyfile.hpp
@@ -27,13 +27,13 @@
#ifndef TRACE_SNAPPYFILE_HPP
#define TRACE_SNAPPYFILE_HPP
+#include <assert.h>
+
#include "trace_file.hpp"
#include <string>
#include <fstream>
-#include <stdint.h>
-
namespace snappy {
class File;
}
@@ -52,30 +52,43 @@ public:
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, int length);
- virtual bool rawRead(void *buffer, int length);
+ 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 int freeCacheSize() const
+ inline size_t usedCacheSize() const
{
- if (m_cacheSize > 0)
- return m_cacheSize - (m_cachePtr - m_cache);
- else
+ 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 flushCache();
+ void flushWriteCache();
+ void flushReadCache(size_t skipLength = 0);
void createCache(size_t size);
- void writeCompressedLength(uint32_t num);
- uint32_t readCompressedLength();
+ void writeCompressedLength(size_t length);
+ size_t readCompressedLength();
private:
std::fstream m_stream;
char *m_cache;
@@ -83,6 +96,9 @@ private:
size_t m_cacheSize;
char *m_compressedCache;
+
+ File::Offset m_currentOffset;
+ std::streampos m_endPos;
};
}
diff --git a/trace_writer.cpp b/common/trace_writer.cpp
index 5a5f1f7..5a5f1f7 100644
--- a/trace_writer.cpp
+++ b/common/trace_writer.cpp
diff --git a/trace_writer.hpp b/common/trace_writer.hpp
index dfb76b2..dfb76b2 100644
--- a/trace_writer.hpp
+++ b/common/trace_writer.hpp
diff --git a/d3d.py b/d3d.py
index f587fc5..857e5b3 100644
--- a/d3d.py
+++ b/d3d.py
@@ -473,55 +473,3 @@ interfaces = [
ddraw.add_interfaces(interfaces)
-
-class DDrawTracer(DllTracer):
-
- def trace_function_impl_body(self, function):
- if function.name in ('AcquireDDThreadLock', 'ReleaseDDThreadLock'):
- self.dispatch_function(function)
- return
-
- DllTracer.trace_function_impl_body(self, function)
-
- def wrap_arg(self, function, arg):
- if function.name == 'DirectDrawCreateEx' and arg.name == 'lplpDD':
- print ' if (*lplpDD) {'
- for iface in interfaces:
- print ' if (iid == IID_%s) {' % iface.name
- print ' *lplpDD = (LPVOID) new Wrap%s((%s *)*lplpDD);' % (iface.name, iface.name)
- print ' }'
- print ' }'
-
- DllTracer.wrap_arg(self, function, arg)
-
-
-if __name__ == '__main__':
- print '#define INITGUID'
- print '#include <windows.h>'
- print '#include <ddraw.h>'
- print '#include <d3d.h>'
- print
- print '''
-
-#ifndef DDBLT_EXTENDED_FLAGS
-#define DDBLT_EXTENDED_FLAGS 0x40000000l
-#endif
-
-#ifndef DDBLT_EXTENDED_LINEAR_CONTENT
-#define DDBLT_EXTENDED_LINEAR_CONTENT 0x00000004l
-#endif
-
-#ifndef D3DLIGHT_PARALLELPOINT
-#define D3DLIGHT_PARALLELPOINT (D3DLIGHTTYPE)4
-#endif
-
-#ifndef D3DLIGHT_GLSPOT
-#define D3DLIGHT_GLSPOT (D3DLIGHTTYPE)5
-#endif
-
-'''
- print '#include "trace_writer.hpp"'
- print '#include "os.hpp"'
- print
- tracer = DDrawTracer('ddraw.dll')
- tracer.trace_api(ddraw)
diff --git a/d3d8.py b/d3d8.py
index f579a9b..0713696 100644
--- a/d3d8.py
+++ b/d3d8.py
@@ -28,7 +28,6 @@
from winapi import *
from d3d8types import *
from d3d8caps import *
-from trace import DllTracer
HRESULT = Enum("HRESULT", [
"D3D_OK",
@@ -281,27 +280,3 @@ d3d8 = API("d3d8")
d3d8.add_functions([
StdFunction(PDIRECT3D8, "Direct3DCreate8", [(UINT, "SDKVersion")]),
])
-
-
-class D3D8Tracer(DllTracer):
-
- def dump_arg_instance(self, function, arg):
- # Dump shaders as strings
- if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
- print ' DumpShader(Trace::localWriter, %s);' % (arg.name)
- return
-
- DllTracer.dump_arg_instance(self, function, arg)
-
-
-if __name__ == '__main__':
- print '#include <windows.h>'
- print '#include <d3d8.h>'
- print '#include "d3dshader.hpp"'
- print
- print '#include "trace_writer.hpp"'
- print '#include "os.hpp"'
- print
- tracer = D3D8Tracer('d3d8.dll')
- tracer.trace_api(d3d8)
-
diff --git a/d3d8trace.py b/d3d8trace.py
new file mode 100644
index 0000000..236f56c
--- /dev/null
+++ b/d3d8trace.py
@@ -0,0 +1,52 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+from d3d8 import d3d8
+from trace import DllTracer
+
+
+class D3D8Tracer(DllTracer):
+
+ def dump_arg_instance(self, function, arg):
+ # Dump shaders as strings
+ if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
+ print ' DumpShader(Trace::localWriter, %s);' % (arg.name)
+ return
+
+ DllTracer.dump_arg_instance(self, function, arg)
+
+
+if __name__ == '__main__':
+ print '#include <windows.h>'
+ print '#include <d3d8.h>'
+ print '#include "d3dshader.hpp"'
+ print
+ print '#include "trace_writer.hpp"'
+ print '#include "os.hpp"'
+ print
+ tracer = D3D8Tracer('d3d8.dll')
+ tracer.trace_api(d3d8)
+
diff --git a/d3d9.py b/d3d9.py
index 640d218..251f292 100644
--- a/d3d9.py
+++ b/d3d9.py
@@ -28,7 +28,7 @@
from winapi import *
from d3d9types import *
from d3d9caps import *
-from trace import DllTracer
+
D3DSHADER9 = Opaque("const DWORD *")
@@ -448,26 +448,3 @@ d3d9.add_functions([
StdFunction(Void, "D3DPERF_SetOptions", [(DWORD, "dwOptions")]),
StdFunction(DWORD, "D3DPERF_GetStatus", [], fail='0'),
])
-
-
-class D3D9Tracer(DllTracer):
-
- def dump_arg_instance(self, function, arg):
- # Dump shaders as strings
- if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
- print ' DumpShader(Trace::localWriter, %s);' % (arg.name)
- return
-
- DllTracer.dump_arg_instance(self, function, arg)
-
-
-if __name__ == '__main__':
- print '#include "trace_writer.hpp"'
- print '#include "os.hpp"'
- print
- print '#include "d3d9imports.hpp"'
- print '#include "d3dshader.hpp"'
- print
- tracer = D3D9Tracer('d3d9.dll')
- tracer.trace_api(d3d9)
-
diff --git a/d3d9trace.py b/d3d9trace.py
new file mode 100644
index 0000000..b83ebf6
--- /dev/null
+++ b/d3d9trace.py
@@ -0,0 +1,51 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+from trace import DllTracer
+from d3d9 import d3d9
+
+
+class D3D9Tracer(DllTracer):
+
+ def dump_arg_instance(self, function, arg):
+ # Dump shaders as strings
+ if function.name in ('CreateVertexShader', 'CreatePixelShader') and arg.name == 'pFunction':
+ print ' DumpShader(Trace::localWriter, %s);' % (arg.name)
+ return
+
+ DllTracer.dump_arg_instance(self, function, arg)
+
+
+if __name__ == '__main__':
+ print '#include "trace_writer.hpp"'
+ print '#include "os.hpp"'
+ print
+ print '#include "d3d9imports.hpp"'
+ print '#include "d3dshader.hpp"'
+ print
+ tracer = D3D9Tracer('d3d9.dll')
+ tracer.trace_api(d3d9)
+
diff --git a/ddraw.py b/ddraw.py
index 8ac08a8..eb5a072 100644
--- a/ddraw.py
+++ b/ddraw.py
@@ -26,7 +26,6 @@
"""ddraw.h"""
from winapi import *
-from trace import DllTracer
DirectDrawOptSurfaceDescFlags = Flags(DWORD, [
"DDOSD_GUID",
diff --git a/ddrawtrace.py b/ddrawtrace.py
new file mode 100644
index 0000000..0b53f0d
--- /dev/null
+++ b/ddrawtrace.py
@@ -0,0 +1,81 @@
+##########################################################################
+#
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+from d3d import ddraw, interfaces
+from trace import DllTracer
+
+
+class DDrawTracer(DllTracer):
+
+ def trace_function_impl_body(self, function):
+ if function.name in ('AcquireDDThreadLock', 'ReleaseDDThreadLock'):
+ self.dispatch_function(function)
+ return
+
+ DllTracer.trace_function_impl_body(self, function)
+
+ def wrap_arg(self, function, arg):
+ if function.name == 'DirectDrawCreateEx' and arg.name == 'lplpDD':
+ print ' if (*lplpDD) {'
+ for iface in interfaces:
+ print ' if (iid == IID_%s) {' % iface.name
+ print ' *lplpDD = (LPVOID) new Wrap%s((%s *)*lplpDD);' % (iface.name, iface.name)
+ print ' }'
+ print ' }'
+
+ DllTracer.wrap_arg(self, function, arg)
+
+
+if __name__ == '__main__':
+ print '#define INITGUID'
+ print '#include <windows.h>'
+ print '#include <ddraw.h>'
+ print '#include <d3d.h>'
+ print
+ print '''
+
+#ifndef DDBLT_EXTENDED_FLAGS
+#define DDBLT_EXTENDED_FLAGS 0x40000000l
+#endif
+
+#ifndef DDBLT_EXTENDED_LINEAR_CONTENT
+#define DDBLT_EXTENDED_LINEAR_CONTENT 0x00000004l
+#endif
+
+#ifndef D3DLIGHT_PARALLELPOINT
+#define D3DLIGHT_PARALLELPOINT (D3DLIGHTTYPE)4
+#endif
+
+#ifndef D3DLIGHT_GLSPOT
+#define D3DLIGHT_GLSPOT (D3DLIGHTTYPE)5
+#endif
+
+'''
+ print '#include "trace_writer.hpp"'
+ print '#include "os.hpp"'
+ print
+ tracer = DDrawTracer('ddraw.dll')
+ tracer.trace_api(ddraw)
diff --git a/glapi.py b/glapi.py
index cb903fa..a3a0b58 100644
--- a/glapi.py
+++ b/glapi.py
@@ -664,7 +664,7 @@ glapi.add_functions([
GlFunction(Void, "glEnablei", [(GLenum, "target"), (GLuint, "index")]),
GlFunction(Void, "glDisablei", [(GLenum, "target"), (GLuint, "index")]),
GlFunction(GLboolean, "glIsEnabledi", [(GLenum, "target"), (GLuint, "index")], sideeffects=False),
- GlFunction(Void, "glBeginTransformFeedback", [(GLenum, "primitiveMode")]),
+ GlFunction(Void, "glBeginTransformFeedback", [(GLenum_mode, "primitiveMode")]),
GlFunction(Void, "glEndTransformFeedback", []),
GlFunction(Void, "glBindBufferRange", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
GlFunction(Void, "glBindBufferBase", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer")]),
@@ -1177,17 +1177,17 @@ glapi.add_functions([
GlFunction(Void, "glPatchParameterfv", [(GLenum, "pname"), (Const(Array(GLfloat, "__gl_param_size(pname)")), "values")]),
# GL_ARB_transform_feedback2
- GlFunction(Void, "glBindTransformFeedback", [(GLenum, "target"), (GLuint, "id")]),
- GlFunction(Void, "glDeleteTransformFeedbacks", [(GLsizei, "n"), (Const(Array(GLuint, "n")), "ids")]),
- GlFunction(Void, "glGenTransformFeedbacks", [(GLsizei, "n"), Out(Array(GLuint, "n"), "ids")]),
- GlFunction(GLboolean, "glIsTransformFeedback", [(GLuint, "id")], sideeffects=False),
+ GlFunction(Void, "glBindTransformFeedback", [(GLenum, "target"), (GLfeedback, "id")]),
+ GlFunction(Void, "glDeleteTransformFeedbacks", [(GLsizei, "n"), (Const(Array(GLfeedback, "n")), "ids")]),
+ GlFunction(Void, "glGenTransformFeedbacks", [(GLsizei, "n"), Out(Array(GLfeedback, "n"), "ids")]),
+ GlFunction(GLboolean, "glIsTransformFeedback", [(GLfeedback, "id")], sideeffects=False),
GlFunction(Void, "glPauseTransformFeedback", []),
GlFunction(Void, "glResumeTransformFeedback", []),
- GlFunction(Void, "glDrawTransformFeedback", [(GLenum, "mode"), (GLuint, "id")]),
+ GlFunction(Void, "glDrawTransformFeedback", [(GLenum_mode, "mode"), (GLfeedback, "id")]),
# GL_ARB_transform_feedback3
- GlFunction(Void, "glDrawTransformFeedbackStream", [(GLenum, "mode"), (GLuint, "id"), (GLuint, "stream")]),
- GlFunction(Void, "glBeginQueryIndexed", [(GLenum, "target"), (GLuint, "index"), (GLuint, "id")]),
+ GlFunction(Void, "glDrawTransformFeedbackStream", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLuint, "stream")]),
+ GlFunction(Void, "glBeginQueryIndexed", [(GLenum, "target"), (GLuint, "index"), (GLfeedback, "id")]),
GlFunction(Void, "glEndQueryIndexed", [(GLenum, "target"), (GLuint, "index")]),
GlFunction(Void, "glGetQueryIndexediv", [(GLenum, "target"), (GLuint, "index"), (GLenum, "pname"), Out(OpaqueArray(GLint, "__glGetQueryIndexediv_size(pname)"), "params")], sideeffects=False),
@@ -1317,6 +1317,33 @@ glapi.add_functions([
GlFunction(Void, "glGetnUniformuivARB", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "bufSize"), Out(Array(GLuint, "bufSize"), "params")], sideeffects=False),
GlFunction(Void, "glGetnUniformdvARB", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "bufSize"), Out(Array(GLdouble, "bufSize"), "params")], sideeffects=False),
+ # GL_ARB_base_instance
+ GlFunction(Void, "glDrawArraysInstancedBaseInstance", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "primcount"), (GLuint, "baseinstance")]),
+ GlFunction(Void, "glDrawElementsInstancedBaseInstance", [(GLenum_mode, "mode"), (GLsizei, "count"), (GLenum, "type"), (OpaquePointer(Const(GLvoid)), "indices"), (GLsizei, "primcount"), (GLuint, "baseinstance")]),
+ GlFunction(Void, "glDrawElementsInstancedBaseVertexBaseInstance", [(GLenum_mode, "mode"), (GLsizei, "count"), (GLenum, "type"), (OpaquePointer(Const(GLvoid)), "indices"), (GLsizei, "primcount"), (GLint, "basevertex"), (GLuint, "baseinstance")]),
+
+ # GL_ARB_transform_feedback_instanced
+ GlFunction(Void, "glDrawTransformFeedbackInstanced", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLsizei, "primcount")]),
+ GlFunction(Void, "glDrawTransformFeedbackStreamInstanced", [(GLenum_mode, "mode"), (GLfeedback, "id"), (GLuint, "stream"), (GLsizei, "primcount")]),
+
+ # GL_ARB_internalformat_query
+ GlFunction(Void, "glGetInternalformativ", [(GLenum, "target"), (GLenum, "internalformat"), (GLenum, "pname"), (GLsizei, "bufSize"), Out(Array(GLint, "bufSize"), "params")], sideeffects=False),
+
+ # GL_ARB_shader_atomic_counters
+ GlFunction(Void, "glGetActiveAtomicCounterBufferiv", [(GLprogram, "program"), (GLuint, "bufferIndex"), (GLenum, "pname"), Out(OpaqueArray(GLint, "__glGetActiveAtomicCounterBufferiv_size(pname)"), "params")], sideeffects=False),
+
+ # GL_ARB_shader_image_load_store
+ GlFunction(Void, "glBindImageTexture", [(GLuint, "unit"), (GLtexture, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLenum, "format")]),
+ GlFunction(Void, "glMemoryBarrier", [(GLbitfield_barrier, "barriers")]),
+
+ # GL_ARB_texture_storage
+ GlFunction(Void, "glTexStorage1D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width")]),
+ GlFunction(Void, "glTexStorage2D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height")]),
+ GlFunction(Void, "glTexStorage3D", [(GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
+ GlFunction(Void, "glTextureStorage1DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width")]),
+ GlFunction(Void, "glTextureStorage2DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height")]),
+ GlFunction(Void, "glTextureStorage3DEXT", [(GLtexture, "texture"), (GLenum, "target"), (GLsizei, "levels"), (GLenum, "internalformat"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
+
# GL_EXT_blend_color
GlFunction(Void, "glBlendColorEXT", [(GLclampf, "red"), (GLclampf, "green"), (GLclampf, "blue"), (GLclampf, "alpha")]),
@@ -1992,11 +2019,11 @@ glapi.add_functions([
# GL_ATI_element_array
GlFunction(Void, "glElementPointerATI", [(GLenum, "type"), (Const(OpaquePointer(GLvoid)), "pointer")]),
- GlFunction(Void, "glDrawElementArrayATI", [(GLenum, "mode"), (GLsizei, "count")]),
- GlFunction(Void, "glDrawRangeElementArrayATI", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (GLsizei, "count")]),
+ GlFunction(Void, "glDrawElementArrayATI", [(GLenum_mode, "mode"), (GLsizei, "count")]),
+ GlFunction(Void, "glDrawRangeElementArrayATI", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (GLsizei, "count")]),
# GL_SUN_mesh_array
- GlFunction(Void, "glDrawMeshArraysSUN", [(GLenum, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "width")]),
+ GlFunction(Void, "glDrawMeshArraysSUN", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count"), (GLsizei, "width")]),
# GL_NV_occlusion_query
GlFunction(Void, "glGenOcclusionQueriesNV", [(GLsizei, "n"), Out(Array(GLquery, "n"), "ids")]),
@@ -2016,10 +2043,10 @@ glapi.add_functions([
# GL_APPLE_element_array
GlFunction(Void, "glElementPointerAPPLE", [(GLenum, "type"), (Const(Blob(GLvoid, "type")), "pointer")]),
- GlFunction(Void, "glDrawElementArrayAPPLE", [(GLenum, "mode"), (GLint, "first"), (GLsizei, "count")]),
- GlFunction(Void, "glDrawRangeElementArrayAPPLE", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (GLint, "first"), (GLsizei, "count")]),
- GlFunction(Void, "glMultiDrawElementArrayAPPLE", [(GLenum, "mode"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
- GlFunction(Void, "glMultiDrawRangeElementArrayAPPLE", [(GLenum, "mode"), (GLuint, "start"), (GLuint, "end"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
+ GlFunction(Void, "glDrawElementArrayAPPLE", [(GLenum_mode, "mode"), (GLint, "first"), (GLsizei, "count")]),
+ GlFunction(Void, "glDrawRangeElementArrayAPPLE", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (GLint, "first"), (GLsizei, "count")]),
+ GlFunction(Void, "glMultiDrawElementArrayAPPLE", [(GLenum_mode, "mode"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
+ GlFunction(Void, "glMultiDrawRangeElementArrayAPPLE", [(GLenum_mode, "mode"), (GLuint, "start"), (GLuint, "end"), (Const(Array(GLint, "primcount")), "first"), (Const(Array(GLsizei, "primcount")), "count"), (GLsizei, "primcount")]),
# GL_APPLE_fence
GlFunction(Void, "glGenFencesAPPLE", [(GLsizei, "n"), Out(Array(GLuint, "n"), "fences")]),
@@ -2270,7 +2297,7 @@ glapi.add_functions([
GlFunction(GLboolean, "glIsEnabledIndexedEXT", [(GLenum, "target"), (GLuint, "index")], sideeffects=False),
# GL_NV_transform_feedback
- GlFunction(Void, "glBeginTransformFeedbackNV", [(GLenum, "primitiveMode")]),
+ GlFunction(Void, "glBeginTransformFeedbackNV", [(GLenum_mode, "primitiveMode")]),
GlFunction(Void, "glEndTransformFeedbackNV", []),
GlFunction(Void, "glTransformFeedbackAttribsNV", [(GLuint, "count"), (Const(OpaqueArray(GLint, "__glTransformFeedbackAttribsNV_size(count)")), "attribs"), (GLenum, "bufferMode")]),
GlFunction(Void, "glBindBufferRangeNV", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
@@ -2297,7 +2324,7 @@ glapi.add_functions([
GlFunction(Void, "glClearColorIuiEXT", [(GLuint, "red"), (GLuint, "green"), (GLuint, "blue"), (GLuint, "alpha")]),
# GL_GREMEDY_frame_terminator
- GlFunction(Void, "glFrameTerminatorGREMEDY", [], sideeffects=False),
+ GlFunction(Void, "glFrameTerminatorGREMEDY", []),
# GL_NV_conditional_render
GlFunction(Void, "glBeginConditionalRenderNV", [(GLuint, "id"), (GLenum, "mode")]),
@@ -2312,7 +2339,7 @@ glapi.add_functions([
GlFunction(Void, "glGetVideoui64vNV", [(GLuint, "video_slot"), (GLenum, "pname"), Out(OpaqueArray(GLuint64EXT, "__glGetVideoui64vNV_size(pname)"), "params")], sideeffects=False),
# GL_EXT_transform_feedback
- GlFunction(Void, "glBeginTransformFeedbackEXT", [(GLenum, "primitiveMode")]),
+ GlFunction(Void, "glBeginTransformFeedbackEXT", [(GLenum_mode, "primitiveMode")]),
GlFunction(Void, "glEndTransformFeedbackEXT", []),
GlFunction(Void, "glBindBufferRangeEXT", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset"), (GLsizeiptr, "size")]),
GlFunction(Void, "glBindBufferOffsetEXT", [(GLenum, "target"), (GLuint, "index"), (GLbuffer, "buffer"), (GLintptr, "offset")]),
@@ -2527,25 +2554,25 @@ glapi.add_functions([
GlFunction(Void, "glProgramUniformMatrix3x4dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*3*4")), "value")]),
GlFunction(Void, "glProgramUniformMatrix4x2dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*4*2")), "value")]),
GlFunction(Void, "glProgramUniformMatrix4x3dvEXT", [(GLprogram, "program"), (GLlocation, "location"), (GLsizei, "count"), (GLboolean, "transpose"), (Const(Array(GLdouble, "count*4*3")), "value")]),
- Function(Void, "glVertexArrayVertexOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayColorOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayEdgeFlagOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayIndexOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayNormalOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayTexCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayMultiTexCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "texunit"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayFogCoordOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArraySecondaryColorOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayVertexAttribOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLboolean, "normalized"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glVertexArrayVertexAttribIOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
- Function(Void, "glEnableVertexArrayEXT", [(GLuint, "vaobj"), (GLenum, "array")]),
- Function(Void, "glDisableVertexArrayEXT", [(GLuint, "vaobj"), (GLenum, "array")]),
- Function(Void, "glEnableVertexArrayAttribEXT", [(GLuint, "vaobj"), (GLuint, "index")]),
- Function(Void, "glDisableVertexArrayAttribEXT", [(GLuint, "vaobj"), (GLuint, "index")]),
- Function(Void, "glGetVertexArrayIntegervEXT", [(GLuint, "vaobj"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
- Function(Void, "glGetVertexArrayPointervEXT", [(GLuint, "vaobj"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
- Function(Void, "glGetVertexArrayIntegeri_vEXT", [(GLuint, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
- Function(Void, "glGetVertexArrayPointeri_vEXT", [(GLuint, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
+ GlFunction(Void, "glVertexArrayVertexOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayColorOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayEdgeFlagOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayIndexOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayNormalOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayTexCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayMultiTexCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "texunit"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayFogCoordOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArraySecondaryColorOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayVertexAttribOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLboolean, "normalized"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayVertexAttribIOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glEnableVertexArrayEXT", [(GLarray, "vaobj"), (GLenum, "array")]),
+ GlFunction(Void, "glDisableVertexArrayEXT", [(GLarray, "vaobj"), (GLenum, "array")]),
+ GlFunction(Void, "glEnableVertexArrayAttribEXT", [(GLarray, "vaobj"), (GLuint, "index")]),
+ GlFunction(Void, "glDisableVertexArrayAttribEXT", [(GLarray, "vaobj"), (GLuint, "index")]),
+ GlFunction(Void, "glGetVertexArrayIntegervEXT", [(GLarray, "vaobj"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
+ GlFunction(Void, "glGetVertexArrayPointervEXT", [(GLarray, "vaobj"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
+ GlFunction(Void, "glGetVertexArrayIntegeri_vEXT", [(GLarray, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(GLint), "param")]),
+ GlFunction(Void, "glGetVertexArrayPointeri_vEXT", [(GLarray, "vaobj"), (GLuint, "index"), (GLenum, "pname"), Out(Pointer(OpaquePointer(GLvoid)), "param")]),
# GL_NV_explicit_multisample
GlFunction(Void, "glGetMultisamplefvNV", [(GLenum, "pname"), (GLuint, "index"), Out(Array(GLfloat, "2"), "val")], sideeffects=False),
@@ -2553,13 +2580,13 @@ glapi.add_functions([
GlFunction(Void, "glTexRenderbufferNV", [(GLenum, "target"), (GLuint, "renderbuffer")]),
# GL_NV_transform_feedback2
- GlFunction(Void, "glBindTransformFeedbackNV", [(GLenum, "target"), (GLuint, "id")]),
- GlFunction(Void, "glDeleteTransformFeedbacksNV", [(GLsizei, "n"), (Const(Array(GLuint, "n")), "ids")]),
- GlFunction(Void, "glGenTransformFeedbacksNV", [(GLsizei, "n"), Out(Array(GLuint, "n"), "ids")]),
- GlFunction(GLboolean, "glIsTransformFeedbackNV", [(GLuint, "id")], sideeffects=False),
+ GlFunction(Void, "glBindTransformFeedbackNV", [(GLenum, "target"), (GLfeedback, "id")]),
+ GlFunction(Void, "glDeleteTransformFeedbacksNV", [(GLsizei, "n"), (Const(Array(GLfeedback, "n")), "ids")]),
+ GlFunction(Void, "glGenTransformFeedbacksNV", [(GLsizei, "n"), Out(Array(GLfeedback, "n"), "ids")]),
+ GlFunction(GLboolean, "glIsTransformFeedbackNV", [(GLfeedback, "id")], sideeffects=False),
GlFunction(Void, "glPauseTransformFeedbackNV", []),
GlFunction(Void, "glResumeTransformFeedbackNV", []),
- GlFunction(Void, "glDrawTransformFeedbackNV", [(GLenum, "mode"), (GLuint, "id")]),
+ GlFunction(Void, "glDrawTransformFeedbackNV", [(GLenum_mode, "mode"), (GLfeedback, "id")]),
# GL_AMD_performance_monitor
GlFunction(Void, "glGetPerfMonitorGroupsAMD", [Out(Pointer(GLint), "numGroups"), (GLsizei, "groupsSize"), Out(Array(GLuint, "groupsSize"), "groups")], sideeffects=False),
@@ -2661,8 +2688,8 @@ glapi.add_functions([
GlFunction(Void, "glTextureBarrierNV", []),
# GL_EXT_shader_image_load_store
- GlFunction(Void, "glBindImageTextureEXT", [(GLuint, "index"), (GLuint, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLint, "format")]),
- GlFunction(Void, "glMemoryBarrierEXT", [(GLbitfield, "barriers")]),
+ GlFunction(Void, "glBindImageTextureEXT", [(GLuint, "index"), (GLtexture, "texture"), (GLint, "level"), (GLboolean, "layered"), (GLint, "layer"), (GLenum, "access"), (GLint, "format")]),
+ GlFunction(Void, "glMemoryBarrierEXT", [(GLbitfield_barrier, "barriers")]),
# GL_EXT_vertex_attrib_64bit
GlFunction(Void, "glVertexAttribL1dEXT", [(GLuint, "index"), (GLdouble, "x")]),
@@ -2675,7 +2702,7 @@ glapi.add_functions([
GlFunction(Void, "glVertexAttribL4dvEXT", [(GLuint, "index"), (Const(Array(GLdouble, "4")), "v")]),
GlFunction(Void, "glVertexAttribLPointerEXT", [(GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (Const(Blob(GLvoid, "size")), "pointer")]),
GlFunction(Void, "glGetVertexAttribLdvEXT", [(GLuint, "index"), (GLenum, "pname"), Out(OpaqueArray(GLdouble, "__glGetVertexAttribLdvEXT_size(pname)"), "params")], sideeffects=False),
- GlFunction(Void, "glVertexArrayVertexAttribLOffsetEXT", [(GLuint, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
+ GlFunction(Void, "glVertexArrayVertexAttribLOffsetEXT", [(GLarray, "vaobj"), (GLuint, "buffer"), (GLuint, "index"), (GLint, "size"), (GLenum, "type"), (GLsizei, "stride"), (GLintptr, "offset")]),
# GL_NV_gpu_program5
GlFunction(Void, "glProgramSubroutineParametersuivNV", [(GLenum, "target"), (GLsizei, "count"), (Const(Array(GLuint, "count")), "params")]),
@@ -2763,8 +2790,8 @@ glapi.add_functions([
GlFunction(GLsync, "glImportSyncEXT", [(GLenum, "external_sync_type"), (GLintptr, "external_sync"), (GLbitfield, "flags")]),
# GL_AMD_multi_draw_indirect
- GlFunction(Void, "glMultiDrawArraysIndirectAMD", [(GLenum, "mode"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
- GlFunction(Void, "glMultiDrawElementsIndirectAMD", [(GLenum, "mode"), (GLenum, "type"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
+ GlFunction(Void, "glMultiDrawArraysIndirectAMD", [(GLenum_mode, "mode"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
+ GlFunction(Void, "glMultiDrawElementsIndirectAMD", [(GLenum_mode, "mode"), (GLenum, "type"), (Const(OpaquePointer(GLvoid)), "indirect"), (GLsizei, "primcount"), (GLsizei, "stride")]),
# GL_KTX_buffer_region
# XXX: http://www.west.net/~brittain/3dsmax2.htm does not mention EXT suffix
@@ -2781,7 +2808,7 @@ glapi.add_functions([
GlFunction(GLuint, "glBufferRegionEnabledEXT", [], sideeffects=False),
# GL_WIN_swap_hint
- Function(Void, "glAddSwapHintRectWIN", [(GLint, "x"), (GLint, "y"), (GLsizei, "width"), (GLsizei, "height")]),
+ GlFunction(Void, "glAddSwapHintRectWIN", [(GLint, "x"), (GLint, "y"), (GLsizei, "width"), (GLsizei, "height")]),
])
diff --git a/glparams.py b/glparams.py
index 9337a39..8636877 100644
--- a/glparams.py
+++ b/glparams.py
@@ -33,7 +33,7 @@ from gltypes import *
# Shorthands for the types
-X = None # To be determined
+X = None # To be determined, merely an enum
B = GLboolean
I = GLint
I64 = GLint64
@@ -44,6 +44,8 @@ P = OpaquePointer(Void)
S = CString
H = GLhandleARB
+# A underscore prefix (e.g., _glGet) is used to skip automatic code generation
+# for parameters that are obtained through other ways.
parameters = [
# (functions, type, count, name) # value
@@ -285,7 +287,7 @@ parameters = [
("glGet", F, 1, "GL_DEPTH_BIAS"), # 0x0D1F
("glGet", I, 1, "GL_MAX_EVAL_ORDER"), # 0x0D30
("glGet", I, 1, "GL_MAX_LIGHTS"), # 0x0D31
- ("glGet", I, 1, "GL_MAX_CLIP_PLANES"), # 0x0D32
+ ("glGet", I, 1, "GL_MAX_CLIP_DISTANCES"), # 0x0D32
("glGet", I, 1, "GL_MAX_TEXTURE_SIZE"), # 0x0D33
("glGet", I, 1, "GL_MAX_PIXEL_MAP_TABLE"), # 0x0D34
("glGet", I, 1, "GL_MAX_ATTRIB_STACK_DEPTH"), # 0x0D35
@@ -331,8 +333,8 @@ parameters = [
("glGet", I, 1, "GL_MAP1_GRID_SEGMENTS"), # 0x0DD1
("glGet", F, 4, "GL_MAP2_GRID_DOMAIN"), # 0x0DD2
("glGet", I, 2, "GL_MAP2_GRID_SEGMENTS"), # 0x0DD3
- ("glGet", B, 1, "GL_TEXTURE_1D"), # 0x0DE0
- ("glGet", B, 1, "GL_TEXTURE_2D"), # 0x0DE1
+ ("_glGet", B, 1, "GL_TEXTURE_1D"), # 0x0DE0
+ ("_glGet", B, 1, "GL_TEXTURE_2D"), # 0x0DE1
("glGet", P, 1, "GL_FEEDBACK_BUFFER_POINTER"), # 0x0DF0
("glGet", I, 1, "GL_FEEDBACK_BUFFER_SIZE"), # 0x0DF1
("glGet", E, 1, "GL_FEEDBACK_BUFFER_TYPE"), # 0x0DF2
@@ -497,14 +499,14 @@ parameters = [
("", X, 1, "GL_T2F_N3F_V3F"), # 0x2A2B
("", X, 1, "GL_T2F_C4F_N3F_V3F"), # 0x2A2C
("", X, 1, "GL_T4F_C4F_N3F_V4F"), # 0x2A2D
- ("glGet", B, 1, "GL_CLIP_PLANE0"), # 0x3000
- ("glGet", B, 1, "GL_CLIP_PLANE1"), # 0x3001
- ("glGet", B, 1, "GL_CLIP_PLANE2"), # 0x3002
- ("glGet", B, 1, "GL_CLIP_PLANE3"), # 0x3003
- ("glGet", B, 1, "GL_CLIP_PLANE4"), # 0x3004
- ("glGet", B, 1, "GL_CLIP_PLANE5"), # 0x3005
- ("", X, 1, "GL_CLIP_DISTANCE6"), # 0x3006
- ("", X, 1, "GL_CLIP_DISTANCE7"), # 0x3007
+ ("glGet", B, 1, "GL_CLIP_DISTANCE0"), # 0x3000
+ ("glGet", B, 1, "GL_CLIP_DISTANCE1"), # 0x3001
+ ("glGet", B, 1, "GL_CLIP_DISTANCE2"), # 0x3002
+ ("glGet", B, 1, "GL_CLIP_DISTANCE3"), # 0x3003
+ ("glGet", B, 1, "GL_CLIP_DISTANCE4"), # 0x3004
+ ("glGet", B, 1, "GL_CLIP_DISTANCE5"), # 0x3005
+ ("glGet", B, 1, "GL_CLIP_DISTANCE6"), # 0x3006
+ ("glGet", B, 1, "GL_CLIP_DISTANCE7"), # 0x3007
("_glGet", B, 1, "GL_LIGHT0"), # 0x4000
("_glGet", B, 1, "GL_LIGHT1"), # 0x4001
("_glGet", B, 1, "GL_LIGHT2"), # 0x4002
@@ -617,9 +619,9 @@ parameters = [
("", X, 1, "GL_TEXTURE_TOO_LARGE_EXT"), # 0x8065
("glGetTexParameter", F, 1, "GL_TEXTURE_PRIORITY"), # 0x8066
("glGetTexParameter", B, 1, "GL_TEXTURE_RESIDENT"), # 0x8067
- ("glGet", I, 1, "GL_TEXTURE_BINDING_1D"), # 0x8068
- ("glGet", I, 1, "GL_TEXTURE_BINDING_2D"), # 0x8069
- ("glGet", I, 1, "GL_TEXTURE_BINDING_3D"), # 0x806A
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_1D"), # 0x8068
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_2D"), # 0x8069
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_3D"), # 0x806A
("glGet", I, 1, "GL_PACK_SKIP_IMAGES"), # 0x806B
("glGet", F, 1, "GL_PACK_IMAGE_HEIGHT"), # 0x806C
("glGet", I, 1, "GL_UNPACK_SKIP_IMAGES"), # 0x806D
@@ -1182,8 +1184,8 @@ parameters = [
("", X, 1, "GL_ALL_COMPLETED_NV"), # 0x84F2
("", X, 1, "GL_FENCE_STATUS_NV"), # 0x84F3
("", X, 1, "GL_FENCE_CONDITION_NV"), # 0x84F4
- ("glGet", B, 1, "GL_TEXTURE_RECTANGLE"), # 0x84F5
- ("glGet", I, 1, "GL_TEXTURE_BINDING_RECTANGLE"), # 0x84F6
+ ("_glGet", B, 1, "GL_TEXTURE_RECTANGLE"), # 0x84F5
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_RECTANGLE"), # 0x84F6
("", X, 1, "GL_PROXY_TEXTURE_RECTANGLE"), # 0x84F7
("glGet", I, 1, "GL_MAX_RECTANGLE_TEXTURE_SIZE"), # 0x84F8
("", X, 1, "GL_DEPTH_STENCIL"), # 0x84F9
@@ -1210,8 +1212,8 @@ parameters = [
("", X, 1, "GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT"), # 0x8510
("", X, 1, "GL_NORMAL_MAP"), # 0x8511
("", X, 1, "GL_REFLECTION_MAP"), # 0x8512
- ("glGet", B, 1, "GL_TEXTURE_CUBE_MAP"), # 0x8513
- ("glGet", I, 1, "GL_TEXTURE_BINDING_CUBE_MAP"), # 0x8514
+ ("_glGet", B, 1, "GL_TEXTURE_CUBE_MAP"), # 0x8513
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_CUBE_MAP"), # 0x8514
("", X, 1, "GL_TEXTURE_CUBE_MAP_POSITIVE_X"), # 0x8515
("", X, 1, "GL_TEXTURE_CUBE_MAP_NEGATIVE_X"), # 0x8516
("", X, 1, "GL_TEXTURE_CUBE_MAP_POSITIVE_Y"), # 0x8517
@@ -1233,8 +1235,8 @@ parameters = [
("", X, 1, "GL_VARIABLE_E_NV"), # 0x8527
("", X, 1, "GL_VARIABLE_F_NV"), # 0x8528
("", X, 1, "GL_VARIABLE_G_NV"), # 0x8529
- ("", X, 1, "GL_CONSTANT_COLOR0_NV"), # 0x852A
- ("", X, 1, "GL_CONSTANT_COLOR1_NV"), # 0x852B
+ ("glGet", F, 4, "GL_CONSTANT_COLOR0_NV"), # 0x852A
+ ("glGet", F, 4, "GL_CONSTANT_COLOR1_NV"), # 0x852B
("", X, 1, "GL_PRIMARY_COLOR_NV"), # 0x852C
("", X, 1, "GL_SECONDARY_COLOR_NV"), # 0x852D
("", X, 1, "GL_SPARE0_NV"), # 0x852E
@@ -1268,9 +1270,9 @@ parameters = [
("", X, 1, "GL_COMBINER_AB_OUTPUT_NV"), # 0x854A
("", X, 1, "GL_COMBINER_CD_OUTPUT_NV"), # 0x854B
("", X, 1, "GL_COMBINER_SUM_OUTPUT_NV"), # 0x854C
- ("", X, 1, "GL_MAX_GENERAL_COMBINERS_NV"), # 0x854D
- ("", X, 1, "GL_NUM_GENERAL_COMBINERS_NV"), # 0x854E
- ("", X, 1, "GL_COLOR_SUM_CLAMP_NV"), # 0x854F
+ ("glGet", I, 1, "GL_MAX_GENERAL_COMBINERS_NV"), # 0x854D
+ ("glGet", I, 1, "GL_NUM_GENERAL_COMBINERS_NV"), # 0x854E
+ ("glGet", B, 1, "GL_COLOR_SUM_CLAMP_NV"), # 0x854F
("", X, 1, "GL_COMBINER0_NV"), # 0x8550
("", X, 1, "GL_COMBINER1_NV"), # 0x8551
("", X, 1, "GL_COMBINER2_NV"), # 0x8552
@@ -1384,7 +1386,7 @@ parameters = [
("", X, 1, "GL_MATRIX7_NV"), # 0x8637
("glGet", I, 1, "GL_CURRENT_MATRIX_STACK_DEPTH_ARB"), # 0x8640
("glGet", F, 16, "GL_CURRENT_MATRIX_ARB"), # 0x8641
- ("glGet", B, 1, "GL_VERTEX_PROGRAM_POINT_SIZE"), # 0x8642
+ ("glGet", B, 1, "GL_PROGRAM_POINT_SIZE"), # 0x8642
("glGet", B, 1, "GL_VERTEX_PROGRAM_TWO_SIDE"), # 0x8643
("", X, 1, "GL_PROGRAM_PARAMETER_NV"), # 0x8644
("glGetVertexAttrib", P, 1, "GL_VERTEX_ATTRIB_ARRAY_POINTER"), # 0x8645
@@ -1825,7 +1827,7 @@ parameters = [
("glGetTexParameter", E, 1, "GL_DEPTH_TEXTURE_MODE"), # 0x884B
("glGetTexParameter", E, 1, "GL_TEXTURE_COMPARE_MODE"), # 0x884C
("glGetTexParameter", E, 1, "GL_TEXTURE_COMPARE_FUNC"), # 0x884D
- ("", X, 1, "GL_COMPARE_R_TO_TEXTURE"), # 0x884E
+ ("", X, 1, "GL_COMPARE_REF_TO_TEXTURE"), # 0x884E
("glGet", B, 1, "GL_TEXTURE_CUBE_MAP_SEAMLESS"), # 0x884F
("", X, 1, "GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV"), # 0x8850
("", X, 1, "GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV"), # 0x8851
@@ -2118,6 +2120,12 @@ parameters = [
("", X, 1, "GL_RESAMPLE_ZERO_FILL_OML"), # 0x8987
("", X, 1, "GL_RESAMPLE_AVERAGE_OML"), # 0x8988
("", X, 1, "GL_RESAMPLE_DECIMATE_OML"), # 0x8989
+ #("", X, 1, "GL_POINT_SIZE_ARRAY_TYPE_OES"), # 0x898A
+ #("", X, 1, "GL_POINT_SIZE_ARRAY_STRIDE_OES"), # 0x898B
+ #("", X, 1, "GL_POINT_SIZE_ARRAY_POINTER_OES"), # 0x898C
+ #("", X, 1, "GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES"), # 0x898D
+ #("", X, 1, "GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES"), # 0x898E
+ #("", X, 1, "GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES"), # 0x898F
("", X, 1, "GL_VERTEX_ATTRIB_MAP1_APPLE"), # 0x8A00
("", X, 1, "GL_VERTEX_ATTRIB_MAP2_APPLE"), # 0x8A01
("", X, 1, "GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE"), # 0x8A02
@@ -2177,9 +2185,9 @@ parameters = [
("glGetActiveUniformBlock", B, 1, "GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER"), # 0x8A44
("glGetActiveUniformBlock", B, 1, "GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER"), # 0x8A45
("glGetActiveUniformBlock", B, 1, "GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER"), # 0x8A46
- #"glGet", (X, 1, "GL_TEXTURE_SRGB_DECODE_EXT"), # 0x8A48
- #"glGet", (X, 1, "GL_DECODE_EXT"), # 0x8A49
- #"glGet", (X, 1, "GL_SKIP_DECODE_EXT"), # 0x8A4A
+ ("glGetTexParameter", E, 1, "GL_TEXTURE_SRGB_DECODE_EXT"), # 0x8A48
+ ("", X, 1, "GL_DECODE_EXT"), # 0x8A49
+ ("", X, 1, "GL_SKIP_DECODE_EXT"), # 0x8A4A
("", X, 1, "GL_FRAGMENT_SHADER"), # 0x8B30
("", X, 1, "GL_VERTEX_SHADER"), # 0x8B31
("", H, 1, "GL_PROGRAM_OBJECT_ARB"), # 0x8B40
@@ -2232,8 +2240,30 @@ parameters = [
("", X, 1, "GL_FRAGMENT_SHADER_DERIVATIVE_HINT"), # 0x8B8B
("", X, 1, "GL_SHADING_LANGUAGE_VERSION"), # 0x8B8C
("glGet", I, 1, "GL_CURRENT_PROGRAM"), # 0x8B8D
+ #("", X, 1, "GL_PALETTE4_RGB8_OES"), # 0x8B90
+ #("", X, 1, "GL_PALETTE4_RGBA8_OES"), # 0x8B91
+ #("", X, 1, "GL_PALETTE4_R5_G6_B5_OES"), # 0x8B92
+ #("", X, 1, "GL_PALETTE4_RGBA4_OES"), # 0x8B93
+ #("", X, 1, "GL_PALETTE4_RGB5_A1_OES"), # 0x8B94
+ #("", X, 1, "GL_PALETTE8_RGB8_OES"), # 0x8B95
+ #("", X, 1, "GL_PALETTE8_RGBA8_OES"), # 0x8B96
+ #("", X, 1, "GL_PALETTE8_R5_G6_B5_OES"), # 0x8B97
+ #("", X, 1, "GL_PALETTE8_RGBA4_OES"), # 0x8B98
+ #("", X, 1, "GL_PALETTE8_RGB5_A1_OES"), # 0x8B99
("", X, 1, "GL_IMPLEMENTATION_COLOR_READ_TYPE"), # 0x8B9A
("", X, 1, "GL_IMPLEMENTATION_COLOR_READ_FORMAT"), # 0x8B9B
+ #("", X, 1, "GL_POINT_SIZE_ARRAY_OES"), # 0x8B9C
+ #("", X, 1, "GL_TEXTURE_CROP_RECT_OES"), # 0x8B9D
+ #("", X, 1, "GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES"), # 0x8B9E
+ #("", X, 1, "GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES"), # 0x8B9F
+ #("", X, 1, "GL_FRAGMENT_PROGRAM_POSITION_MESA"), # 0x8BB0
+ #("", X, 1, "GL_FRAGMENT_PROGRAM_CALLBACK_MESA"), # 0x8BB1
+ #("", X, 1, "GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA"), # 0x8BB2
+ #("", X, 1, "GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA"), # 0x8BB3
+ #("", X, 1, "GL_VERTEX_PROGRAM_CALLBACK_MESA"), # 0x8BB4
+ #("", X, 1, "GL_VERTEX_PROGRAM_POSITION_MESA"), # 0x8BB4
+ #("", X, 1, "GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA"), # 0x8BB6
+ #("", X, 1, "GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA"), # 0x8BB7
("", X, 1, "GL_COUNTER_TYPE_AMD"), # 0x8BC0
("", X, 1, "GL_COUNTER_RANGE_AMD"), # 0x8BC1
("", X, 1, "GL_UNSIGNED_INT64_AMD"), # 0x8BC2
@@ -2241,6 +2271,28 @@ parameters = [
("", X, 1, "GL_PERFMON_RESULT_AVAILABLE_AMD"), # 0x8BC4
("", X, 1, "GL_PERFMON_RESULT_SIZE_AMD"), # 0x8BC5
("", X, 1, "GL_PERFMON_RESULT_AMD"), # 0x8BC6
+ #("", X, 1, "GL_TEXTURE_WIDTH_QCOM"), # 0x8BD2
+ #("", X, 1, "GL_TEXTURE_HEIGHT_QCOM"), # 0x8BD3
+ #("", X, 1, "GL_TEXTURE_DEPTH_QCOM"), # 0x8BD4
+ #("", X, 1, "GL_TEXTURE_INTERNAL_FORMAT_QCOM"), # 0x8BD5
+ #("", X, 1, "GL_TEXTURE_FORMAT_QCOM"), # 0x8BD6
+ #("", X, 1, "GL_TEXTURE_TYPE_QCOM"), # 0x8BD7
+ #("", X, 1, "GL_TEXTURE_IMAGE_VALID_QCOM"), # 0x8BD8
+ #("", X, 1, "GL_TEXTURE_NUM_LEVELS_QCOM"), # 0x8BD9
+ #("", X, 1, "GL_TEXTURE_TARGET_QCOM"), # 0x8BDA
+ #("", X, 1, "GL_TEXTURE_OBJECT_VALID_QCOM"), # 0x8BDB
+ #("", X, 1, "GL_STATE_RESTORE"), # 0x8BDC
+ #("", X, 1, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"), # 0x8C00
+ #("", X, 1, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"), # 0x8C01
+ #("", X, 1, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"), # 0x8C02
+ #("", X, 1, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"), # 0x8C03
+ #("", X, 1, "GL_MODULATE_COLOR_IMG"), # 0x8C04
+ #("", X, 1, "GL_RECIP_ADD_SIGNED_ALPHA_IMG"), # 0x8C05
+ #("", X, 1, "GL_TEXTURE_ALPHA_MODULATE_IMG"), # 0x8C06
+ #("", X, 1, "GL_FACTOR_ALPHA_MODULATE_IMG"), # 0x8C07
+ #("", X, 1, "GL_FRAGMENT_ALPHA_MODULATE_IMG"), # 0x8C08
+ #("", X, 1, "GL_ADD_BLEND_IMG"), # 0x8C09
+ #("", X, 1, "GL_SGX_BINARY_IMG"), # 0x8C0A
("", X, 1, "GL_TEXTURE_RED_TYPE"), # 0x8C10
("", X, 1, "GL_TEXTURE_GREEN_TYPE"), # 0x8C11
("", X, 1, "GL_TEXTURE_BLUE_TYPE"), # 0x8C12
@@ -2253,8 +2305,8 @@ parameters = [
("", X, 1, "GL_PROXY_TEXTURE_1D_ARRAY"), # 0x8C19
("", X, 1, "GL_TEXTURE_2D_ARRAY"), # 0x8C1A
("", X, 1, "GL_PROXY_TEXTURE_2D_ARRAY"), # 0x8C1B
- ("glGet", I, 1, "GL_TEXTURE_BINDING_1D_ARRAY"), # 0x8C1C
- ("glGet", I, 1, "GL_TEXTURE_BINDING_2D_ARRAY"), # 0x8C1D
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_1D_ARRAY"), # 0x8C1C
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_2D_ARRAY"), # 0x8C1D
("", X, 1, "GL_GEOMETRY_PROGRAM_NV"), # 0x8C26
("", X, 1, "GL_MAX_PROGRAM_OUTPUT_VERTICES_NV"), # 0x8C27
("", X, 1, "GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV"), # 0x8C28
@@ -2321,6 +2373,8 @@ parameters = [
("", X, 1, "GL_SEPARATE_ATTRIBS"), # 0x8C8D
("", X, 1, "GL_TRANSFORM_FEEDBACK_BUFFER"), # 0x8C8E
("glGet", I, 1, "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING"), # 0x8C8F
+ #("", X, 1, "GL_ATC_RGB_AMD"), # 0x8C92
+ #("", X, 1, "GL_ATC_RGBA_EXPLICIT_ALPHA_AMD"), # 0x8C93
("glGet", E, 1, "GL_POINT_SPRITE_COORD_ORIGIN"), # 0x8CA0
("", X, 1, "GL_LOWER_LEFT"), # 0x8CA1
("", X, 1, "GL_UPPER_LEFT"), # 0x8CA2
@@ -2384,6 +2438,14 @@ parameters = [
("glGetRenderbufferParameter", I, 1, "GL_RENDERBUFFER_STENCIL_SIZE"), # 0x8D55
("", X, 1, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"), # 0x8D56
("glGet", I, 1, "GL_MAX_SAMPLES"), # 0x8D57
+ #("", X, 1, "GL_TEXTURE_GEN_STR_OES"), # 0x8D60
+ #("", X, 1, "GL_HALF_FLOAT_OES"), # 0x8D61
+ #("", X, 1, "GL_RGB565_OES"), # 0x8D62
+ #("", X, 1, "GL_ETC1_RGB8_OES"), # 0x8D64
+ #("", X, 1, "GL_TEXTURE_EXTERNAL_OES"), # 0x8D65
+ #("", X, 1, "GL_SAMPLER_EXTERNAL_OES"), # 0x8D66
+ #("", X, 1, "GL_TEXTURE_BINDING_EXTERNAL_OES"), # 0x8D67
+ #("", X, 1, "GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES"), # 0x8D68
("", X, 1, "GL_RGBA32UI"), # 0x8D70
("", X, 1, "GL_RGB32UI"), # 0x8D71
("", X, 1, "GL_ALPHA32UI_EXT"), # 0x8D72
@@ -2595,6 +2657,14 @@ parameters = [
("", X, 1, "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"), # 0x8E8D
("", X, 1, "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"), # 0x8E8E
("", X, 1, "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"), # 0x8E8F
+ #("", X, 1, "GL_COVERAGE_COMPONENT_NV"), # 0x8ED0
+ #("", X, 1, "GL_COVERAGE_COMPONENT4_NV"), # 0x8ED1
+ #("", X, 1, "GL_COVERAGE_ATTACHMENT_NV"), # 0x8ED2
+ #("", X, 1, "GL_COVERAGE_BUFFERS_NV"), # 0x8ED3
+ #("", X, 1, "GL_COVERAGE_SAMPLES_NV"), # 0x8ED4
+ #("", X, 1, "GL_COVERAGE_ALL_FRAGMENTS_NV"), # 0x8ED5
+ #("", X, 1, "GL_COVERAGE_EDGE_FRAGMENTS_NV"), # 0x8ED6
+ #("", X, 1, "GL_COVERAGE_AUTOMATIC_NV"), # 0x8ED7
("", X, 1, "GL_BUFFER_GPU_ADDRESS_NV"), # 0x8F1D
("", X, 1, "GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV"), # 0x8F1E
("", X, 1, "GL_ELEMENT_ARRAY_UNIFIED_NV"), # 0x8F1F
@@ -2622,13 +2692,13 @@ parameters = [
("", X, 1, "GL_MAX_SHADER_BUFFER_ADDRESS_NV"), # 0x8F35
("", X, 1, "GL_COPY_READ_BUFFER"), # 0x8F36
("", X, 1, "GL_COPY_WRITE_BUFFER"), # 0x8F37
- ("", X, 1, "GL_MAX_IMAGE_UNITS_EXT"), # 0x8F38
- ("", X, 1, "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT"), # 0x8F39
- ("", X, 1, "GL_IMAGE_BINDING_NAME_EXT"), # 0x8F3A
- ("", X, 1, "GL_IMAGE_BINDING_LEVEL_EXT"), # 0x8F3B
- ("", X, 1, "GL_IMAGE_BINDING_LAYERED_EXT"), # 0x8F3C
- ("", X, 1, "GL_IMAGE_BINDING_LAYER_EXT"), # 0x8F3D
- ("", X, 1, "GL_IMAGE_BINDING_ACCESS_EXT"), # 0x8F3E
+ ("", X, 1, "GL_MAX_IMAGE_UNITS"), # 0x8F38
+ ("", X, 1, "GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS"), # 0x8F39
+ ("", X, 1, "GL_IMAGE_BINDING_NAME"), # 0x8F3A
+ ("", X, 1, "GL_IMAGE_BINDING_LEVEL"), # 0x8F3B
+ ("", X, 1, "GL_IMAGE_BINDING_LAYERED"), # 0x8F3C
+ ("", X, 1, "GL_IMAGE_BINDING_LAYER"), # 0x8F3D
+ ("", X, 1, "GL_IMAGE_BINDING_ACCESS"), # 0x8F3E
("", X, 1, "GL_DRAW_INDIRECT_BUFFER"), # 0x8F3F
("", X, 1, "GL_DRAW_INDIRECT_UNIFIED_NV"), # 0x8F40
("", X, 1, "GL_DRAW_INDIRECT_ADDRESS_NV"), # 0x8F41
@@ -2645,6 +2715,7 @@ parameters = [
("", X, 1, "GL_DOUBLE_MAT3x4"), # 0x8F4C
("", X, 1, "GL_DOUBLE_MAT4x2"), # 0x8F4D
("", X, 1, "GL_DOUBLE_MAT4x3"), # 0x8F4E
+ #("", X, 1, "GL_MALI_SHADER_BINARY_ARM"), # 0x8F60
("", X, 1, "GL_RED_SNORM"), # 0x8F90
("", X, 1, "GL_RG_SNORM"), # 0x8F91
("", X, 1, "GL_RGB_SNORM"), # 0x8F92
@@ -2660,6 +2731,9 @@ parameters = [
("", X, 1, "GL_SIGNED_NORMALIZED"), # 0x8F9C
("glGet", B, 1, "GL_PRIMITIVE_RESTART"), # 0x8F9D
("glGet", I, 1, "GL_PRIMITIVE_RESTART_INDEX"), # 0x8F9E
+ #("", X, 1, "GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS"), # 0x8F9F
+ #("", X, 1, "GL_PERFMON_GLOBAL_MODE_QCOM"), # 0x8FA0
+ #("", X, 1, "GL_SHADER_BINARY_VIV"), # 0x8FC4
("", X, 1, "GL_INT8_NV"), # 0x8FE0
("", X, 1, "GL_INT8_VEC2_NV"), # 0x8FE1
("", X, 1, "GL_INT8_VEC3_NV"), # 0x8FE2
@@ -2697,7 +2771,7 @@ parameters = [
("", X, 1, "GL_DISCRETE_AMD"), # 0x9006
("", X, 1, "GL_CONTINUOUS_AMD"), # 0x9007
("", X, 1, "GL_TEXTURE_CUBE_MAP_ARRAY"), # 0x9009
- ("glGet", I, 1, "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY"), # 0x900A
+ ("_glGet", I, 1, "GL_TEXTURE_BINDING_CUBE_MAP_ARRAY"), # 0x900A
("", X, 1, "GL_PROXY_TEXTURE_CUBE_MAP_ARRAY"), # 0x900B
("", X, 1, "GL_SAMPLER_CUBE_MAP_ARRAY"), # 0x900C
("", X, 1, "GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW"), # 0x900D
@@ -2715,6 +2789,8 @@ parameters = [
("", X, 1, "GL_LUMINANCE16_SNORM"), # 0x9019
("", X, 1, "GL_LUMINANCE16_ALPHA16_SNORM"), # 0x901A
("", X, 1, "GL_INTENSITY16_SNORM"), # 0x901B
+ ("", X, 1, "GL_FACTOR_MIN_AMD"), # 0x901C
+ ("", X, 1, "GL_FACTOR_MAX_AMD"), # 0x901D
("", B, 1, "GL_DEPTH_CLAMP_NEAR_AMD"), # 0x901E
("", B, 1, "GL_DEPTH_CLAMP_FAR_AMD"), # 0x901F
("", X, 1, "GL_VIDEO_BUFFER_NV"), # 0x9020
@@ -2746,42 +2822,57 @@ parameters = [
("", X, 1, "GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV"), # 0x903A
("", X, 1, "GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV"), # 0x903B
("", X, 1, "GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV"), # 0x903C
- ("", X, 1, "GL_IMAGE_1D_EXT"), # 0x904C
- ("", X, 1, "GL_IMAGE_2D_EXT"), # 0x904D
- ("", X, 1, "GL_IMAGE_3D_EXT"), # 0x904E
- ("", X, 1, "GL_IMAGE_2D_RECT_EXT"), # 0x904F
- ("", X, 1, "GL_IMAGE_CUBE_EXT"), # 0x9050
- ("", X, 1, "GL_IMAGE_BUFFER_EXT"), # 0x9051
- ("", X, 1, "GL_IMAGE_1D_ARRAY_EXT"), # 0x9052
- ("", X, 1, "GL_IMAGE_2D_ARRAY_EXT"), # 0x9053
- ("", X, 1, "GL_IMAGE_CUBE_MAP_ARRAY_EXT"), # 0x9054
- ("", X, 1, "GL_IMAGE_2D_MULTISAMPLE_EXT"), # 0x9055
- ("", X, 1, "GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"), # 0x9056
- ("", X, 1, "GL_INT_IMAGE_1D_EXT"), # 0x9057
- ("", X, 1, "GL_INT_IMAGE_2D_EXT"), # 0x9058
- ("", X, 1, "GL_INT_IMAGE_3D_EXT"), # 0x9059
- ("", X, 1, "GL_INT_IMAGE_2D_RECT_EXT"), # 0x905A
- ("", X, 1, "GL_INT_IMAGE_CUBE_EXT"), # 0x905B
- ("", X, 1, "GL_INT_IMAGE_BUFFER_EXT"), # 0x905C
- ("", X, 1, "GL_INT_IMAGE_1D_ARRAY_EXT"), # 0x905D
- ("", X, 1, "GL_INT_IMAGE_2D_ARRAY_EXT"), # 0x905E
- ("", X, 1, "GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT"), # 0x905F
- ("", X, 1, "GL_INT_IMAGE_2D_MULTISAMPLE_EXT"), # 0x9060
- ("", X, 1, "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"), # 0x9061
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_1D_EXT"), # 0x9062
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_EXT"), # 0x9063
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_3D_EXT"), # 0x9064
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT"), # 0x9065
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_CUBE_EXT"), # 0x9066
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_BUFFER_EXT"), # 0x9067
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT"), # 0x9068
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT"), # 0x9069
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT"), # 0x906A
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT"), # 0x906B
- ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT"), # 0x906C
- ("", X, 1, "GL_MAX_IMAGE_SAMPLES_EXT"), # 0x906D
- ("", X, 1, "GL_IMAGE_BINDING_FORMAT_EXT"), # 0x906E
+ ("", X, 1, "GL_TEXTURE_COVERAGE_SAMPLES_NV"), # 0x9045
+ ("", X, 1, "GL_TEXTURE_COLOR_SAMPLES_NV"), # 0x9046
+ ("", X, 1, "GL_IMAGE_1D"), # 0x904C
+ ("", X, 1, "GL_IMAGE_2D"), # 0x904D
+ ("", X, 1, "GL_IMAGE_3D"), # 0x904E
+ ("", X, 1, "GL_IMAGE_2D_RECT"), # 0x904F
+ ("", X, 1, "GL_IMAGE_CUBE"), # 0x9050
+ ("", X, 1, "GL_IMAGE_BUFFER"), # 0x9051
+ ("", X, 1, "GL_IMAGE_1D_ARRAY"), # 0x9052
+ ("", X, 1, "GL_IMAGE_2D_ARRAY"), # 0x9053
+ ("", X, 1, "GL_IMAGE_CUBE_MAP_ARRAY"), # 0x9054
+ ("", X, 1, "GL_IMAGE_2D_MULTISAMPLE"), # 0x9055
+ ("", X, 1, "GL_IMAGE_2D_MULTISAMPLE_ARRAY"), # 0x9056
+ ("", X, 1, "GL_INT_IMAGE_1D"), # 0x9057
+ ("", X, 1, "GL_INT_IMAGE_2D"), # 0x9058
+ ("", X, 1, "GL_INT_IMAGE_3D"), # 0x9059
+ ("", X, 1, "GL_INT_IMAGE_2D_RECT"), # 0x905A
+ ("", X, 1, "GL_INT_IMAGE_CUBE"), # 0x905B
+ ("", X, 1, "GL_INT_IMAGE_BUFFER"), # 0x905C
+ ("", X, 1, "GL_INT_IMAGE_1D_ARRAY"), # 0x905D
+ ("", X, 1, "GL_INT_IMAGE_2D_ARRAY"), # 0x905E
+ ("", X, 1, "GL_INT_IMAGE_CUBE_MAP_ARRAY"), # 0x905F
+ ("", X, 1, "GL_INT_IMAGE_2D_MULTISAMPLE"), # 0x9060
+ ("", X, 1, "GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY"), # 0x9061
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_1D"), # 0x9062
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D"), # 0x9063
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_3D"), # 0x9064
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_RECT"), # 0x9065
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_CUBE"), # 0x9066
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_BUFFER"), # 0x9067
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_1D_ARRAY"), # 0x9068
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_ARRAY"), # 0x9069
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY"), # 0x906A
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE"), # 0x906B
+ ("", X, 1, "GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY"), # 0x906C
+ ("", X, 1, "GL_MAX_IMAGE_SAMPLES"), # 0x906D
+ ("", X, 1, "GL_IMAGE_BINDING_FORMAT"), # 0x906E
("", X, 1, "GL_RGB10_A2UI"), # 0x906F
+ ("", X, 1, "GL_SCALED_RESOLVE_FASTEST_EXT"), # 0x90BA
+ ("", X, 1, "GL_SCALED_RESOLVE_NICEST_EXT"), # 0x90BB
+ ("", X, 1, "GL_MIN_MAP_BUFFER_ALIGNMENT"), # 0x90BC
+ ("", X, 1, "GL_IMAGE_FORMAT_COMPATIBILITY_TYPE"), # 0x90C7
+ ("", X, 1, "GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE"), # 0x90C8
+ ("", X, 1, "GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS"), # 0x90C9
+ ("", X, 1, "GL_MAX_VERTEX_IMAGE_UNIFORMS"), # 0x90CA
+ ("", X, 1, "GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS"), # 0x90CB
+ ("", X, 1, "GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS"), # 0x90CC
+ ("", X, 1, "GL_MAX_GEOMETRY_IMAGE_UNIFORMS"), # 0x90CD
+ ("", X, 1, "GL_MAX_FRAGMENT_IMAGE_UNIFORMS"), # 0x90CE
+ ("", X, 1, "GL_MAX_COMBINED_IMAGE_UNIFORMS"), # 0x90CF
+ ("", X, 1, "GL_SYNC_X11_FENCE_EXT"), # 0x90E1
("", X, 1, "GL_TEXTURE_2D_MULTISAMPLE"), # 0x9100
("", X, 1, "GL_PROXY_TEXTURE_2D_MULTISAMPLE"), # 0x9101
("", X, 1, "GL_TEXTURE_2D_MULTISAMPLE_ARRAY"), # 0x9102
@@ -2820,6 +2911,20 @@ parameters = [
("", X, 1, "GL_MAX_GEOMETRY_OUTPUT_COMPONENTS"), # 0x9124
("", X, 1, "GL_MAX_FRAGMENT_INPUT_COMPONENTS"), # 0x9125
("glGet", I, 1, "GL_CONTEXT_PROFILE_MASK"), # 0x9126
+ ("", X, 1, "GL_UNPACK_COMPRESSED_BLOCK_WIDTH"), # 0x9127
+ ("", X, 1, "GL_UNPACK_COMPRESSED_BLOCK_HEIGHT"), # 0x9128
+ ("", X, 1, "GL_UNPACK_COMPRESSED_BLOCK_DEPTH"), # 0x9129
+ ("", X, 1, "GL_UNPACK_COMPRESSED_BLOCK_SIZE"), # 0x912A
+ ("", X, 1, "GL_PACK_COMPRESSED_BLOCK_WIDTH"), # 0x912B
+ ("", X, 1, "GL_PACK_COMPRESSED_BLOCK_HEIGHT"), # 0x912C
+ ("", X, 1, "GL_PACK_COMPRESSED_BLOCK_DEPTH"), # 0x912D
+ ("", X, 1, "GL_PACK_COMPRESSED_BLOCK_SIZE"), # 0x912E
+ ("", X, 1, "GL_TEXTURE_IMMUTABLE_FORMAT"), # 0x912F
+ #("", X, 1, "GL_SGX_PROGRAM_BINARY_IMG"), # 0x9130
+ #("", X, 1, "GL_RENDERBUFFER_SAMPLES_IMG"), # 0x9133
+ #("", X, 1, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG"), # 0x9134
+ #("", X, 1, "GL_MAX_SAMPLES_IMG"), # 0x9135
+ #("", X, 1, "GL_TEXTURE_SAMPLES_IMG"), # 0x9136
("", X, 1, "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB"), # 0x9143
("", X, 1, "GL_MAX_DEBUG_LOGGED_MESSAGES_ARB"), # 0x9144
("", X, 1, "GL_DEBUG_LOGGED_MESSAGES_ARB"), # 0x9145
@@ -2839,6 +2944,37 @@ parameters = [
("", X, 1, "GL_QUERY_OBJECT_AMD"), # 0x9153
("", X, 1, "GL_VERTEX_ARRAY_OBJECT_AMD"), # 0x9154
("", X, 1, "GL_SAMPLER_OBJECT_AMD"), # 0x9155
+ #("", X, 1, "GL_SHADER_BINARY_DMP"), # 0x9250
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER"), # 0x92C0
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_BINDING"), # 0x92C1
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_START"), # 0x92C2
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_SIZE"), # 0x92C3
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE"), # 0x92C4
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS"), # 0x92C5
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES"), # 0x92C6
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER"), # 0x92C7
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER"), # 0x92C8
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER"), # 0x92C9
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER"), # 0x92CA
+ ("", X, 1, "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER"), # 0x92CB
+ ("", X, 1, "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS"), # 0x92CC
+ ("", X, 1, "GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS"), # 0x92CD
+ ("", X, 1, "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS"), # 0x92CE
+ ("", X, 1, "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS"), # 0x92CF
+ ("", X, 1, "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS"), # 0x92D0
+ ("", X, 1, "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS"), # 0x92D1
+ ("", X, 1, "GL_MAX_VERTEX_ATOMIC_COUNTERS"), # 0x92D2
+ ("", X, 1, "GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS"), # 0x92D3
+ ("", X, 1, "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS"), # 0x92D4
+ ("", X, 1, "GL_MAX_GEOMETRY_ATOMIC_COUNTERS"), # 0x92D5
+ ("", X, 1, "GL_MAX_FRAGMENT_ATOMIC_COUNTERS"), # 0x92D6
+ ("", X, 1, "GL_MAX_COMBINED_ATOMIC_COUNTERS"), # 0x92D7
+ ("", X, 1, "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE"), # 0x92D8
+ ("", X, 1, "GL_ACTIVE_ATOMIC_COUNTER_BUFFERS"), # 0x92D9
+ ("", X, 1, "GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX"), # 0x92DA
+ ("", X, 1, "GL_UNSIGNED_INT_ATOMIC_COUNTER"), # 0x92DB
+ ("", X, 1, "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS"), # 0x92DC
+ ("", X, 1, "GL_NUM_SAMPLE_COUNTS"), # 0x9380
("", X, 1, "GL_INVALID_INDEX"), # 0xFFFFFFFFu
]
diff --git a/glretrace.hpp b/glretrace.hpp
index 255dd6f..5b93f2d 100644
--- a/glretrace.hpp
+++ b/glretrace.hpp
@@ -69,6 +69,7 @@ void retrace_call_wgl(Trace::Call &call);
void snapshot(unsigned call_no);
void frame_complete(unsigned call_no);
+void updateDrawable(int width, int height);
} /* namespace glretrace */
diff --git a/glretrace.py b/glretrace.py
index 6a5103e..356659a 100644
--- a/glretrace.py
+++ b/glretrace.py
@@ -99,6 +99,11 @@ class GlRetracer(Retracer):
"glMultiModeDrawElementsIBM",
])
+ draw_indirect_function_names = set([
+ "glDrawArraysIndirect",
+ "glDrawElementsIndirect",
+ ])
+
misc_draw_function_names = set([
"glClear",
"glEnd",
@@ -170,6 +175,12 @@ class GlRetracer(Retracer):
print ' GLint __pack_buffer = 0;'
print ' glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
print ' if (!__pack_buffer) {'
+ if function.name == 'glReadPixels':
+ print ' glFinish();'
+ print ' if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
+ print ' glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
+ print ' glretrace::snapshot(call.no);'
+ print ' }'
print ' return;'
print ' }'
@@ -178,6 +189,9 @@ class GlRetracer(Retracer):
print ' if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
print ' glretrace::snapshot(call.no - 1);'
print ' }'
+ if function.name == 'glFrameTerminatorGREMEDY':
+ print ' glretrace::frame_complete(call.no);'
+ return
Retracer.retrace_function_body(self, function)
@@ -186,12 +200,6 @@ class GlRetracer(Retracer):
print ' if (!glretrace::double_buffer) {'
print ' glretrace::frame_complete(call.no);'
print ' }'
- if function.name == 'glReadPixels':
- print ' glFinish();'
- print ' if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
- print ' glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
- print ' glretrace::snapshot(call.no);'
- print ' }'
if is_draw_array or is_draw_elements or is_misc_draw:
print ' if (glretrace::snapshot_frequency == glretrace::FREQUENCY_DRAW) {'
print ' glretrace::snapshot(call.no);'
@@ -199,23 +207,13 @@ class GlRetracer(Retracer):
def call_function(self, function):
+ # Infer the drawable size from GL calls
if function.name == "glViewport":
- print ' GLint draw_framebuffer = 0;'
- print ' glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);'
- print ' if (draw_framebuffer == 0) {'
- print ' if (glretrace::drawable) {'
- print ' int drawable_width = x + width;'
- print ' int drawable_height = y + height;'
- print ' if (drawable_width > (int)glretrace::drawable->width ||'
- print ' drawable_height > (int)glretrace::drawable->height) {'
- print ' glretrace::drawable->resize(drawable_width, drawable_height);'
- print ' if (!glretrace::drawable->visible) {'
- print ' glretrace::drawable->show();'
- print ' }'
- print ' glScissor(0, 0, drawable_width, drawable_height);'
- print ' }'
- print ' }'
- print ' }'
+ print ' glretrace::updateDrawable(x + width, y + height);'
+ if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
+ # Some applications do all their rendering in a framebuffer, and
+ # then just blit to the drawable without ever calling glViewport.
+ print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
if function.name == "glEnd":
print ' glretrace::insideGlBeginEnd = false;'
@@ -290,13 +288,13 @@ class GlRetracer(Retracer):
if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
print r' GLint __orig_result = call.ret->toSInt();'
print r' if (__result != __orig_result) {'
- print r' std::cerr << call.no << ": warning vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
+ print r' std::cerr << call.no << ": warning: vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
print r' }'
if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
print r' GLint __orig_result = call.ret->toSInt();'
print r' if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
print r' __result != GL_FRAMEBUFFER_COMPLETE) {'
- print r' std::cerr << call.no << ": incomplete framebuffer (" << __result << ")\n";'
+ print r' std::cerr << call.no << ": warning: incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
print r' }'
print ' }'
@@ -305,7 +303,8 @@ class GlRetracer(Retracer):
print ' %s = static_cast<%s>(%s.toPointer(true));' % (lvalue, arg_type, rvalue)
return
- if function.name in self.draw_elements_function_names and arg.name == 'indices':
+ if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
+ function.name in self.draw_indirect_function_names and arg.name == 'indirect':
self.extract_opaque_arg(function, arg, arg_type, lvalue, rvalue)
return
@@ -342,6 +341,7 @@ if __name__ == '__main__':
#include "glproc.hpp"
#include "glretrace.hpp"
+#include "glstate.hpp"
'''
diff --git a/glretrace_main.cpp b/glretrace_main.cpp
index 56ee763..cd35889 100644
--- a/glretrace_main.cpp
+++ b/glretrace_main.cpp
@@ -103,6 +103,37 @@ checkGlError(Trace::Call &call) {
std::cerr << "\n";
}
+/**
+ * Grow the current drawble.
+ *
+ * We need to infer the drawable size from GL calls because the drawable sizes
+ * are specified by OS specific calls which we do not trace.
+ */
+void
+updateDrawable(int width, int height) {
+ if (!drawable) {
+ return;
+ }
+
+ if (width <= glretrace::drawable->width &&
+ height <= glretrace::drawable->height) {
+ return;
+ }
+
+ // Check for bound framebuffer last, as this may have a performance impact.
+ GLint draw_framebuffer = 0;
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
+ if (draw_framebuffer != 0) {
+ return;
+ }
+
+ glretrace::drawable->resize(width, height);
+ if (!drawable->visible) {
+ drawable->show();
+ }
+ glScissor(0, 0, width, height);
+}
+
void snapshot(unsigned call_no) {
if (!drawable ||
@@ -131,7 +162,9 @@ void snapshot(unsigned call_no) {
if (snapshot_prefix) {
if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
- src->writePNM(std::cout);
+ char comment[21];
+ snprintf(comment, sizeof comment, "%u", call_no);
+ src->writePNM(std::cout, comment);
} else {
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s%010u.png", snapshot_prefix, call_no);
diff --git a/glsize.hpp b/glsize.hpp
index a58b41e..257d599 100644
--- a/glsize.hpp
+++ b/glsize.hpp
@@ -610,14 +610,18 @@ __gl_format_channels(GLenum format) {
case GL_DEPTH_STENCIL:
case GL_LUMINANCE_ALPHA:
case GL_RG:
+ case GL_HILO_NV:
+ case GL_DSDT_NV:
return 2;
case GL_RGB:
case GL_BGR:
+ case GL_DSDT_MAG_NV:
return 3;
case GL_RGBA:
case GL_BGRA:
case GL_ABGR_EXT:
case GL_CMYK_EXT:
+ case GL_DSDT_MAG_VIB_NV:
return 4;
case GL_CMYKA_EXT:
return 5;
diff --git a/glstate.cpp b/glstate.cpp
index aaf4d4b..ac63a78 100644
--- a/glstate.cpp
+++ b/glstate.cpp
@@ -591,7 +591,7 @@ dumpTextureImage(JSONWriter &json, GLenum target, GLint level)
json.beginMember("__data__");
char *pngBuffer;
int pngBufferSize;
- Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
+ Image::writePixelsToBuffer(pixels, width, height, 4, true, &pngBuffer, &pngBufferSize);
json.writeBase64(pngBuffer, pngBufferSize);
free(pngBuffer);
json.endMember(); // __data__
@@ -949,7 +949,7 @@ dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format)
json.beginMember("__data__");
char *pngBuffer;
int pngBufferSize;
- Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
+ Image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize);
//std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
// <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
json.writeBase64(pngBuffer, pngBufferSize);
diff --git a/glstate.py b/glstate.py
index fb3e090..c348d2b 100644
--- a/glstate.py
+++ b/glstate.py
@@ -380,13 +380,18 @@ class StateDumper:
print ' json.beginMember(name);'
print ' glActiveTexture(GL_TEXTURE0 + unit);'
print ' json.beginObject();'
- print ' GLint texture;'
+ print ' GLboolean enabled;'
+ print ' GLint binding;'
print
for target, binding in texture_targets:
print ' // %s' % target
- print ' texture = 0;'
- print ' glGetIntegerv(%s, &texture);' % binding
- print ' if (glIsEnabled(%s) || texture) {' % target
+ print ' enabled = GL_FALSE;'
+ print ' glGetBooleanv(%s, &enabled);' % target
+ print ' json.writeBoolMember("%s", enabled);' % target
+ print ' binding = 0;'
+ print ' glGetIntegerv(%s, &binding);' % binding
+ print ' json.writeNumberMember("%s", binding);' % binding
+ print ' if (enabled || binding) {'
print ' json.beginMember("%s");' % target
print ' json.beginObject();'
self.dump_atoms(glGetTexParameter, target)
diff --git a/gltypes.py b/gltypes.py
index 32a6ca8..e25cd7e 100644
--- a/gltypes.py
+++ b/gltypes.py
@@ -82,6 +82,7 @@ GLregion = Handle("region", GLuint)
GLmap = Handle("map", OpaquePointer(GLvoid))
GLpipeline = Handle("pipeline", GLuint)
GLsampler = Handle("sampler", GLuint)
+GLfeedback = Handle("feedback", GLuint)
GLsync_ = Opaque("GLsync")
GLsync = Handle("sync", GLsync_)
@@ -182,3 +183,21 @@ GLbitfield_access = Flags(GLbitfield, [
GLbitfield_sync_flush = Flags(GLbitfield, [
"GL_SYNC_FLUSH_COMMANDS_BIT", # 0x00000001
])
+
+GLbitfield_barrier = Flags(GLbitfield, [
+ "GL_ALL_BARRIER_BITS", # 0xFFFFFFFF
+ "GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT", # 0x00000001
+ "GL_ELEMENT_ARRAY_BARRIER_BIT", # 0x00000002
+ "GL_UNIFORM_BARRIER_BIT", # 0x00000004
+ "GL_TEXTURE_FETCH_BARRIER_BIT", # 0x00000008
+ "GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV", # 0x00000010
+ "GL_SHADER_IMAGE_ACCESS_BARRIER_BIT", # 0x00000020
+ "GL_COMMAND_BARRIER_BIT", # 0x00000040
+ "GL_PIXEL_BUFFER_BARRIER_BIT", # 0x00000080
+ "GL_TEXTURE_UPDATE_BARRIER_BIT", # 0x00000100
+ "GL_BUFFER_UPDATE_BARRIER_BIT", # 0x00000200
+ "GL_FRAMEBUFFER_BARRIER_BIT", # 0x00000400
+ "GL_TRANSFORM_FEEDBACK_BARRIER_BIT", # 0x00000800
+ "GL_ATOMIC_COUNTER_BARRIER_BIT", # 0x00001000
+])
+
diff --git a/glxapi.py b/glxapi.py
index 7c389b6..4a35ce1 100644
--- a/glxapi.py
+++ b/glxapi.py
@@ -433,6 +433,10 @@ glxapi.add_functions([
# GLX_NV_copy_image
Function(Void, "glXCopyImageSubDataNV", [(Display, "dpy"), (GLXContext, "srcCtx"), (GLuint, "srcName"), (GLenum, "srcTarget"), (GLint, "srcLevel"), (GLint, "srcX"), (GLint, "srcY"), (GLint, "srcZ"), (GLXContext, "dstCtx"), (GLuint, "dstName"), (GLenum, "dstTarget"), (GLint, "dstLevel"), (GLint, "dstX"), (GLint, "dstY"), (GLint, "dstZ"), (GLsizei, "width"), (GLsizei, "height"), (GLsizei, "depth")]),
+ # GLX_NV_vertex_array_range
+ Function(OpaquePointer(Void), "glXAllocateMemoryNV", [(GLsizei, "size"), (GLfloat, "readfreq"), (GLfloat, "writefreq"), (GLfloat, "priority")]),
+ Function(Void, "glXFreeMemoryNV", [(OpaquePointer(Void), "pointer")]),
+
# Must be last
Function(PROC, "glXGetProcAddressARB", [(Alias("const GLubyte *", CString), "procName")]),
Function(PROC, "glXGetProcAddress", [(Alias("const GLubyte *", CString), "procName")]),
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 6973450..777bc92 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -12,7 +12,6 @@ set(qapitrace_SRCS
glsledit.cpp
imageviewer.cpp
jumpwidget.cpp
- loaderthread.cpp
mainwindow.cpp
main.cpp
retracer.cpp
@@ -21,6 +20,7 @@ set(qapitrace_SRCS
settingsdialog.cpp
shaderssourcewidget.cpp
tracedialog.cpp
+ traceloader.cpp
traceprocess.cpp
vertexdatainterpreter.cpp
)
diff --git a/gui/apicalldelegate.cpp b/gui/apicalldelegate.cpp
index dc9dc94..11ed3a5 100644
--- a/gui/apicalldelegate.cpp
+++ b/gui/apicalldelegate.cpp
@@ -33,7 +33,7 @@ void ApiCallDelegate::paint(QPainter *painter,
//QStyledItemDelegate::paint(painter, option, index);
QStyle *style = QApplication::style();
style->drawControl(QStyle::CE_ItemViewItem, &option, painter, 0);
- if (!event->state().isEmpty()) {
+ if (event->hasState()) {
QPixmap px = m_stateEmblem.pixmap(option.rect.height(),
option.rect.height());
painter->drawPixmap(option.rect.topLeft(), px);
diff --git a/gui/apisurface.cpp b/gui/apisurface.cpp
index 64aa153..050c081 100644
--- a/gui/apisurface.cpp
+++ b/gui/apisurface.cpp
@@ -31,7 +31,6 @@ void ApiSurface::contentsFromBase64(const QByteArray &base64)
{
QByteArray dataArray = QByteArray::fromBase64(base64);
m_image.loadFromData(dataArray, "png");
- m_image = m_image.mirrored();
m_thumb = m_image.scaled(64, 64, Qt::KeepAspectRatio);
}
diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp
index f3b95dc..bc86209 100644
--- a/gui/apitrace.cpp
+++ b/gui/apitrace.cpp
@@ -1,32 +1,75 @@
#include "apitrace.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "saverthread.h"
+#include <QDebug>
#include <QDir>
+#include <QThread>
ApiTrace::ApiTrace()
: m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
m_needsSaving(false)
{
- m_loader = new LoaderThread(this);
- connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
+ m_loader = new TraceLoader();
+
+ connect(this, SIGNAL(loadTrace(QString)),
+ m_loader, SLOT(loadTrace(QString)));
+ connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
+ m_loader, SLOT(loadFrame(ApiTraceFrame*)));
+ connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
- connect(m_loader, SIGNAL(started()),
+ connect(m_loader,
+ SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
+ this,
+ SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
+ connect(m_loader, SIGNAL(finishedParsing()),
+ this, SLOT(finishedParsing()));
+ connect(this, SIGNAL(loaderSearchNext(int,QString,Qt::CaseSensitivity)),
+ m_loader, SLOT(searchNext(int,QString,Qt::CaseSensitivity)));
+ connect(this, SIGNAL(loaderSearchPrev(int,QString,Qt::CaseSensitivity)),
+ m_loader, SLOT(searchPrev(int,QString,Qt::CaseSensitivity)));
+ connect(m_loader,
+ SIGNAL(searchResult(ApiTrace::SearchResult,ApiTraceCall*)),
+ this,
+ SLOT(loaderSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
+ connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
+ m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
+ connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
+ m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
+ connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
+ this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
+ connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
+ this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
+ connect(this, SIGNAL(loaderFindCallIndex(int)),
+ m_loader, SLOT(findCallIndex(int)));
+ connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
+ this, SIGNAL(foundCallIndex(ApiTraceCall*)));
+
+
+ connect(m_loader, SIGNAL(startedParsing()),
this, SIGNAL(startedLoadingTrace()));
- connect(m_loader, SIGNAL(finished()),
+ connect(m_loader, SIGNAL(parsed(int)),
+ this, SIGNAL(loaded(int)));
+ connect(m_loader, SIGNAL(finishedParsing()),
this, SIGNAL(finishedLoadingTrace()));
+
m_saver = new SaverThread(this);
connect(m_saver, SIGNAL(traceSaved()),
this, SLOT(slotSaved()));
connect(m_saver, SIGNAL(traceSaved()),
this, SIGNAL(saved()));
+
+ m_loaderThread = new QThread();
+ m_loader->moveToThread(m_loaderThread);
+ m_loaderThread->start();
}
ApiTrace::~ApiTrace()
{
- qDeleteAll(m_calls);
+ m_loaderThread->quit();
+ m_loaderThread->deleteLater();
qDeleteAll(m_frames);
delete m_loader;
delete m_saver;
@@ -35,8 +78,9 @@ ApiTrace::~ApiTrace()
bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
ApiTrace::FrameMarker marker)
{
- if (!call)
+ if (!call) {
return false;
+ }
switch (marker) {
case FrameMarker_SwapBuffers:
@@ -58,13 +102,14 @@ bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
bool ApiTrace::isEmpty() const
{
- return m_calls.isEmpty();
+ return m_frames.isEmpty();
}
QString ApiTrace::fileName() const
{
- if (edited())
+ if (edited()) {
return m_tempFileName;
+ }
return m_fileName;
}
@@ -74,21 +119,6 @@ ApiTrace::FrameMarker ApiTrace::frameMarker() const
return m_frameMarker;
}
-QList<ApiTraceCall*> ApiTrace::calls() const
-{
- return m_calls;
-}
-
-ApiTraceCall * ApiTrace::callAt(int idx) const
-{
- return m_calls.value(idx);
-}
-
-int ApiTrace::numCalls() const
-{
- return m_calls.count();
-}
-
QList<ApiTraceFrame*> ApiTrace::frames() const
{
return m_frames;
@@ -107,10 +137,11 @@ int ApiTrace::numFrames() const
int ApiTrace::numCallsInFrame(int idx) const
{
const ApiTraceFrame *frame = frameAt(idx);
- if (frame)
+ if (frame) {
return frame->numChildren();
- else
+ } else {
return 0;
+ }
}
void ApiTrace::setFileName(const QString &name)
@@ -118,35 +149,18 @@ void ApiTrace::setFileName(const QString &name)
if (m_fileName != name) {
m_fileName = name;
- if (m_loader->isRunning()) {
- m_loader->terminate();
- m_loader->wait();
- }
m_frames.clear();
- m_calls.clear();
m_errors.clear();
m_editedCalls.clear();
m_needsSaving = false;
emit invalidated();
- m_loader->loadFile(m_fileName);
- }
-}
-
-void ApiTrace::setFrameMarker(FrameMarker marker)
-{
- if (m_frameMarker != marker) {
- emit framesInvalidated();
-
- qDeleteAll(m_frames);
- m_frames.clear();
- detectFrames();
+ emit loadTrace(m_fileName);
}
}
void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
{
- QList<ApiTraceCall*> calls;
int currentFrames = m_frames.count();
int numNewFrames = frames.count();
@@ -154,57 +168,20 @@ void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
m_frames += frames;
- int currentCalls = m_calls.count();
- int numNewCalls = 0;
foreach(ApiTraceFrame *frame, frames) {
- Q_ASSERT(this == frame->parentTrace());
- numNewCalls += frame->numChildren();
- calls += frame->calls();
+ frame->setParentTrace(this);
}
- m_calls.reserve(m_calls.count() + calls.count());
- m_calls += calls;
emit endAddingFrames();
- emit callsAdded(currentCalls, numNewCalls);
-}
-
-void ApiTrace::detectFrames()
-{
- if (m_calls.isEmpty())
- return;
-
- emit beginAddingFrames(0, m_frames.count());
-
- ApiTraceFrame *currentFrame = 0;
- foreach(ApiTraceCall *apiCall, m_calls) {
- if (!currentFrame) {
- currentFrame = new ApiTraceFrame(this);
- currentFrame->number = m_frames.count();
- }
- apiCall->setParentFrame(currentFrame);
- currentFrame->addCall(apiCall);
- if (ApiTrace::isCallAFrameMarker(apiCall,
- m_frameMarker)) {
- m_frames.append(currentFrame);
- currentFrame = 0;
- }
- }
- //last frames won't have markers
- // it's just a bunch of Delete calls for every object
- // after the last SwapBuffers
- if (currentFrame) {
- m_frames.append(currentFrame);
- currentFrame = 0;
- }
- emit endAddingFrames();
}
ApiTraceCall * ApiTrace::callWithIndex(int idx) const
{
- for (int i = 0; i < m_calls.count(); ++i) {
- ApiTraceCall *call = m_calls[i];
- if (call->index() == idx)
+ for (int i = 0; i < m_frames.count(); ++i) {
+ ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
+ if (call) {
return call;
+ }
}
return NULL;
}
@@ -212,10 +189,16 @@ ApiTraceCall * ApiTrace::callWithIndex(int idx) const
ApiTraceState ApiTrace::defaultState() const
{
ApiTraceFrame *frame = frameAt(0);
- if (!frame)
+ if (!frame || !frame->isLoaded() || frame->isEmpty()) {
+ return ApiTraceState();
+ }
+
+ ApiTraceCall *firstCall = frame->calls().first();
+ if (!firstCall->hasState()) {
return ApiTraceState();
+ }
- return frame->state();
+ return *firstCall->state();
}
void ApiTrace::callEdited(ApiTraceCall *call)
@@ -259,7 +242,9 @@ void ApiTrace::save()
QDir dir;
emit startedSaving();
dir.mkpath(fi.absolutePath());
- m_saver->saveFile(m_tempFileName, m_calls);
+ m_saver->saveFile(m_tempFileName,
+ m_fileName,
+ m_editedCalls);
}
void ApiTrace::slotSaved()
@@ -272,31 +257,223 @@ bool ApiTrace::isSaving() const
return m_saver->isRunning();
}
-void ApiTrace::callError(ApiTraceCall *call)
+bool ApiTrace::hasErrors() const
{
- Q_ASSERT(call);
+ return !m_errors.isEmpty();
+}
- if (call->hasError())
- m_errors.insert(call);
- else
- m_errors.remove(call);
+void ApiTrace::loadFrame(ApiTraceFrame *frame)
+{
+ Q_ASSERT(!frame->isLoaded());
+ emit requestFrame(frame);
+}
- emit changed(call);
+void ApiTrace::finishedParsing()
+{
+ ApiTraceFrame *firstFrame = m_frames[0];
+ if (firstFrame && !firstFrame->isLoaded()) {
+ loadFrame(firstFrame);
+ }
}
-bool ApiTrace::hasErrors() const
+void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize)
{
- return !m_errors.isEmpty();
+ Q_ASSERT(frame->numChildrenToLoad() == calls.size());
+ emit beginLoadingFrame(frame, calls.size());
+ frame->setCalls(calls, binaryDataSize);
+ emit endLoadingFrame(frame);
+
+ if (!m_queuedErrors.isEmpty()) {
+ QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
+ for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
+ ++itr) {
+ const ApiTraceError &error = (*itr).second;
+ if ((*itr).first == frame) {
+ ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+
+ if (!call) {
+ continue;
+ }
+
+ call->setError(error.message);
+ m_queuedErrors.erase(itr);
+
+ if (call->hasError()) {
+ m_errors.insert(call);
+ } else {
+ m_errors.remove(call);
+ }
+ emit changed(call);
+ }
+ }
+ }
+}
+
+void ApiTrace::findNext(ApiTraceFrame *frame,
+ ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ ApiTraceCall *foundCall = 0;
+ int frameIdx = m_frames.indexOf(frame);
+
+ if (frame->isLoaded()) {
+ foundCall = frame->findNextCall(from, str, sensitivity);
+ if (foundCall) {
+ emit findResult(SearchResult_Found, foundCall);
+ return;
+ }
+
+ //if the frame is loaded we already searched it above
+ // so skip it
+ frameIdx += 1;
+ }
+
+ for (int i = frameIdx; i < m_frames.count(); ++i) {
+ ApiTraceFrame *frame = m_frames[i];
+ if (!frame->isLoaded()) {
+ emit loaderSearchNext(i, str, sensitivity);
+ return;
+ } else {
+ ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
+ if (call) {
+ emit findResult(SearchResult_Found, call);
+ return;
+ }
+ }
+ }
+ emit findResult(SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::findPrev(ApiTraceFrame *frame,
+ ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ ApiTraceCall *foundCall = 0;
+ int frameIdx = m_frames.indexOf(frame);
+
+ if (frame->isLoaded()) {
+ foundCall = frame->findPrevCall(from, str, sensitivity);
+ if (foundCall) {
+ emit findResult(SearchResult_Found, foundCall);
+ return;
+ }
+
+ //if the frame is loaded we already searched it above
+ // so skip it
+ frameIdx -= 1;
+ }
+
+ for (int i = frameIdx; i >= 0; --i) {
+ ApiTraceFrame *frame = m_frames[i];
+ if (!frame->isLoaded()) {
+ emit loaderSearchPrev(i, str, sensitivity);
+ return;
+ } else {
+ ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
+ if (call) {
+ emit findResult(SearchResult_Found, call);
+ return;
+ }
+ }
+ }
+ emit findResult(SearchResult_Wrapped, 0);
+}
+
+void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
+ ApiTraceCall *call)
+{
+ //qDebug()<<"Search result = "<<result
+ // <<", call is = "<<call;
+ emit findResult(result, call);
+}
+
+void ApiTrace::findFrameStart(ApiTraceFrame *frame)
+{
+ if (frame->isLoaded()) {
+ emit foundFrameStart(frame);
+ } else {
+ emit loaderFindFrameStart(frame);
+ }
+}
+
+void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
+{
+ if (frame->isLoaded()) {
+ emit foundFrameEnd(frame);
+ } else {
+ emit loaderFindFrameEnd(frame);
+ }
+}
+
+void ApiTrace::findCallIndex(int index)
+{
+ int frameIdx = callInFrame(index);
+ ApiTraceFrame *frame = 0;
+
+ if (frameIdx < 0) {
+ emit foundCallIndex(0);
+ return;
+ }
+
+ frame = m_frames[frameIdx];
+
+ if (frame) {
+ if (frame->isLoaded()) {
+ ApiTraceCall *call = frame->callWithIndex(index);
+ emit foundCallIndex(call);
+ } else {
+ emit loaderFindCallIndex(index);
+ }
+ }
}
-ApiTraceCallSignature * ApiTrace::signature(const QString &callName)
+int ApiTrace::callInFrame(int callIdx) const
{
- return m_signatures[callName];
+ unsigned numCalls = 0;
+
+ for (int frameIdx = 0; frameIdx <= m_frames.size(); ++frameIdx) {
+ const ApiTraceFrame *frame = m_frames[frameIdx];
+ unsigned numCallsInFrame = frame->isLoaded()
+ ? frame->numChildren()
+ : frame->numChildrenToLoad();
+ unsigned firstCall = numCalls;
+ unsigned endCall = numCalls + numCallsInFrame;
+ if (firstCall <= callIdx && endCall > callIdx) {
+ return frameIdx;
+ }
+ numCalls = endCall;
+ }
+
+ return -1;
}
-void ApiTrace::addSignature(ApiTraceCallSignature *signature)
+void ApiTrace::setCallError(const ApiTraceError &error)
{
- m_signatures.insert(signature->name(), signature);
+ int frameIdx = callInFrame(error.callIndex);
+ ApiTraceFrame *frame = 0;
+
+ if (frameIdx < 0) {
+ return;
+ }
+ frame = m_frames[frameIdx];
+
+ if (frame->isLoaded()) {
+ ApiTraceCall *call = frame->callWithIndex(error.callIndex);
+ call->setError(error.message);
+ if (call->hasError()) {
+ m_errors.insert(call);
+ } else {
+ m_errors.remove(call);
+ }
+ emit changed(call);
+ } else {
+ emit requestFrame(frame);
+ m_queuedErrors.append(qMakePair(frame, error));
+ }
}
#include "apitrace.moc"
diff --git a/gui/apitrace.h b/gui/apitrace.h
index abcdb01..bf90d17 100644
--- a/gui/apitrace.h
+++ b/gui/apitrace.h
@@ -6,8 +6,9 @@
#include <QObject>
#include <QSet>
-class LoaderThread;
+class TraceLoader;
class SaverThread;
+class QThread;
class ApiTrace : public QObject
{
@@ -19,6 +20,12 @@ public:
FrameMarker_Finish,
FrameMarker_Clear
};
+ enum SearchResult {
+ SearchResult_NotFound,
+ SearchResult_Found,
+ SearchResult_Wrapped
+ };
+
static bool isCallAFrameMarker(const ApiTraceCall *call,
FrameMarker marker);
public:
@@ -33,13 +40,7 @@ public:
ApiTraceState defaultState() const;
- ApiTraceCallSignature *signature(const QString &callName);
- void addSignature(ApiTraceCallSignature *signature);
-
- QList<ApiTraceCall*> calls() const;
- ApiTraceCall *callAt(int idx) const;
ApiTraceCall *callWithIndex(int idx) const;
- int numCalls() const;
QList<ApiTraceFrame*> frames() const;
ApiTraceFrame *frameAt(int idx) const;
@@ -59,37 +60,78 @@ public:
public slots:
void setFileName(const QString &name);
- void setFrameMarker(FrameMarker marker);
void save();
+ void loadFrame(ApiTraceFrame *frame);
+ void findNext(ApiTraceFrame *frame,
+ ApiTraceCall *call,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void findPrev(ApiTraceFrame *frame,
+ ApiTraceCall *call,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void findFrameStart(ApiTraceFrame *frame);
+ void findFrameEnd(ApiTraceFrame *frame);
+ void findCallIndex(int index);
+ void setCallError(const ApiTraceError &error);
+
signals:
+ void loadTrace(const QString &name);
+ void requestFrame(ApiTraceFrame *frame);
void startedLoadingTrace();
+ void loaded(int percent);
void finishedLoadingTrace();
void invalidated();
void framesInvalidated();
void changed(ApiTraceCall *call);
void startedSaving();
void saved();
+ void findResult(ApiTrace::SearchResult result,
+ ApiTraceCall *call);
void beginAddingFrames(int oldCount, int numAdded);
void endAddingFrames();
- void callsAdded(int oldCount, int numAdded);
+ void beginLoadingFrame(ApiTraceFrame *frame, int numAdded);
+ void endLoadingFrame(ApiTraceFrame *frame);
+ void foundFrameStart(ApiTraceFrame *frame);
+ void foundFrameEnd(ApiTraceFrame *frame);
+ void foundCallIndex(ApiTraceCall *call);
+
+signals:
+ void loaderSearchNext(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void loaderSearchPrev(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void loaderFindFrameStart(ApiTraceFrame *frame);
+ void loaderFindFrameEnd(ApiTraceFrame *frame);
+ void loaderFindCallIndex(int index);
private slots:
void addFrames(const QList<ApiTraceFrame*> &frames);
void slotSaved();
+ void finishedParsing();
+ void loaderFrameLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize);
+ void loaderSearchResult(ApiTrace::SearchResult result,
+ ApiTraceCall *call);
+
private:
- void detectFrames();
+ int callInFrame(int callIdx) const;
private:
QString m_fileName;
QString m_tempFileName;
QList<ApiTraceFrame*> m_frames;
- QList<ApiTraceCall*> m_calls;
+ QVector<ApiTraceCall*> m_calls;
FrameMarker m_frameMarker;
- LoaderThread *m_loader;
+ TraceLoader *m_loader;
+ QThread *m_loaderThread;
SaverThread *m_saver;
QSet<ApiTraceCall*> m_editedCalls;
@@ -97,7 +139,7 @@ private:
bool m_needsSaving;
QSet<ApiTraceCall*> m_errors;
- QHash<QString, ApiTraceCallSignature*> m_signatures;
+ QList< QPair<ApiTraceFrame*, ApiTraceError> > m_queuedErrors;
};
#endif
diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp
index 5c7d861..67fc955 100644
--- a/gui/apitracecall.cpp
+++ b/gui/apitracecall.cpp
@@ -1,6 +1,7 @@
#include "apitracecall.h"
#include "apitrace.h"
+#include "traceloader.h"
#include "trace_model.hpp"
#include <QDebug>
@@ -173,10 +174,21 @@ void VariantVisitor::visit(Trace::String *node)
void VariantVisitor::visit(Trace::Enum *e)
{
- QVariant val = QVariant(e->sig->value);
+ ApiTraceEnumSignature *sig = 0;
- m_variant = QVariant::fromValue(
- ApiEnum(QString::fromStdString(e->sig->name), val));
+ if (m_loader) {
+ sig = m_loader->enumSignature(e->sig->id);
+ }
+ if (!sig) {
+ sig = new ApiTraceEnumSignature(
+ QString::fromStdString(e->sig->name),
+ QVariant(e->sig->value));
+ if (m_loader) {
+ m_loader->addEnumSignature(e->sig->id, sig);
+ }
+ }
+
+ m_variant = QVariant::fromValue(ApiEnum(sig));
}
void VariantVisitor::visit(Trace::Bitmask *bitmask)
@@ -204,6 +216,7 @@ void VariantVisitor::visit(Trace::Blob *blob)
// Blob's will start deleting the data we will need to
// start deep copying it or switch to using something like
// Boost's shared_ptr or Qt's QSharedPointer to handle it
+ blob->toPointer(true);
QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
m_variant = QVariant(barray);
}
@@ -214,25 +227,36 @@ void VariantVisitor::visit(Trace::Pointer *ptr)
}
-ApiEnum::ApiEnum(const QString &name, const QVariant &val)
- : m_name(name),
- m_value(val)
+ApiEnum::ApiEnum(ApiTraceEnumSignature *sig)
+ : m_sig(sig)
{
}
QString ApiEnum::toString() const
{
- return m_name;
+ if (m_sig) {
+ return m_sig->name();
+ }
+ Q_ASSERT(!"should never happen");
+ return QString();
}
QVariant ApiEnum::value() const
{
- return m_value;
+ if (m_sig) {
+ return m_sig->value();
+ }
+ Q_ASSERT(!"should never happen");
+ return QVariant();
}
QString ApiEnum::name() const
{
- return m_name;
+ if (m_sig) {
+ return m_sig->name();
+ }
+ Q_ASSERT(!"should never happen");
+ return QString();
}
unsigned long long ApiBitmask::value() const
@@ -353,7 +377,7 @@ void ApiStruct::init(const Trace::Struct *s)
m_sig.name = QString::fromStdString(s->sig->name);
for (unsigned i = 0; i < s->sig->num_members; ++i) {
- VariantVisitor vis;
+ VariantVisitor vis(0);
m_sig.memberNames.append(
QString::fromStdString(s->sig->member_names[i]));
s->members[i]->visit(vis);
@@ -366,12 +390,12 @@ ApiArray::ApiArray(const Trace::Array *arr)
init(arr);
}
-ApiArray::ApiArray(const QList<QVariant> &vals)
+ApiArray::ApiArray(const QVector<QVariant> &vals)
: m_array(vals)
{
}
-QList<QVariant> ApiArray::values() const
+QVector<QVariant> ApiArray::values() const
{
return m_array;
}
@@ -398,11 +422,12 @@ void ApiArray::init(const Trace::Array *arr)
m_array.reserve(arr->values.size());
for (int i = 0; i < arr->values.size(); ++i) {
- VariantVisitor vis;
+ VariantVisitor vis(0);
arr->values[i]->visit(vis);
m_array.append(vis.variant());
}
+ m_array.squeeze();
}
ApiTraceState::ApiTraceState()
@@ -512,6 +537,22 @@ const QList<ApiFramebuffer> & ApiTraceState::framebuffers() const
return m_framebuffers;
}
+ApiFramebuffer ApiTraceState::colorBuffer() const
+{
+ foreach (ApiFramebuffer fbo, m_framebuffers) {
+ if (fbo.type() == QLatin1String("GL_BACK")) {
+ return fbo;
+ }
+ }
+ foreach (ApiFramebuffer fbo, m_framebuffers) {
+ if (fbo.type() == QLatin1String("GL_FRONT")) {
+ return fbo;
+ }
+ }
+ return ApiFramebuffer();
+}
+
+
ApiTraceCallSignature::ApiTraceCallSignature(const QString &name,
const QStringList &argNames)
: m_name(name),
@@ -535,68 +576,75 @@ void ApiTraceCallSignature::setHelpUrl(const QUrl &url)
ApiTraceEvent::ApiTraceEvent()
: m_type(ApiTraceEvent::None),
+ m_hasBinaryData(false),
+ m_binaryDataIndex(0),
+ m_state(0),
m_staticText(0)
{
}
ApiTraceEvent::ApiTraceEvent(Type t)
: m_type(t),
+ m_hasBinaryData(false),
+ m_binaryDataIndex(0),
+ m_state(0),
m_staticText(0)
{
}
ApiTraceEvent::~ApiTraceEvent()
{
+ delete m_state;
delete m_staticText;
}
QVariantMap ApiTraceEvent::stateParameters() const
{
- return m_state.parameters();
+ if (m_state) {
+ return m_state->parameters();
+ } else {
+ return QVariantMap();
+ }
}
-ApiTraceState ApiTraceEvent::state() const
+ApiTraceState *ApiTraceEvent::state() const
{
return m_state;
}
-void ApiTraceEvent::setState(const ApiTraceState &state)
+void ApiTraceEvent::setState(ApiTraceState *state)
{
m_state = state;
}
-ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
+ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
+ TraceLoader *loader,
+ const Trace::Call *call)
: ApiTraceEvent(ApiTraceEvent::Call),
- m_parentFrame(parentFrame),
- m_hasBinaryData(false),
- m_binaryDataIndex(0)
+ m_parentFrame(parentFrame)
{
- ApiTrace *trace = parentTrace();
-
- Q_ASSERT(trace);
-
m_index = call->no;
- QString name = QString::fromStdString(call->sig->name);
- m_signature = trace->signature(name);
+ m_signature = loader->signature(call->sig->id);
if (!m_signature) {
+ QString name = QString::fromStdString(call->sig->name);
QStringList argNames;
argNames.reserve(call->sig->num_args);
for (int i = 0; i < call->sig->num_args; ++i) {
argNames += QString::fromStdString(call->sig->arg_names[i]);
}
m_signature = new ApiTraceCallSignature(name, argNames);
- trace->addSignature(m_signature);
+ loader->addSignature(call->sig->id, m_signature);
}
if (call->ret) {
- VariantVisitor retVisitor;
+ VariantVisitor retVisitor(loader);
call->ret->visit(retVisitor);
m_returnValue = retVisitor.variant();
}
m_argValues.reserve(call->args.size());
for (int i = 0; i < call->args.size(); ++i) {
- VariantVisitor argVisitor;
+ VariantVisitor argVisitor(loader);
call->args[i]->visit(argVisitor);
m_argValues.append(argVisitor.variant());
if (m_argValues[i].type() == QVariant::ByteArray) {
@@ -604,6 +652,7 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
m_binaryDataIndex = i;
}
}
+ m_argValues.squeeze();
}
ApiTraceCall::~ApiTraceCall()
@@ -624,11 +673,8 @@ QString ApiTraceCall::error() const
void ApiTraceCall::setError(const QString &msg)
{
if (m_error != msg) {
- ApiTrace *trace = parentTrace();
m_error = msg;
m_richText = QString();
- if (trace)
- trace->callError(this);
}
}
@@ -639,12 +685,12 @@ ApiTrace * ApiTraceCall::parentTrace() const
return NULL;
}
-QVariantList ApiTraceCall::originalValues() const
+QVector<QVariant> ApiTraceCall::originalValues() const
{
return m_argValues;
}
-void ApiTraceCall::setEditedValues(const QVariantList &lst)
+void ApiTraceCall::setEditedValues(const QVector<QVariant> &lst)
{
ApiTrace *trace = parentTrace();
@@ -664,7 +710,7 @@ void ApiTraceCall::setEditedValues(const QVariantList &lst)
}
}
-QVariantList ApiTraceCall::editedValues() const
+QVector<QVariant> ApiTraceCall::editedValues() const
{
return m_editedValues;
}
@@ -676,7 +722,7 @@ bool ApiTraceCall::edited() const
void ApiTraceCall::revert()
{
- setEditedValues(QVariantList());
+ setEditedValues(QVector<QVariant>());
}
void ApiTraceCall::setHelpUrl(const QUrl &url)
@@ -709,7 +755,7 @@ QStringList ApiTraceCall::argNames() const
return m_signature->argNames();
}
-QVariantList ApiTraceCall::arguments() const
+QVector<QVariant> ApiTraceCall::arguments() const
{
if (m_editedValues.isEmpty())
return m_argValues;
@@ -742,7 +788,7 @@ QStaticText ApiTraceCall::staticText() const
if (m_staticText && !m_staticText->text().isEmpty())
return *m_staticText;
- QVariantList argValues = arguments();
+ QVector<QVariant> argValues = arguments();
QString richText = QString::fromLatin1(
"<span style=\"font-weight:bold\">%1</span>(").arg(
@@ -811,7 +857,7 @@ QString ApiTraceCall::toHtml() const
.arg(m_signature->name());
}
- QVariantList argValues = arguments();
+ QVector<QVariant> argValues = arguments();
QStringList argNames = m_signature->argNames();
for (int i = 0; i < argNames.count(); ++i) {
m_richText +=
@@ -861,7 +907,7 @@ QString ApiTraceCall::searchText() const
if (!m_searchText.isEmpty())
return m_searchText;
- QVariantList argValues = arguments();
+ QVector<QVariant> argValues = arguments();
m_searchText = m_signature->name() + QLatin1Literal("(");
QStringList argNames = m_signature->argNames();
for (int i = 0; i < argNames.count(); ++i) {
@@ -886,11 +932,27 @@ int ApiTraceCall::numChildren() const
return 0;
}
+bool ApiTraceCall::contains(const QString &str,
+ Qt::CaseSensitivity sensitivity) const
+{
+ QString txt = searchText();
+ return txt.contains(str, sensitivity);
+}
+
+
ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
: ApiTraceEvent(ApiTraceEvent::Frame),
m_parentTrace(parentTrace),
- m_binaryDataSize(0)
+ m_binaryDataSize(0),
+ m_loaded(false),
+ m_callsToLoad(0),
+ m_lastCallIndex(0)
+{
+}
+
+ApiTraceFrame::~ApiTraceFrame()
{
+ qDeleteAll(m_calls);
}
QStaticText ApiTraceFrame::staticText() const
@@ -898,23 +960,23 @@ QStaticText ApiTraceFrame::staticText() const
if (m_staticText && !m_staticText->text().isEmpty())
return *m_staticText;
- QString richText;
+ QString richText = QObject::tr(
+ "<span style=\"font-weight:bold\">Frame %1</span>"
+ "&nbsp;&nbsp;&nbsp;"
+ "<span style=\"font-style:italic;font-size:small;font-weight:lighter;\"> "
+ "(%2 calls)</span>")
+ .arg(number)
+ .arg(m_loaded ? m_calls.count() : m_callsToLoad);
//mark the frame if it uploads more than a meg a frame
if (m_binaryDataSize > (1024*1024)) {
richText =
QObject::tr(
- "<span style=\"font-weight:bold;\">"
- "Frame&nbsp;%1</span>"
+ "%1"
"<span style=\"font-style:italic;\">"
"&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
- .arg(number)
+ .arg(richText)
.arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
- } else {
- richText =
- QObject::tr(
- "<span style=\"font-weight:bold\">Frame %1</span>")
- .arg(number);
}
if (!m_staticText)
@@ -948,7 +1010,7 @@ void ApiTraceFrame::addCall(ApiTraceCall *call)
}
}
-QList<ApiTraceCall*> ApiTraceFrame::calls() const
+QVector<ApiTraceCall*> ApiTraceFrame::calls() const
{
return m_calls;
}
@@ -958,6 +1020,18 @@ ApiTraceCall * ApiTraceFrame::call(int idx) const
return m_calls.value(idx);
}
+
+ApiTraceCall * ApiTraceFrame::callWithIndex(int index) const
+{
+ QVector<ApiTraceCall*>::const_iterator itr;
+ for (itr = m_calls.constBegin(); itr != m_calls.constEnd(); ++itr) {
+ if ((*itr)->index() == index) {
+ return *itr;
+ }
+ }
+ return 0;
+}
+
int ApiTraceFrame::callIndex(ApiTraceCall *call) const
{
return m_calls.indexOf(call);
@@ -965,10 +1039,107 @@ int ApiTraceFrame::callIndex(ApiTraceCall *call) const
bool ApiTraceFrame::isEmpty() const
{
- return m_calls.isEmpty();
+ if (m_loaded) {
+ return m_calls.isEmpty();
+ } else {
+ return m_callsToLoad == 0;
+ }
}
int ApiTraceFrame::binaryDataSize() const
{
return m_binaryDataSize;
}
+
+void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize)
+{
+ m_calls = calls;
+ m_binaryDataSize = binaryDataSize;
+ m_loaded = true;
+ delete m_staticText;
+ m_staticText = 0;
+}
+
+bool ApiTraceFrame::isLoaded() const
+{
+ return m_loaded;
+}
+
+void ApiTraceFrame::setLoaded(bool l)
+{
+ m_loaded = l;
+}
+
+void ApiTraceFrame::setNumChildren(int num)
+{
+ m_callsToLoad = num;
+}
+
+void ApiTraceFrame::setParentTrace(ApiTrace *parent)
+{
+ m_parentTrace = parent;
+}
+
+int ApiTraceFrame::numChildrenToLoad() const
+{
+ return m_callsToLoad;
+}
+
+ApiTraceCall *
+ApiTraceFrame::findNextCall(ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity) const
+{
+ Q_ASSERT(m_loaded);
+
+ int callIndex = 0;
+
+ if (from) {
+ callIndex = m_calls.indexOf(from) + 1;
+ }
+
+ for (int i = callIndex; i < m_calls.count(); ++i) {
+ ApiTraceCall *call = m_calls[i];
+ if (call->contains(str, sensitivity)) {
+ return call;
+ }
+ }
+ return 0;
+}
+
+ApiTraceCall *
+ApiTraceFrame::findPrevCall(ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity) const
+{
+ Q_ASSERT(m_loaded);
+
+ int callIndex = m_calls.count() - 1;
+
+ if (from) {
+ callIndex = m_calls.indexOf(from) - 1;
+ }
+
+ for (int i = callIndex; i >= 0; --i) {
+ ApiTraceCall *call = m_calls[i];
+ if (call->contains(str, sensitivity)) {
+ return call;
+ }
+ }
+ return 0;
+}
+
+void ApiTraceFrame::setLastCallIndex(unsigned index)
+{
+ m_lastCallIndex = index;
+}
+
+unsigned ApiTraceFrame::lastCallIndex() const
+{
+ if (m_loaded && !m_calls.isEmpty()) {
+ return m_calls.last()->index();
+ } else {
+ return m_lastCallIndex;
+ }
+}
diff --git a/gui/apitracecall.h b/gui/apitracecall.h
index 89f3102..12b0216 100644
--- a/gui/apitracecall.h
+++ b/gui/apitracecall.h
@@ -12,10 +12,14 @@
class ApiTrace;
+class TraceLoader;
class VariantVisitor : public Trace::Visitor
{
public:
+ VariantVisitor(TraceLoader *loader)
+ : m_loader(loader)
+ {}
virtual void visit(Trace::Null *);
virtual void visit(Trace::Bool *node);
virtual void visit(Trace::SInt *node);
@@ -34,21 +38,45 @@ public:
return m_variant;
}
private:
+ TraceLoader *m_loader;
QVariant m_variant;
};
+
+struct ApiTraceError
+{
+ int callIndex;
+ QString type;
+ QString message;
+};
+
+class ApiTraceEnumSignature
+{
+public:
+ ApiTraceEnumSignature(const QString &name = QString(),
+ const QVariant &val=QVariant())\
+ : m_name(name),
+ m_value(val)
+ {}
+
+ QVariant value() const { return m_value; }
+ QString name() const { return m_name; }
+private:
+ QString m_name;
+ QVariant m_value;
+};
+
class ApiEnum
{
public:
- ApiEnum(const QString &name = QString(), const QVariant &val=QVariant());
+ ApiEnum(ApiTraceEnumSignature *sig=0);
QString toString() const;
QVariant value() const;
QString name() const;
private:
- QString m_name;
- QVariant m_value;
+ ApiTraceEnumSignature *m_sig;
};
Q_DECLARE_METATYPE(ApiEnum);
@@ -112,15 +140,15 @@ class ApiArray
{
public:
ApiArray(const Trace::Array *arr = 0);
- ApiArray(const QList<QVariant> &vals);
+ ApiArray(const QVector<QVariant> &vals);
QString toString() const;
- QList<QVariant> values() const;
+ QVector<QVariant> values() const;
private:
void init(const Trace::Array *arr);
private:
- QList<QVariant> m_array;
+ QVector<QVariant> m_array;
};
Q_DECLARE_METATYPE(ApiArray);
@@ -141,6 +169,7 @@ public:
const QList<ApiTexture> & textures() const;
const QList<ApiFramebuffer> & framebuffers() const;
+ ApiFramebuffer colorBuffer() const;
private:
QVariantMap m_parameters;
QMap<QString, QString> m_shaderSources;
@@ -179,27 +208,33 @@ class ApiTraceEvent
{
public:
enum Type {
- None,
- Call,
- Frame
+ None = 0,
+ Call = 1 << 0,
+ Frame = 1 << 1
};
public:
ApiTraceEvent();
ApiTraceEvent(Type t);
virtual ~ApiTraceEvent();
- Type type() const { return m_type; }
+ Type type() const { return (Type)m_type; }
virtual QStaticText staticText() const = 0;
virtual int numChildren() const = 0;
QVariantMap stateParameters() const;
- ApiTraceState state() const;
- void setState(const ApiTraceState &state);
+ ApiTraceState *state() const;
+ void setState(ApiTraceState *state);
+ bool hasState() const
+ {
+ return m_state && !m_state->isEmpty();
+ }
protected:
- Type m_type;
- ApiTraceState m_state;
+ int m_type : 4;
+ mutable bool m_hasBinaryData;
+ mutable int m_binaryDataIndex:8;
+ ApiTraceState *m_state;
mutable QStaticText *m_staticText;
};
@@ -208,13 +243,14 @@ Q_DECLARE_METATYPE(ApiTraceEvent*);
class ApiTraceCall : public ApiTraceEvent
{
public:
- ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *tcall);
+ ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader,
+ const Trace::Call *tcall);
~ApiTraceCall();
int index() const;
QString name() const;
QStringList argNames() const;
- QVariantList arguments() const;
+ QVector<QVariant> arguments() const;
QVariant returnValue() const;
QUrl helpUrl() const;
void setHelpUrl(const QUrl &url);
@@ -225,13 +261,16 @@ public:
QString error() const;
void setError(const QString &msg);
- QVariantList originalValues() const;
+ QVector<QVariant> originalValues() const;
bool edited() const;
- void setEditedValues(const QVariantList &lst);
- QVariantList editedValues() const;
+ void setEditedValues(const QVector<QVariant> &lst);
+ QVector<QVariant> editedValues() const;
void revert();
+ bool contains(const QString &str,
+ Qt::CaseSensitivity sensitivity) const;
+
ApiTrace *parentTrace() const;
QString toHtml() const;
@@ -243,44 +282,66 @@ public:
private:
int m_index;
ApiTraceCallSignature *m_signature;
- QVariantList m_argValues;
+ QVector<QVariant> m_argValues;
QVariant m_returnValue;
ApiTraceFrame *m_parentFrame;
- QVariantList m_editedValues;
+ QVector<QVariant> m_editedValues;
QString m_error;
mutable QString m_richText;
mutable QString m_searchText;
- mutable bool m_hasBinaryData;
- mutable int m_binaryDataIndex;
};
Q_DECLARE_METATYPE(ApiTraceCall*);
class ApiTraceFrame : public ApiTraceEvent
{
public:
- ApiTraceFrame(ApiTrace *parent);
+ ApiTraceFrame(ApiTrace *parent=0);
+ ~ApiTraceFrame();
int number;
bool isEmpty() const;
+ void setParentTrace(ApiTrace *parent);
ApiTrace *parentTrace() const;
+ void setNumChildren(int num);
int numChildren() const;
+ int numChildrenToLoad() const;
QStaticText staticText() const;
int callIndex(ApiTraceCall *call) const;
ApiTraceCall *call(int idx) const;
+ ApiTraceCall *callWithIndex(int index) const;
void addCall(ApiTraceCall *call);
- QList<ApiTraceCall*> calls() const;
+ QVector<ApiTraceCall*> calls() const;
+ void setCalls(const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize);
+
+ ApiTraceCall *findNextCall(ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity) const;
+
+ ApiTraceCall *findPrevCall(ApiTraceCall *from,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity) const;
int binaryDataSize() const;
+
+ bool isLoaded() const;
+ void setLoaded(bool l);
+
+ void setLastCallIndex(unsigned index);
+ unsigned lastCallIndex() const;
private:
ApiTrace *m_parentTrace;
quint64 m_binaryDataSize;
- QList<ApiTraceCall*> m_calls;
+ QVector<ApiTraceCall*> m_calls;
+ bool m_loaded;
+ unsigned m_callsToLoad;
+ unsigned m_lastCallIndex;
};
Q_DECLARE_METATYPE(ApiTraceFrame*);
diff --git a/gui/apitracefilter.cpp b/gui/apitracefilter.cpp
index 2bf7bf8..cfa930d 100644
--- a/gui/apitracefilter.cpp
+++ b/gui/apitracefilter.cpp
@@ -89,12 +89,6 @@ void ApiTraceFilter::setFilterOptions(ApiTraceFilter::FilterOptions opts)
}
}
-QModelIndex ApiTraceFilter::callIndex(int callIdx) const
-{
- ApiTraceModel *model = static_cast<ApiTraceModel *>(sourceModel());
- QModelIndex index = model->callIndex(callIdx);
- return mapFromSource(index);
-}
QModelIndex ApiTraceFilter::indexForCall(ApiTraceCall *call) const
{
diff --git a/gui/apitracefilter.h b/gui/apitracefilter.h
index 217938c..30c92a1 100644
--- a/gui/apitracefilter.h
+++ b/gui/apitracefilter.h
@@ -27,7 +27,6 @@ public:
void setFilterRegexp(const QRegExp &regexp);
QRegExp filterRegexp() const;
- QModelIndex callIndex(int callNum) const;
QModelIndex indexForCall(ApiTraceCall *call) const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
diff --git a/gui/apitracemodel.cpp b/gui/apitracemodel.cpp
index e60b176..7303ae1 100644
--- a/gui/apitracemodel.cpp
+++ b/gui/apitracemodel.cpp
@@ -1,9 +1,10 @@
#include "apitracemodel.h"
#include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "trace_parser.hpp"
+#include <QBuffer>
#include <QDebug>
#include <QImage>
#include <QVariant>
@@ -42,7 +43,7 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
const QString stateText = tr("State info available.");
if (itm->type() == ApiTraceEvent::Call) {
ApiTraceCall *call = static_cast<ApiTraceCall*>(itm);
- if (call->state().isEmpty())
+ if (!call->hasState())
return QString::fromLatin1("%1)&nbsp;<b>%2</b>")
.arg(call->index())
.arg(call->name());
@@ -52,22 +53,53 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
.arg(call->name())
.arg(stateText);
} else {
+ const char *htmlTempl =
+ "<div>\n"
+ "<div>\n"
+ "%1"
+ "<span style=\"font-weight:bold; font-size:large; vertical-align:center; padding-bottom: 30px \">\n"
+ "Frame %2</span>\n"
+ "</div>\n"
+ "<div >%3 calls%4</div>\n"
+ "</div>\n";
+
+
ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(itm);
- QString text = QObject::tr("%1)&nbsp;Frame&nbsp;")
- .arg(frame->number);
- int binaryDataSize = frame->binaryDataSize() / 1024;
- if (frame->state().isEmpty())
- return QObject::tr(
- "<b>%1&nbsp;</b>(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)")
- .arg(text)
- .arg(binaryDataSize);
- else
- return QObject::tr(
- "<b>%1&nbsp;(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)</b>"
- "<br/>%3")
- .arg(text)
- .arg(binaryDataSize)
- .arg(stateText);
+ QString thumbStr, sizeStr;
+
+ if (frame->hasState()) {
+ static const char *imgTempl =
+ "<img style=\"float:left;\" "
+ "src=\"data:image/png;base64,%1\"/>\n";
+ static const char *sizeTempl =
+ ", %1kb";
+
+ ApiFramebuffer fbo = frame->state()->colorBuffer();
+ QImage thumb = fbo.thumb();
+ if (!thumb.isNull()) {
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ thumb.save(&buffer, "PNG");
+ thumbStr = tr(imgTempl).arg(
+ QString(buffer.data().toBase64()));
+ }
+
+ int binaryDataSize = frame->binaryDataSize() / 1024;
+ if (binaryDataSize > 0) {
+ sizeStr = tr(sizeTempl).arg(binaryDataSize);
+ }
+ }
+
+ int numCalls = frame->isLoaded()
+ ? frame->numChildren()
+ : frame->numChildrenToLoad();
+
+ return tr(htmlTempl)
+ .arg(thumbStr)
+ .arg(frame->number)
+ .arg(numCalls)
+ .arg(sizeStr);
}
}
case ApiTraceModel::EventRole:
@@ -218,6 +250,11 @@ void ApiTraceModel::setApiTrace(ApiTrace *trace)
this, SLOT(endAddingFrames()));
connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
this, SLOT(callChanged(ApiTraceCall*)));
+ connect(m_trace, SIGNAL(beginLoadingFrame(ApiTraceFrame*,int)),
+ this, SLOT(beginLoadingFrame(ApiTraceFrame*,int)));
+ connect(m_trace, SIGNAL(endLoadingFrame(ApiTraceFrame*)),
+ this, SLOT(endLoadingFrame(ApiTraceFrame*)));
+
}
const ApiTrace * ApiTraceModel::apiTrace() const
@@ -264,12 +301,6 @@ void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event)
}
}
-QModelIndex ApiTraceModel::callIndex(int callNum) const
-{
- ApiTraceCall *call = m_trace->callWithIndex(callNum);
- return indexForCall(call);
-}
-
QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const
{
if (!call) {
@@ -313,4 +344,58 @@ void ApiTraceModel::endAddingFrames()
endInsertRows();
}
+bool ApiTraceModel::canFetchMore(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ ApiTraceEvent *event = item(parent);
+ if (event && event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ return !frame->isLoaded() && !m_loadingFrames.contains(frame);
+ } else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+void ApiTraceModel::fetchMore(const QModelIndex &parent)
+{
+ if (parent.isValid()) {
+ ApiTraceEvent *event = item(parent);
+ if (event && event->type() == ApiTraceEvent::Frame) {
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ QModelIndex index = createIndex(frame->number, 0, frame);
+
+ Q_ASSERT(!frame->isLoaded());
+ m_loadingFrames.insert(frame);
+
+ m_trace->loadFrame(frame);
+ }
+ }
+}
+
+void ApiTraceModel::beginLoadingFrame(ApiTraceFrame *frame, int numAdded)
+{
+ QModelIndex index = createIndex(frame->number, 0, frame);
+ beginInsertRows(index, 0, numAdded - 1);
+}
+
+void ApiTraceModel::endLoadingFrame(ApiTraceFrame *frame)
+{
+ QModelIndex index = createIndex(frame->number, 0, frame);
+#if 0
+ qDebug()<<"Frame loaded = "<<frame->loaded();
+ qDebug()<<"\tframe idx = "<<frame->number;
+ qDebug()<<"\tis empty = "<<frame->isEmpty();
+ qDebug()<<"\tnum children = "<<frame->numChildren();
+ qDebug()<<"\tindex is "<<index;
+#endif
+
+ endInsertRows();
+
+ emit dataChanged(index, index);
+
+ m_loadingFrames.remove(frame);
+}
+
#include "apitracemodel.moc"
diff --git a/gui/apitracemodel.h b/gui/apitracemodel.h
index 2cdd7d0..fe6b5ce 100644
--- a/gui/apitracemodel.h
+++ b/gui/apitracemodel.h
@@ -4,11 +4,13 @@
#include <QAbstractItemModel>
#include <QModelIndex>
+#include <QSet>
#include <QVariant>
class ApiTrace;
class ApiTraceCall;
class ApiTraceEvent;
+class ApiTraceFrame;
class ApiTraceModel : public QAbstractItemModel
{
@@ -25,7 +27,6 @@ public:
const ApiTrace *apiTrace() const;
void stateSetOnEvent(ApiTraceEvent *event);
- QModelIndex callIndex(int callNum) const;
QModelIndex indexForCall(ApiTraceCall *call) const;
public:
@@ -45,6 +46,8 @@ public:
const QModelIndex &parent = QModelIndex());
bool removeRows(int position, int rows,
const QModelIndex &parent = QModelIndex());
+ virtual bool canFetchMore(const QModelIndex & parent) const;
+ virtual void fetchMore(const QModelIndex &parent);
/* } QAbstractItemModel; */
private slots:
@@ -52,12 +55,15 @@ private slots:
void beginAddingFrames(int oldCount, int numAdded);
void endAddingFrames();
void callChanged(ApiTraceCall *call);
+ void beginLoadingFrame(ApiTraceFrame *frame, int numAdded);
+ void endLoadingFrame(ApiTraceFrame *frame);
private:
ApiTraceEvent *item(const QModelIndex &index) const;
private:
ApiTrace *m_trace;
+ QSet<ApiTraceFrame*> m_loadingFrames;
};
#endif
diff --git a/gui/argumentseditor.cpp b/gui/argumentseditor.cpp
index 8848122..1ee519e 100644
--- a/gui/argumentseditor.cpp
+++ b/gui/argumentseditor.cpp
@@ -16,7 +16,7 @@ isVariantEditable(const QVariant &var)
{
if (var.canConvert<ApiArray>()) {
ApiArray array = var.value<ApiArray>();
- QList<QVariant> vals = array.values();
+ QVector<QVariant> vals = array.values();
if (vals.isEmpty())
return false;
else
@@ -42,7 +42,7 @@ isVariantStringArray(const QVariant &var)
return false;
ApiArray array = var.value<ApiArray>();
- QList<QVariant> origValues = array.values();
+ QVector<QVariant> origValues = array.values();
if (origValues.isEmpty() ||
origValues.first().userType() != QVariant::String)
return false;
@@ -210,7 +210,7 @@ void ArgumentsEditor::setupCall()
if (val.canConvert<ApiArray>()) {
ApiArray array = val.value<ApiArray>();
- QList<QVariant> vals = array.values();
+ QVector<QVariant> vals = array.values();
QVariant firstVal = vals.value(0);
if (firstVal.userType() == QVariant::String) {
@@ -304,7 +304,7 @@ void ArgumentsEditor::setupCall()
}
}
-void ArgumentsEditor::setupShaderEditor(const QList<QVariant> &sources)
+void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources)
{
m_ui.selectStringCB->clear();
m_ui.glslEdit->clear();
@@ -339,8 +339,8 @@ void ArgumentsEditor::sourceChanged()
void ArgumentsEditor::accept()
{
QStringList argNames = m_call->argNames();
- QList<QVariant> originalValues = m_call->arguments();
- QList<QVariant> newValues;
+ QVector<QVariant> originalValues = m_call->arguments();
+ QVector<QVariant> newValues;
bool changed = false;
for (int i = 0; i < argNames.count(); ++i) {
bool valChanged = false;
@@ -405,14 +405,14 @@ QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
const ApiArray &origArray,
bool *changed) const
{
- QList<QVariant> origValues = origArray.values();
+ QVector<QVariant> origValues = origArray.values();
*changed = false;
if (origValues.isEmpty())
return QVariant::fromValue(ApiArray());
- QList<QVariant> lst;
+ QVector<QVariant> lst;
for (int i = 0; i < origValues.count(); ++i) {
QModelIndex valIdx = m_model->index(i, 1, parentIndex);
QVariant var = valIdx.data();
@@ -428,8 +428,8 @@ QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
QVariant ArgumentsEditor::arrayFromEditor(const ApiArray &origArray,
bool *changed) const
{
- QList<QVariant> vals;
- QList<QVariant> origValues = origArray.values();
+ QVector<QVariant> vals;
+ QVector<QVariant> origValues = origArray.values();
Q_ASSERT(isVariantStringArray(QVariant::fromValue(origArray)));
*changed = false;
diff --git a/gui/argumentseditor.h b/gui/argumentseditor.h
index e6b3d8f..7671d71 100644
--- a/gui/argumentseditor.h
+++ b/gui/argumentseditor.h
@@ -49,7 +49,7 @@ private slots:
private:
void init();
void setupCall();
- void setupShaderEditor(const QList<QVariant> &sources);
+ void setupShaderEditor(const QVector<QVariant> &sources);
QVariant valueForName(const QString &name,
const QVariant &orignalValue,
bool *changed) const;
diff --git a/gui/loaderthread.cpp b/gui/loaderthread.cpp
deleted file mode 100644
index 0545453..0000000
--- a/gui/loaderthread.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-#include "loaderthread.h"
-
-#include "trace_parser.hpp"
-
-#include <QFile>
-#include <QHash>
-#include <QUrl>
-
-#include <QDebug>
-
-#define FRAMES_TO_CACHE 100
-
-static ApiTraceCall *
-apiCallFromTraceCall(const Trace::Call *call,
- const QHash<QString, QUrl> &helpHash,
- ApiTraceFrame *frame)
-{
- ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
-
- apiCall->setHelpUrl(helpHash.value(apiCall->name()));
-
- return apiCall;
-}
-
-LoaderThread::LoaderThread(ApiTrace *parent)
- : QThread(parent),
- m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
- m_trace(parent)
-{
-}
-
-void LoaderThread::run()
-{
- QList<ApiTraceFrame*> frames;
- ApiTraceFrame *currentFrame = 0;
- int frameCount = 0;
-
- QHash<QString, QUrl> helpHash;
-
-
- QFile file(":/resources/glreference.tsv");
- if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QString line;
- while (!file.atEnd()) {
- line = file.readLine();
- QString function = line.section('\t', 0, 0).trimmed();
- QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
- //qDebug()<<"function = "<<function<<", url = "<<url.toString();
- helpHash.insert(function, url);
- }
- } else {
- qWarning() << "Couldn't open reference file "
- << file.fileName();
- }
- file.close();
-
- Trace::Parser p;
- if (p.open(m_fileName.toLatin1().constData())) {
- Trace::Call *call = p.parse_call();
- while (call) {
- //std::cout << *call;
- if (!currentFrame) {
- currentFrame = new ApiTraceFrame(m_trace);
- currentFrame->number = frameCount;
- ++frameCount;
- }
- ApiTraceCall *apiCall =
- apiCallFromTraceCall(call, helpHash, currentFrame);
- currentFrame->addCall(apiCall);
- if (ApiTrace::isCallAFrameMarker(apiCall,
- m_frameMarker)) {
- frames.append(currentFrame);
- currentFrame = 0;
- if (frames.count() >= FRAMES_TO_CACHE) {
- emit parsedFrames(frames);
- frames.clear();
- }
- }
- delete call;
- call = p.parse_call();
- }
- }
- //last frames won't have markers
- // it's just a bunch of Delete calls for every object
- // after the last SwapBuffers
- if (currentFrame) {
- frames.append(currentFrame);
- currentFrame = 0;
- }
- if (frames.count()) {
- emit parsedFrames(frames);
- }
-}
-
-void LoaderThread::loadFile(const QString &fileName)
-{
- m_fileName = fileName;
- start();
-}
-
-ApiTrace::FrameMarker LoaderThread::frameMarker() const
-{
- return m_frameMarker;
-}
-
-void LoaderThread::setFrameMarker(ApiTrace::FrameMarker marker)
-{
- Q_ASSERT(!isRunning());
- m_frameMarker = marker;
-}
-
-#include "loaderthread.moc"
diff --git a/gui/loaderthread.h b/gui/loaderthread.h
deleted file mode 100644
index c847c73..0000000
--- a/gui/loaderthread.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef LOADERTHREAD_H
-#define LOADERTHREAD_H
-
-#include "apitrace.h"
-#include <QThread>
-#include <QList>
-
-class ApiTraceCall;
-class ApiTraceFrame;
-
-class LoaderThread : public QThread
-{
- Q_OBJECT
-public:
- LoaderThread(ApiTrace *parent);
-
- ApiTrace::FrameMarker frameMarker() const;
- void setFrameMarker(ApiTrace::FrameMarker marker);
-public slots:
- void loadFile(const QString &fileName);
-
-signals:
- void parsedFrames(const QList<ApiTraceFrame*> &frames);
-
-protected:
- virtual void run();
-
-private:
- QString m_fileName;
- ApiTrace::FrameMarker m_frameMarker;
- ApiTrace *m_trace;
-};
-
-#endif
diff --git a/gui/main.cpp b/gui/main.cpp
index 3f8cfa6..6043b75 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -1,5 +1,6 @@
#include "mainwindow.h"
+#include "apitrace.h"
#include "apitracecall.h"
#include <QApplication>
@@ -7,13 +8,20 @@
#include <QVariant>
Q_DECLARE_METATYPE(QList<ApiTraceFrame*>);
+Q_DECLARE_METATYPE(QVector<ApiTraceCall*>);
+Q_DECLARE_METATYPE(Qt::CaseSensitivity);
+Q_DECLARE_METATYPE(ApiTrace::SearchResult);
+
int main(int argc, char **argv)
{
QApplication app(argc, argv);
qRegisterMetaType<QList<ApiTraceFrame*> >();
+ qRegisterMetaType<QVector<ApiTraceCall*> >();
qRegisterMetaType<ApiTraceState>();
+ qRegisterMetaType<Qt::CaseSensitivity>();
+ qRegisterMetaType<ApiTrace::SearchResult>();
MainWindow window;
window.show();
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index ba19b4d..8d7af8a 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -47,8 +47,6 @@ MainWindow::MainWindow()
void MainWindow::createTrace()
{
- TraceDialog dialog;
-
if (!m_traceProcess->canTrace()) {
QMessageBox::warning(
this,
@@ -57,6 +55,7 @@ void MainWindow::createTrace()
return;
}
+ TraceDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
qDebug()<< "App : " <<dialog.applicationPath();
qDebug()<< " Arguments: "<<dialog.arguments();
@@ -69,11 +68,11 @@ void MainWindow::createTrace()
void MainWindow::openTrace()
{
QString fileName =
- QFileDialog::getOpenFileName(
- this,
- tr("Open Trace"),
- QDir::homePath(),
- tr("Trace Files (*.trace)"));
+ QFileDialog::getOpenFileName(
+ this,
+ tr("Open Trace"),
+ QDir::homePath(),
+ tr("Trace Files (*.trace)"));
if (!fileName.isEmpty() && QFile::exists(fileName)) {
newTraceFile(fileName);
@@ -104,8 +103,8 @@ void MainWindow::callItemSelected(const QModelIndex &index)
QByteArray data =
call->arguments()[call->binaryDataIndex()].toByteArray();
m_vdataInterpreter->setData(data);
- QVariantList args = call->arguments();
+ QVector<QVariant> args = call->arguments();
for (int i = 0; i < call->argNames().count(); ++i) {
QString name = call->argNames()[i];
if (name == QLatin1String("stride")) {
@@ -117,8 +116,9 @@ void MainWindow::callItemSelected(const QModelIndex &index)
} else if (name == QLatin1String("type")) {
QString val = args[i].toString();
int textIndex = m_ui.vertexTypeCB->findText(val);
- if (textIndex >= 0)
+ if (textIndex >= 0) {
m_ui.vertexTypeCB->setCurrentIndex(textIndex);
+ }
}
}
}
@@ -127,15 +127,17 @@ void MainWindow::callItemSelected(const QModelIndex &index)
} else {
if (event && event->type() == ApiTraceEvent::Frame) {
m_selectedEvent = static_cast<ApiTraceFrame*>(event);
- } else
+ } else {
m_selectedEvent = 0;
+ }
m_ui.detailsDock->hide();
m_ui.vertexDataDock->hide();
}
- if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
+ if (m_selectedEvent && m_selectedEvent->hasState()) {
fillStateForFrame();
- } else
+ } else {
m_ui.stateDock->hide();
+ }
}
void MainWindow::replayStart()
@@ -207,8 +209,9 @@ void MainWindow::replayFinished(const QString &output)
m_stateEvent = 0;
m_ui.actionShowErrorsDock->setEnabled(m_trace->hasErrors());
m_ui.errorsDock->setVisible(m_trace->hasErrors());
- if (!m_trace->hasErrors())
+ if (!m_trace->hasErrors()) {
m_ui.errorsTreeWidget->clear();
+ }
statusBar()->showMessage(
tr("Replaying finished!"), 2000);
@@ -251,8 +254,9 @@ void MainWindow::finishedLoadingTrace()
void MainWindow::replayTrace(bool dumpState)
{
- if (m_trace->fileName().isEmpty())
+ if (m_trace->fileName().isEmpty()) {
return;
+ }
m_retracer->setFileName(m_trace->fileName());
m_retracer->setCaptureState(dumpState);
@@ -268,7 +272,7 @@ void MainWindow::replayTrace(bool dumpState)
qDebug()<<"tried to get a state for an empty frame";
return;
}
- index = frame->calls().first()->index();
+ index = frame->lastCallIndex();
} else {
qDebug()<<"Unknown event type";
return;
@@ -279,12 +283,13 @@ void MainWindow::replayTrace(bool dumpState)
m_ui.actionStop->setEnabled(true);
m_progressBar->show();
- if (dumpState)
+ if (dumpState) {
statusBar()->showMessage(
tr("Looking up the state..."));
- else
+ } else {
statusBar()->showMessage(
tr("Replaying the trace file..."));
+ }
}
void MainWindow::lookupState()
@@ -320,7 +325,7 @@ static void
variantToString(const QVariant &var, QString &str)
{
if (var.type() == QVariant::List) {
- QVariantList lst = var.toList();
+ QVector<QVariant> lst = var.toList().toVector();
str += QLatin1String("[");
for (int i = 0; i < lst.count(); ++i) {
QVariant val = lst[i];
@@ -339,10 +344,12 @@ variantToString(const QVariant &var, QString &str)
}
static QTreeWidgetItem *
-variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar);
+variantToItem(const QString &key, const QVariant &var,
+ const QVariant &defaultVar);
static void
-variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<QTreeWidgetItem *> &items)
+variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap,
+ QList<QTreeWidgetItem *> &items)
{
QVariantMap::const_iterator itr;
for (itr = map.constBegin(); itr != map.constEnd(); ++itr) {
@@ -358,7 +365,9 @@ variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<Q
}
static void
-variantListToItems(const QVariantList &lst, const QVariantList &defaultLst, QList<QTreeWidgetItem *> &items)
+variantListToItems(const QVector<QVariant> &lst,
+ const QVector<QVariant> &defaultLst,
+ QList<QTreeWidgetItem *> &items)
{
for (int i = 0; i < lst.count(); ++i) {
QString key = QString::number(i);
@@ -380,7 +389,7 @@ static bool
isVariantDeep(const QVariant &var)
{
if (var.type() == QVariant::List) {
- QVariantList lst = var.toList();
+ QVector<QVariant> lst = var.toList().toVector();
for (int i = 0; i < lst.count(); ++i) {
if (isVariantDeep(lst[i])) {
return true;
@@ -397,7 +406,8 @@ isVariantDeep(const QVariant &var)
}
static QTreeWidgetItem *
-variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar)
+variantToItem(const QString &key, const QVariant &var,
+ const QVariant &defaultVar)
{
if (var == defaultVar) {
return NULL;
@@ -426,8 +436,8 @@ variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVa
variantMapToItems(map, defaultMap, children);
}
if (var.type() == QVariant::List) {
- QVariantList lst = var.toList();
- QVariantList defaultLst = defaultVar.toList();
+ QVector<QVariant> lst = var.toList().toVector();
+ QVector<QVariant> defaultLst = defaultVar.toList().toVector();
variantListToItems(lst, defaultLst, children);
}
item->addChildren(children);
@@ -441,13 +451,12 @@ static void addSurfaceItem(const ApiSurface &surface,
QTreeWidgetItem *parent,
QTreeWidget *tree)
{
- int width = surface.size().width();
- int height = surface.size().height();
QIcon icon(QPixmap::fromImage(surface.thumb()));
QTreeWidgetItem *item = new QTreeWidgetItem(parent);
-
item->setIcon(0, icon);
+ int width = surface.size().width();
+ int height = surface.size().height();
QString descr =
QString::fromLatin1("%1, %2 x %3")
.arg(label)
@@ -464,8 +473,9 @@ static void addSurfaceItem(const ApiSurface &surface,
void MainWindow::fillStateForFrame()
{
- if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
+ if (!m_selectedEvent || !m_selectedEvent->hasState()) {
return;
+ }
if (m_nonDefaultsLookupEvent) {
m_ui.nonDefaultsCB->blockSignals(true);
@@ -480,7 +490,7 @@ void MainWindow::fillStateForFrame()
defaultParams = defaultState.parameters();
}
- const ApiTraceState &state = m_selectedEvent->state();
+ const ApiTraceState &state = *m_selectedEvent->state();
m_ui.stateTreeWidget->clear();
QList<QTreeWidgetItem *> items;
variantMapToItems(state.parameters(), defaultParams, items);
@@ -512,8 +522,9 @@ void MainWindow::fillStateForFrame()
QTreeWidgetItem *textureItem =
new QTreeWidgetItem(m_ui.surfacesTreeWidget);
textureItem->setText(0, tr("Textures"));
- if (textures.count() <= 6)
+ if (textures.count() <= 6) {
textureItem->setExpanded(true);
+ }
for (int i = 0; i < textures.count(); ++i) {
const ApiTexture &texture =
@@ -527,8 +538,9 @@ void MainWindow::fillStateForFrame()
QTreeWidgetItem *fboItem =
new QTreeWidgetItem(m_ui.surfacesTreeWidget);
fboItem->setText(0, tr("Framebuffers"));
- if (fbos.count() <= 6)
+ if (fbos.count() <= 6) {
fboItem->setExpanded(true);
+ }
for (int i = 0; i < fbos.count(); ++i) {
const ApiFramebuffer &fbo =
@@ -560,8 +572,9 @@ void MainWindow::showSurfacesMenu(const QPoint &pos)
{
QTreeWidget *tree = m_ui.surfacesTreeWidget;
QTreeWidgetItem *item = tree->itemAt(pos);
- if (!item)
+ if (!item) {
return;
+ }
QMenu menu(tr("Surfaces"), this);
@@ -583,24 +596,28 @@ void MainWindow::showSelectedSurface()
QTreeWidgetItem *item =
m_ui.surfacesTreeWidget->currentItem();
- if (!item)
+ if (!item) {
return;
+ }
- QVariant var = item->data(0, Qt::UserRole);
- QImage img = var.value<QImage>();
ImageViewer *viewer = new ImageViewer(this);
QString title;
- if (currentCall()) {
+ if (selectedCall()) {
title = tr("QApiTrace - Surface at %1 (%2)")
- .arg(currentCall()->name())
- .arg(currentCall()->index());
+ .arg(selectedCall()->name())
+ .arg(selectedCall()->index());
} else {
title = tr("QApiTrace - Surface Viewer");
}
viewer->setWindowTitle(title);
+
viewer->setAttribute(Qt::WA_DeleteOnClose, true);
+
+ QVariant var = item->data(0, Qt::UserRole);
+ QImage img = var.value<QImage>();
viewer->setImage(img);
+
QRect screenRect = QApplication::desktop()->availableGeometry();
viewer->resize(qMin(int(0.75 * screenRect.width()), img.width()) + 40,
qMin(int(0.75 * screenRect.height()), img.height()) + 40);
@@ -646,7 +663,7 @@ void MainWindow::initObjects()
m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu);
m_progressBar = new QProgressBar();
- m_progressBar->setRange(0, 0);
+ m_progressBar->setRange(0, 100);
statusBar()->addPermanentWidget(m_progressBar);
m_progressBar->hide();
@@ -681,6 +698,8 @@ void MainWindow::initConnections()
{
connect(m_trace, SIGNAL(startedLoadingTrace()),
this, SLOT(startedLoadingTrace()));
+ connect(m_trace, SIGNAL(loaded(int)),
+ this, SLOT(loadProgess(int)));
connect(m_trace, SIGNAL(finishedLoadingTrace()),
this, SLOT(finishedLoadingTrace()));
connect(m_trace, SIGNAL(startedSaving()),
@@ -689,15 +708,23 @@ void MainWindow::initConnections()
this, SLOT(slotSaved()));
connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
this, SLOT(slotTraceChanged(ApiTraceCall*)));
+ connect(m_trace, SIGNAL(findResult(ApiTrace::SearchResult,ApiTraceCall*)),
+ this, SLOT(slotSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
+ connect(m_trace, SIGNAL(foundFrameStart(ApiTraceFrame*)),
+ this, SLOT(slotFoundFrameStart(ApiTraceFrame*)));
+ connect(m_trace, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
+ this, SLOT(slotFoundFrameEnd(ApiTraceFrame*)));
+ connect(m_trace, SIGNAL(foundCallIndex(ApiTraceCall*)),
+ this, SLOT(slotJumpToResult(ApiTraceCall*)));
connect(m_retracer, SIGNAL(finished(const QString&)),
this, SLOT(replayFinished(const QString&)));
connect(m_retracer, SIGNAL(error(const QString&)),
this, SLOT(replayError(const QString&)));
- connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)),
- this, SLOT(replayStateFound(const ApiTraceState&)));
- connect(m_retracer, SIGNAL(retraceErrors(const QList<RetraceError>&)),
- this, SLOT(slotRetraceErrors(const QList<RetraceError>&)));
+ connect(m_retracer, SIGNAL(foundState(ApiTraceState*)),
+ this, SLOT(replayStateFound(ApiTraceState*)));
+ connect(m_retracer, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
+ this, SLOT(slotRetraceErrors(const QList<ApiTraceError>&)));
connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
m_vdataInterpreter, SLOT(interpretData()));
@@ -778,7 +805,7 @@ void MainWindow::initConnections()
this, SLOT(slotErrorSelected(QTreeWidgetItem*)));
}
-void MainWindow::replayStateFound(const ApiTraceState &state)
+void MainWindow::replayStateFound(ApiTraceState *state)
{
m_stateEvent->setState(state);
m_model->stateSetOnEvent(m_stateEvent);
@@ -799,10 +826,7 @@ void MainWindow::slotGoTo()
void MainWindow::slotJumpTo(int callNum)
{
- QModelIndex index = m_proxyModel->callIndex(callNum);
- if (index.isValid()) {
- m_ui.callView->setCurrentIndex(index);
- }
+ m_trace->findCallIndex(callNum);
}
void MainWindow::createdTrace(const QString &path)
@@ -828,103 +852,31 @@ void MainWindow::slotSearch()
void MainWindow::slotSearchNext(const QString &str,
Qt::CaseSensitivity sensitivity)
{
- QModelIndex index = m_ui.callView->currentIndex();
- ApiTraceEvent *event = 0;
-
-
- if (!index.isValid()) {
- index = m_proxyModel->index(0, 0, QModelIndex());
- if (!index.isValid()) {
- qDebug()<<"no currently valid index";
- m_searchWidget->setFound(false);
- return;
- }
- }
-
- event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
- ApiTraceCall *call = 0;
+ ApiTraceCall *call = currentCall();
+ ApiTraceFrame *frame = currentFrame();
- if (event->type() == ApiTraceCall::Call)
- call = static_cast<ApiTraceCall*>(event);
- else {
- Q_ASSERT(event->type() == ApiTraceCall::Frame);
- ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
- call = frame->call(0);
+ Q_ASSERT(call || frame);
+ if (!frame) {
+ frame = call->parentFrame();
}
+ Q_ASSERT(frame);
- if (!call) {
- m_searchWidget->setFound(false);
- return;
- }
- const QList<ApiTraceCall*> &calls = m_trace->calls();
- int callNum = calls.indexOf(call);
-
- for (int i = callNum + 1; i < calls.count(); ++i) {
- ApiTraceCall *testCall = calls[i];
- QModelIndex index = m_proxyModel->indexForCall(testCall);
- /* if it's not valid it means that the proxy model has already
- * filtered it out */
- if (index.isValid()) {
- QString txt = testCall->searchText();
- if (txt.contains(str, sensitivity)) {
- m_ui.callView->setCurrentIndex(index);
- m_searchWidget->setFound(true);
- return;
- }
- }
- }
- m_searchWidget->setFound(false);
+ m_trace->findNext(frame, call, str, sensitivity);
}
void MainWindow::slotSearchPrev(const QString &str,
Qt::CaseSensitivity sensitivity)
{
- QModelIndex index = m_ui.callView->currentIndex();
- ApiTraceEvent *event = 0;
-
-
- if (!index.isValid()) {
- index = m_proxyModel->index(0, 0, QModelIndex());
- if (!index.isValid()) {
- qDebug()<<"no currently valid index";
- m_searchWidget->setFound(false);
- return;
- }
- }
-
- event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
- ApiTraceCall *call = 0;
+ ApiTraceCall *call = currentCall();
+ ApiTraceFrame *frame = currentFrame();
- if (event->type() == ApiTraceCall::Call)
- call = static_cast<ApiTraceCall*>(event);
- else {
- Q_ASSERT(event->type() == ApiTraceCall::Frame);
- ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
- call = frame->call(0);
+ Q_ASSERT(call || frame);
+ if (!frame) {
+ frame = call->parentFrame();
}
+ Q_ASSERT(frame);
- if (!call) {
- m_searchWidget->setFound(false);
- return;
- }
- const QList<ApiTraceCall*> &calls = m_trace->calls();
- int callNum = calls.indexOf(call);
-
- for (int i = callNum - 1; i >= 0; --i) {
- ApiTraceCall *testCall = calls[i];
- QModelIndex index = m_proxyModel->indexForCall(testCall);
- /* if it's not valid it means that the proxy model has already
- * filtered it out */
- if (index.isValid()) {
- QString txt = testCall->searchText();
- if (txt.contains(str, sensitivity)) {
- m_ui.callView->setCurrentIndex(index);
- m_searchWidget->setFound(true);
- return;
- }
- }
- }
- m_searchWidget->setFound(false);
+ m_trace->findPrev(frame, call, str, sensitivity);
}
void MainWindow::fillState(bool nonDefaults)
@@ -937,11 +889,17 @@ void MainWindow::fillState(bool nonDefaults)
m_ui.nonDefaultsCB->blockSignals(false);
ApiTraceFrame *firstFrame =
m_trace->frameAt(0);
- ApiTraceEvent *oldSelected = m_selectedEvent;
- if (!firstFrame)
+ if (!firstFrame) {
+ return;
+ }
+ if (!firstFrame->isLoaded()) {
+ m_trace->loadFrame(firstFrame);
return;
+ }
+ ApiTraceCall *firstCall = firstFrame->calls().first();
+ ApiTraceEvent *oldSelected = m_selectedEvent;
m_nonDefaultsLookupEvent = m_selectedEvent;
- m_selectedEvent = firstFrame;
+ m_selectedEvent = firstCall;
lookupState();
m_selectedEvent = oldSelected;
}
@@ -951,18 +909,20 @@ void MainWindow::fillState(bool nonDefaults)
void MainWindow::customContextMenuRequested(QPoint pos)
{
- QMenu menu;
QModelIndex index = m_ui.callView->indexAt(pos);
callItemSelected(index);
- if (!index.isValid())
+ if (!index.isValid()) {
return;
+ }
ApiTraceEvent *event =
index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
- if (!event)
+ if (!event) {
return;
+ }
+ QMenu menu;
menu.addAction(QIcon(":/resources/media-record.png"),
tr("Lookup state"), this, SLOT(lookupState()));
if (event->type() == ApiTraceEvent::Call) {
@@ -998,47 +958,28 @@ void MainWindow::slotSaved()
void MainWindow::slotGoFrameStart()
{
ApiTraceFrame *frame = currentFrame();
- if (!frame || frame->isEmpty()) {
- return;
- }
-
- QList<ApiTraceCall*>::const_iterator itr;
- QList<ApiTraceCall*> calls = frame->calls();
+ ApiTraceCall *call = currentCall();
- itr = calls.constBegin();
- while (itr != calls.constEnd()) {
- ApiTraceCall *call = *itr;
- QModelIndex idx = m_proxyModel->indexForCall(call);
- if (idx.isValid()) {
- m_ui.callView->setCurrentIndex(idx);
- break;
- }
- ++itr;
+ if (!frame && call) {
+ frame = call->parentFrame();
}
+
+ m_trace->findFrameStart(frame);
}
void MainWindow::slotGoFrameEnd()
{
ApiTraceFrame *frame = currentFrame();
- if (!frame || frame->isEmpty()) {
- return;
+ ApiTraceCall *call = currentCall();
+
+ if (!frame && call) {
+ frame = call->parentFrame();
}
- QList<ApiTraceCall*>::const_iterator itr;
- QList<ApiTraceCall*> calls = frame->calls();
- itr = calls.constEnd();
- do {
- --itr;
- ApiTraceCall *call = *itr;
- QModelIndex idx = m_proxyModel->indexForCall(call);
- if (idx.isValid()) {
- m_ui.callView->setCurrentIndex(idx);
- break;
- }
- } while (itr != calls.constBegin());
+ m_trace->findFrameEnd(frame);
}
-ApiTraceFrame * MainWindow::currentFrame() const
+ApiTraceFrame * MainWindow::selectedFrame() const
{
if (m_selectedEvent) {
if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
@@ -1060,20 +1001,17 @@ void MainWindow::slotTraceChanged(ApiTraceCall *call)
}
}
-void MainWindow::slotRetraceErrors(const QList<RetraceError> &errors)
+void MainWindow::slotRetraceErrors(const QList<ApiTraceError> &errors)
{
m_ui.errorsTreeWidget->clear();
- foreach(RetraceError error, errors) {
- ApiTraceCall *call = m_trace->callWithIndex(error.callIndex);
- if (!call)
- continue;
- call->setError(error.message);
+ foreach(ApiTraceError error, errors) {
+ m_trace->setCallError(error);
QTreeWidgetItem *item =
new QTreeWidgetItem(m_ui.errorsTreeWidget);
item->setData(0, Qt::DisplayRole, error.callIndex);
- item->setData(0, Qt::UserRole, QVariant::fromValue(call));
+ item->setData(0, Qt::UserRole, error.callIndex);
QString type = error.type;
type[0] = type[0].toUpper();
item->setData(1, Qt::DisplayRole, type);
@@ -1084,19 +1022,13 @@ void MainWindow::slotRetraceErrors(const QList<RetraceError> &errors)
void MainWindow::slotErrorSelected(QTreeWidgetItem *current)
{
if (current) {
- ApiTraceCall *call =
- current->data(0, Qt::UserRole).value<ApiTraceCall*>();
- Q_ASSERT(call);
- QModelIndex index = m_proxyModel->indexForCall(call);
- if (index.isValid()) {
- m_ui.callView->setCurrentIndex(index);
- } else {
- statusBar()->showMessage(tr("Call has been filtered out."));
- }
+ int callIndex =
+ current->data(0, Qt::UserRole).toInt();
+ m_trace->findCallIndex(callIndex);
}
}
-ApiTraceCall * MainWindow::currentCall() const
+ApiTraceCall * MainWindow::selectedCall() const
{
if (m_selectedEvent &&
m_selectedEvent->type() == ApiTraceEvent::Call) {
@@ -1110,18 +1042,19 @@ void MainWindow::saveSelectedSurface()
QTreeWidgetItem *item =
m_ui.surfacesTreeWidget->currentItem();
- if (!item || !m_trace)
+ if (!item || !m_trace) {
return;
+ }
QVariant var = item->data(0, Qt::UserRole);
QImage img = var.value<QImage>();
QString imageIndex;
- if (currentCall()) {
+ if (selectedCall()) {
imageIndex = tr("_call_%1")
- .arg(currentCall()->index());
- } else if (currentFrame()) {
- ApiTraceCall *firstCall = currentFrame()->call(0);
+ .arg(selectedCall()->index());
+ } else if (selectedFrame()) {
+ ApiTraceCall *firstCall = selectedFrame()->call(0);
if (firstCall) {
imageIndex = tr("_frame_%1")
.arg(firstCall->index());
@@ -1158,4 +1091,135 @@ void MainWindow::saveSelectedSurface()
statusBar()->showMessage( tr("Saved '%1'").arg(fileName), 5000);
}
+void MainWindow::loadProgess(int percent)
+{
+ m_progressBar->setValue(percent);
+}
+
+void MainWindow::slotSearchResult(ApiTrace::SearchResult result,
+ ApiTraceCall *call)
+{
+ switch (result) {
+ case ApiTrace::SearchResult_NotFound:
+ m_searchWidget->setFound(false);
+ break;
+ case ApiTrace::SearchResult_Found: {
+ QModelIndex index = m_proxyModel->indexForCall(call);
+ m_ui.callView->setCurrentIndex(index);
+ m_searchWidget->setFound(true);
+ }
+ break;
+ case ApiTrace::SearchResult_Wrapped:
+ m_searchWidget->setFound(false);
+ break;
+ }
+}
+
+ApiTraceFrame * MainWindow::currentFrame() const
+{
+ QModelIndex index = m_ui.callView->currentIndex();
+ ApiTraceEvent *event = 0;
+
+ if (!index.isValid()) {
+ index = m_proxyModel->index(0, 0, QModelIndex());
+ if (!index.isValid()) {
+ qDebug()<<"no currently valid index";
+ return 0;
+ }
+ }
+
+ event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+ Q_ASSERT(event);
+ if (!event) {
+ return 0;
+ }
+
+ ApiTraceFrame *frame = 0;
+ if (event->type() == ApiTraceCall::Frame) {
+ frame = static_cast<ApiTraceFrame*>(event);
+ }
+ return frame;
+}
+
+ApiTraceCall * MainWindow::currentCall() const
+{
+ QModelIndex index = m_ui.callView->currentIndex();
+ ApiTraceEvent *event = 0;
+
+ if (!index.isValid()) {
+ index = m_proxyModel->index(0, 0, QModelIndex());
+ if (!index.isValid()) {
+ qDebug()<<"no currently valid index";
+ return 0;
+ }
+ }
+
+ event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+ Q_ASSERT(event);
+ if (!event) {
+ return 0;
+ }
+
+ ApiTraceCall *call = 0;
+ if (event->type() == ApiTraceCall::Call) {
+ call = static_cast<ApiTraceCall*>(event);
+ }
+
+ return call;
+
+}
+
+void MainWindow::slotFoundFrameStart(ApiTraceFrame *frame)
+{
+ Q_ASSERT(frame->isLoaded());
+ if (!frame || frame->isEmpty()) {
+ return;
+ }
+
+ QVector<ApiTraceCall*>::const_iterator itr;
+ QVector<ApiTraceCall*> calls = frame->calls();
+
+ itr = calls.constBegin();
+ while (itr != calls.constEnd()) {
+ ApiTraceCall *call = *itr;
+ QModelIndex idx = m_proxyModel->indexForCall(call);
+ if (idx.isValid()) {
+ m_ui.callView->setCurrentIndex(idx);
+ break;
+ }
+ ++itr;
+ }
+}
+
+void MainWindow::slotFoundFrameEnd(ApiTraceFrame *frame)
+{
+ Q_ASSERT(frame->isLoaded());
+ if (!frame || frame->isEmpty()) {
+ return;
+ }
+ QVector<ApiTraceCall*>::const_iterator itr;
+ QVector<ApiTraceCall*> calls = frame->calls();
+
+ itr = calls.constEnd();
+ do {
+ --itr;
+ ApiTraceCall *call = *itr;
+ QModelIndex idx = m_proxyModel->indexForCall(call);
+ if (idx.isValid()) {
+ m_ui.callView->setCurrentIndex(idx);
+ break;
+ }
+ } while (itr != calls.constBegin());
+}
+
+void MainWindow::slotJumpToResult(ApiTraceCall *call)
+{
+ QModelIndex index = m_proxyModel->indexForCall(call);
+ if (index.isValid()) {
+ m_ui.callView->setCurrentIndex(index);
+ } else {
+ statusBar()->showMessage(tr("Call has been filtered out."));
+ }
+}
+
#include "mainwindow.moc"
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index 5cb2e76..0ae8ab7 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -3,6 +3,8 @@
#include "ui_mainwindow.h"
+#include "apitrace.h"
+
#include <QMainWindow>
#include <QProcess>
@@ -19,7 +21,7 @@ class QModelIndex;
class QProgressBar;
class QTreeWidgetItem;
class QUrl;
-struct RetraceError;
+struct ApiTraceError;
class Retracer;
class SearchWidget;
class ShadersSourceWidget;
@@ -43,9 +45,10 @@ private slots:
void replayStart();
void replayStop();
void replayFinished(const QString &output);
- void replayStateFound(const ApiTraceState &state);
+ void replayStateFound(ApiTraceState *state);
void replayError(const QString &msg);
void startedLoadingTrace();
+ void loadProgess(int percent);
void finishedLoadingTrace();
void lookupState();
void showSettings();
@@ -68,8 +71,13 @@ private slots:
void slotGoFrameStart();
void slotGoFrameEnd();
void slotTraceChanged(ApiTraceCall *call);
- void slotRetraceErrors(const QList<RetraceError> &errors);
+ void slotRetraceErrors(const QList<ApiTraceError> &errors);
void slotErrorSelected(QTreeWidgetItem *current);
+ void slotSearchResult(ApiTrace::SearchResult result,
+ ApiTraceCall *call);
+ void slotFoundFrameStart(ApiTraceFrame *frame);
+ void slotFoundFrameEnd(ApiTraceFrame *frame);
+ void slotJumpToResult(ApiTraceCall *call);
private:
void initObjects();
@@ -77,9 +85,17 @@ private:
void newTraceFile(const QString &fileName);
void replayTrace(bool dumpState);
void fillStateForFrame();
+
+ /* there's a difference between selected frame/call and
+ * current call/frame. the former implies actual selection
+ * the latter might be just a highlight, e.g. during searching
+ */
+ ApiTraceFrame *selectedFrame() const;
+ ApiTraceCall *selectedCall() const;
ApiTraceFrame *currentFrame() const;
ApiTraceCall *currentCall() const;
+
private:
Ui_MainWindow m_ui;
ShadersSourceWidget *m_sourcesWidget;
diff --git a/gui/retracer.cpp b/gui/retracer.cpp
index 98a4db2..251028c 100644
--- a/gui/retracer.cpp
+++ b/gui/retracer.cpp
@@ -98,10 +98,10 @@ void Retracer::run()
this, SIGNAL(finished(const QString&)));
connect(retrace, SIGNAL(error(const QString&)),
this, SIGNAL(error(const QString&)));
- connect(retrace, SIGNAL(foundState(const ApiTraceState&)),
- this, SIGNAL(foundState(const ApiTraceState&)));
- connect(retrace, SIGNAL(retraceErrors(const QList<RetraceError>&)),
- this, SIGNAL(retraceErrors(const QList<RetraceError>&)));
+ connect(retrace, SIGNAL(foundState(ApiTraceState*)),
+ this, SIGNAL(foundState(ApiTraceState*)));
+ connect(retrace, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
+ this, SIGNAL(retraceErrors(const QList<ApiTraceError>&)));
retrace->start();
@@ -155,7 +155,7 @@ void RetraceProcess::replayFinished()
if (m_captureState) {
bool ok = false;
QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
- ApiTraceState state(parsedJson);
+ ApiTraceState *state = new ApiTraceState(parsedJson);
emit foundState(state);
msg = tr("State fetched.");
} else {
@@ -163,11 +163,11 @@ void RetraceProcess::replayFinished()
}
QStringList errorLines = errStr.split('\n');
- QList<RetraceError> errors;
+ QList<ApiTraceError> errors;
QRegExp regexp("(^\\d+): +(\\b\\w+\\b): (.+$)");
foreach(QString line, errorLines) {
if (regexp.indexIn(line) != -1) {
- RetraceError error;
+ ApiTraceError error;
error.callIndex = regexp.cap(1).toInt();
error.type = regexp.cap(2);
error.message = regexp.cap(3);
@@ -190,14 +190,14 @@ void RetraceProcess::replayError(QProcess::ProcessError err)
tr("Couldn't execute the replay file '%1'").arg(m_fileName));
}
-Q_DECLARE_METATYPE(QList<RetraceError>);
+Q_DECLARE_METATYPE(QList<ApiTraceError>);
RetraceProcess::RetraceProcess(QObject *parent)
: QObject(parent)
{
m_process = new QProcess(this);
m_jsonParser = new QJson::Parser();
- qRegisterMetaType<QList<RetraceError> >();
+ qRegisterMetaType<QList<ApiTraceError> >();
connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(replayFinished()));
diff --git a/gui/retracer.h b/gui/retracer.h
index 1b5a4bd..4a43c26 100644
--- a/gui/retracer.h
+++ b/gui/retracer.h
@@ -1,6 +1,8 @@
#ifndef RETRACER_H
#define RETRACER_H
+#include "apitracecall.h"
+
#include <QThread>
#include <QProcess>
@@ -9,12 +11,6 @@ namespace QJson {
class Parser;
}
-struct RetraceError {
- int callIndex;
- QString type;
- QString message;
-};
-
/* internal class used by the retracer to run
* in the thread */
class RetraceProcess : public QObject
@@ -48,8 +44,8 @@ public slots:
signals:
void finished(const QString &output);
void error(const QString &msg);
- void foundState(const ApiTraceState &state);
- void retraceErrors(const QList<RetraceError> &errors);
+ void foundState(ApiTraceState *state);
+ void retraceErrors(const QList<ApiTraceError> &errors);
private slots:
void replayFinished();
@@ -89,9 +85,9 @@ public:
signals:
void finished(const QString &output);
- void foundState(const ApiTraceState &state);
+ void foundState(ApiTraceState *state);
void error(const QString &msg);
- void retraceErrors(const QList<RetraceError> &errors);
+ void retraceErrors(const QList<ApiTraceError> &errors);
protected:
virtual void run();
diff --git a/gui/saverthread.cpp b/gui/saverthread.cpp
index d7f6906..d5f4d6b 100644
--- a/gui/saverthread.cpp
+++ b/gui/saverthread.cpp
@@ -1,6 +1,8 @@
#include "saverthread.h"
#include "trace_writer.hpp"
+#include "trace_model.hpp"
+#include "trace_parser.hpp"
#include <QFile>
#include <QHash>
@@ -8,7 +10,7 @@
#include <QDebug>
-
+#if 0
static Trace::FunctionSig *
createFunctionSig(ApiTraceCall *call, unsigned id)
{
@@ -162,7 +164,7 @@ writeValue(Trace::Writer &writer, const QVariant &var, unsigned &id)
default:
if (type == arrayType) {
ApiArray array = var.value<ApiArray>();
- QList<QVariant> vals = array.values();
+ QVector<QVariant> vals = array.values();
writer.beginArray(vals.count());
foreach(QVariant el, vals) {
writer.beginElement();
@@ -203,54 +205,164 @@ writeValue(Trace::Writer &writer, const QVariant &var, unsigned &id)
}
}
}
+#endif
+
+class EditVisitor : public Trace::Visitor
+{
+public:
+ EditVisitor(const QVariant &variant)
+ : m_variant(variant),
+ m_editedValue(0)
+ {}
+ virtual void visit(Trace::Null *val)
+ {
+ m_editedValue = val;
+ }
+
+ virtual void visit(Trace::Bool *node)
+ {
+// Q_ASSERT(m_variant.userType() == QVariant::Bool);
+ bool var = m_variant.toBool();
+ m_editedValue = new Trace::Bool(var);
+ }
+
+ virtual void visit(Trace::SInt *node)
+ {
+// Q_ASSERT(m_variant.userType() == QVariant::Int);
+ m_editedValue = new Trace::SInt(m_variant.toInt());
+ }
+
+ virtual void visit(Trace::UInt *node)
+ {
+// Q_ASSERT(m_variant.userType() == QVariant::UInt);
+ m_editedValue = new Trace::SInt(m_variant.toUInt());
+ }
+
+ virtual void visit(Trace::Float *node)
+ {
+ m_editedValue = new Trace::Float(m_variant.toFloat());
+ }
+
+ virtual void visit(Trace::String *node)
+ {
+ QString str = m_variant.toString();
+ m_editedValue = new Trace::String(str.toLocal8Bit().constData());
+ }
+
+ virtual void visit(Trace::Enum *e)
+ {
+ m_editedValue = e;
+ }
+
+ virtual void visit(Trace::Bitmask *bitmask)
+ {
+ m_editedValue = bitmask;
+ }
+
+ virtual void visit(Trace::Struct *str)
+ {
+ m_editedValue = str;
+ }
+
+ virtual void visit(Trace::Array *array)
+ {
+ ApiArray apiArray = m_variant.value<ApiArray>();
+ QVector<QVariant> vals = apiArray.values();
+
+ Trace::Array *newArray = new Trace::Array(vals.count());
+ for (int i = 0; i < vals.count(); ++i) {
+ EditVisitor visitor(vals[i]);
+
+ array->values[i]->visit(visitor);
+ if (array->values[i] == visitor.value()) {
+ //non-editabled
+ delete newArray;
+ m_editedValue = array;
+ return;
+ }
+
+ newArray->values.push_back(visitor.value());
+ }
+ m_editedValue = newArray;
+ }
+
+ virtual void visit(Trace::Blob *blob)
+ {
+ m_editedValue = blob;
+ }
+
+ virtual void visit(Trace::Pointer *ptr)
+ {
+ m_editedValue = ptr;
+ }
+
+ Trace::Value *value() const
+ {
+ return m_editedValue;
+ }
+private:
+ QVariant m_variant;
+ Trace::Value *m_editedValue;
+};
+
+static void
+overwriteValue(Trace::Call *call, const QVariant &val, int index)
+{
+ EditVisitor visitor(val);
+ Trace::Value *origValue = call->args[index];
+ origValue->visit(visitor);
+
+ if (visitor.value() && origValue != visitor.value()) {
+ delete origValue;
+ call->args[index] = visitor.value();
+ }
+}
SaverThread::SaverThread(QObject *parent)
: QThread(parent)
{
}
-void SaverThread::saveFile(const QString &fileName,
- const QList<ApiTraceCall*> &calls)
+void SaverThread::saveFile(const QString &writeFileName,
+ const QString &readFileName,
+ const QSet<ApiTraceCall*> &editedCalls)
{
- m_fileName = fileName;
- m_calls = calls;
+ m_writeFileName = writeFileName;
+ m_readFileName = readFileName;
+ m_editedCalls = editedCalls;
start();
}
void SaverThread::run()
{
- unsigned id = 0;
- qDebug() << "Saving : " << m_fileName;
+ qDebug() << "Saving " << m_readFileName
+ << ", to " << m_writeFileName;
+ QMap<int, ApiTraceCall*> callIndexMap;
+
+ foreach(ApiTraceCall *call, m_editedCalls) {
+ callIndexMap.insert(call->index(), call);
+ }
+
Trace::Writer writer;
- writer.open(m_fileName.toLocal8Bit());
- for (int i = 0; i < m_calls.count(); ++i) {
- ApiTraceCall *call = m_calls[i];
- Trace::FunctionSig *funcSig = createFunctionSig(call, ++id);
- unsigned callNo = writer.beginEnter(funcSig);
- {
- //args
- QVariantList vars = call->arguments();
- int index = 0;
- foreach(QVariant var, vars) {
- writer.beginArg(index++);
- writeValue(writer, var, ++id);
- writer.endArg();
- }
- }
- writer.endEnter();
- writer.beginLeave(callNo);
- {
- QVariant ret = call->returnValue();
- if (!ret.isNull()) {
- writer.beginReturn();
- writeValue(writer, ret, ++id);
- writer.endReturn();
+ writer.open(m_writeFileName.toLocal8Bit());
+
+ Trace::Parser parser;
+ parser.open(m_readFileName.toLocal8Bit());
+
+ Trace::Call *call;
+ while ((call = parser.parse_call())) {
+ if (callIndexMap.contains(call->no)) {
+ QVector<QVariant> values = callIndexMap[call->no]->editedValues();
+ for (int i = 0; i < values.count(); ++i) {
+ const QVariant &val = values[i];
+ overwriteValue(call, val, i);
}
+ writer.writeCall(call);
+ } else {
+ writer.writeCall(call);
}
- writer.endLeave();
-
- deleteFunctionSig(funcSig);
}
+
writer.close();
emit traceSaved();
diff --git a/gui/saverthread.h b/gui/saverthread.h
index 5bea5b7..e8c6889 100644
--- a/gui/saverthread.h
+++ b/gui/saverthread.h
@@ -4,7 +4,7 @@
#include "apitrace.h"
#include <QThread>
-#include <QList>
+#include <QVector>
class ApiTraceCall;
class ApiTraceFrame;
@@ -16,8 +16,9 @@ public:
SaverThread(QObject *parent=0);
public slots:
- void saveFile(const QString &fileName,
- const QList<ApiTraceCall*> &calls);
+ void saveFile(const QString &saveFileName,
+ const QString &readFileName,
+ const QSet<ApiTraceCall*> &editedCalls);
signals:
void traceSaved();
@@ -26,8 +27,9 @@ protected:
virtual void run();
private:
- QString m_fileName;
- QList<ApiTraceCall*> m_calls;
+ QString m_readFileName;
+ QString m_writeFileName;
+ QSet<ApiTraceCall*> m_editedCalls;
};
diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp
new file mode 100644
index 0000000..0fee815
--- /dev/null
+++ b/gui/traceloader.cpp
@@ -0,0 +1,496 @@
+#include "traceloader.h"
+
+#include "apitrace.h"
+#include <QDebug>
+#include <QFile>
+
+#define FRAMES_TO_CACHE 100
+
+static ApiTraceCall *
+apiCallFromTraceCall(const Trace::Call *call,
+ const QHash<QString, QUrl> &helpHash,
+ ApiTraceFrame *frame,
+ TraceLoader *loader)
+{
+ ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+
+ apiCall->setHelpUrl(helpHash.value(apiCall->name()));
+
+ return apiCall;
+}
+
+TraceLoader::TraceLoader(QObject *parent)
+ : QObject(parent),
+ m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
+{
+}
+
+TraceLoader::~TraceLoader()
+{
+ m_parser.close();
+ qDeleteAll(m_signatures);
+ qDeleteAll(m_enumSignatures);
+}
+
+void TraceLoader::loadTrace(const QString &filename)
+{
+ if (m_helpHash.isEmpty()) {
+ loadHelpFile();
+ }
+
+ if (!m_parser.open(filename.toLatin1())) {
+ qDebug() << "error: failed to open " << filename;
+ return;
+ }
+
+ emit startedParsing();
+
+ if (m_parser.supportsOffsets()) {
+ scanTrace();
+ } else {
+ //Load the entire file into memory
+ parseTrace();
+ }
+
+ emit finishedParsing();
+}
+
+void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
+{
+ fetchFrameContents(currentFrame);
+}
+
+void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
+{
+ m_frameMarker = marker;
+}
+
+bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
+{
+ std::string name = call->name();
+
+ switch (m_frameMarker) {
+ case ApiTrace::FrameMarker_SwapBuffers:
+ return name.find("SwapBuffers") != std::string::npos ||
+ name == "CGLFlushDrawable" ||
+ name == "glFrameTerminatorGREMEDY";
+ break;
+ case ApiTrace::FrameMarker_Flush:
+ return name == "glFlush";
+ break;
+ case ApiTrace::FrameMarker_Finish:
+ return name == "glFinish";
+ break;
+ case ApiTrace::FrameMarker_Clear:
+ return name == "glClear";
+ break;
+ }
+ return false;
+}
+
+int TraceLoader::numberOfFrames() const
+{
+ return m_frameBookmarks.size();
+}
+
+int TraceLoader::numberOfCallsInFrame(int frameIdx) const
+{
+ if (frameIdx > m_frameBookmarks.size()) {
+ return 0;
+ }
+ FrameBookmarks::const_iterator itr =
+ m_frameBookmarks.find(frameIdx);
+ return itr->numberOfCalls;
+}
+
+void TraceLoader::loadHelpFile()
+{
+ QFile file(":/resources/glreference.tsv");
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QString line;
+ while (!file.atEnd()) {
+ line = file.readLine();
+ QString function = line.section('\t', 0, 0).trimmed();
+ QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
+ //qDebug()<<"function = "<<function<<", url = "<<url.toString();
+ m_helpHash.insert(function, url);
+ }
+ } else {
+ qWarning() << "Couldn't open reference file "
+ << file.fileName();
+ }
+ file.close();
+}
+
+void TraceLoader::scanTrace()
+{
+ QList<ApiTraceFrame*> frames;
+ ApiTraceFrame *currentFrame = 0;
+
+ Trace::Call *call;
+ Trace::ParseBookmark startBookmark;
+ int numOfFrames = 0;
+ int numOfCalls = 0;
+ int lastPercentReport = 0;
+
+ m_parser.getBookmark(startBookmark);
+
+ while ((call = m_parser.scan_call())) {
+ ++numOfCalls;
+
+ if (isCallAFrameMarker(call)) {
+ FrameBookmark frameBookmark(startBookmark);
+ frameBookmark.numberOfCalls = numOfCalls;
+
+ currentFrame = new ApiTraceFrame();
+ currentFrame->number = numOfFrames;
+ currentFrame->setNumChildren(numOfCalls);
+ currentFrame->setLastCallIndex(call->no);
+ frames.append(currentFrame);
+
+ m_createdFrames.append(currentFrame);
+ m_frameBookmarks[numOfFrames] = frameBookmark;
+ ++numOfFrames;
+
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ emit parsed(m_parser.percentRead());
+ lastPercentReport = m_parser.percentRead();
+ }
+ m_parser.getBookmark(startBookmark);
+ numOfCalls = 0;
+ }
+ delete call;
+ }
+
+ if (numOfCalls) {
+ //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
+ FrameBookmark frameBookmark(startBookmark);
+ frameBookmark.numberOfCalls = numOfCalls;
+
+ currentFrame = new ApiTraceFrame();
+ currentFrame->number = numOfFrames;
+ currentFrame->setNumChildren(numOfCalls);
+ frames.append(currentFrame);
+
+ m_createdFrames.append(currentFrame);
+ m_frameBookmarks[numOfFrames] = frameBookmark;
+ ++numOfFrames;
+ }
+
+ emit parsed(100);
+
+ emit framesLoaded(frames);
+}
+
+void TraceLoader::parseTrace()
+{
+ QList<ApiTraceFrame*> frames;
+ ApiTraceFrame *currentFrame = 0;
+ int frameCount = 0;
+ QVector<ApiTraceCall*> calls;
+ quint64 binaryDataSize = 0;
+
+ int lastPercentReport = 0;
+
+ Trace::Call *call = m_parser.parse_call();
+ while (call) {
+ //std::cout << *call;
+ if (!currentFrame) {
+ currentFrame = new ApiTraceFrame();
+ currentFrame->number = frameCount;
+ ++frameCount;
+ }
+ ApiTraceCall *apiCall =
+ apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
+ calls.append(apiCall);
+ if (apiCall->hasBinaryData()) {
+ QByteArray data =
+ apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+ binaryDataSize += data.size();
+ }
+ if (ApiTrace::isCallAFrameMarker(apiCall,
+ m_frameMarker)) {
+ calls.squeeze();
+ currentFrame->setCalls(calls, binaryDataSize);
+ calls.clear();
+ frames.append(currentFrame);
+ currentFrame = 0;
+ binaryDataSize = 0;
+ if (frames.count() >= FRAMES_TO_CACHE) {
+ emit framesLoaded(frames);
+ frames.clear();
+ }
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ emit parsed(m_parser.percentRead());
+ lastPercentReport = m_parser.percentRead();
+ }
+ }
+ delete call;
+ call = m_parser.parse_call();
+ }
+
+ //last frames won't have markers
+ // it's just a bunch of Delete calls for every object
+ // after the last SwapBuffers
+ if (currentFrame) {
+ calls.squeeze();
+ currentFrame->setCalls(calls, binaryDataSize);
+ frames.append(currentFrame);
+ currentFrame = 0;
+ }
+ if (frames.count()) {
+ emit framesLoaded(frames);
+ }
+}
+
+
+ApiTraceCallSignature * TraceLoader::signature(unsigned id)
+{
+ if (id >= m_signatures.count()) {
+ m_signatures.resize(id + 1);
+ return NULL;
+ } else {
+ return m_signatures[id];
+ }
+}
+
+void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
+{
+ m_signatures[id] = signature;
+}
+
+ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
+{
+ if (id >= m_enumSignatures.count()) {
+ m_enumSignatures.resize(id + 1);
+ return NULL;
+ } else {
+ return m_enumSignatures[id];
+ }
+}
+
+void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
+{
+ m_enumSignatures[id] = signature;
+}
+
+void TraceLoader::searchNext(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ Q_ASSERT(m_parser.supportsOffsets());
+ if (m_parser.supportsOffsets()) {
+ const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
+ m_parser.setBookmark(frameBookmark.start);
+ Trace::Call *call = 0;
+ while ((call = m_parser.parse_call())) {
+
+ if (callContains(call, str, sensitivity)) {
+ unsigned frameIdx = callInFrame(call->no);
+ ApiTraceFrame *frame = m_createdFrames[frameIdx];
+ const QVector<ApiTraceCall*> calls =
+ fetchFrameContents(frame);
+ for (int i = 0; i < calls.count(); ++i) {
+ if (calls[i]->index() == call->no) {
+ emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
+ break;
+ }
+ }
+ delete call;
+ return;
+ }
+
+ delete call;
+ }
+ }
+ emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+}
+
+void TraceLoader::searchPrev(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ Q_ASSERT(m_parser.supportsOffsets());
+ if (m_parser.supportsOffsets()) {
+ Trace::Call *call = 0;
+ QList<Trace::Call*> frameCalls;
+ int frameIdx = startFrame;
+
+ const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+ int numCallsToParse = frameBookmark.numberOfCalls;
+ m_parser.setBookmark(frameBookmark.start);
+
+ while ((call = m_parser.parse_call())) {
+
+ frameCalls.append(call);
+ --numCallsToParse;
+
+ if (numCallsToParse == 0) {
+ bool foundCall = searchCallsBackwards(frameCalls,
+ frameIdx,
+ str, sensitivity);
+
+ qDeleteAll(frameCalls);
+ frameCalls.clear();
+ if (foundCall) {
+ return;
+ }
+
+ --frameIdx;
+
+ if (frameIdx >= 0) {
+ const FrameBookmark &frameBookmark =
+ m_frameBookmarks[frameIdx];
+ m_parser.setBookmark(frameBookmark.start);
+ numCallsToParse = frameBookmark.numberOfCalls;
+ }
+ }
+ }
+ }
+ emit searchResult(ApiTrace::SearchResult_NotFound, 0);
+}
+
+bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
+ int frameIdx,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ for (int i = calls.count() - 1; i >= 0; --i) {
+ Trace::Call *call = calls[i];
+ if (callContains(call, str, sensitivity)) {
+ ApiTraceFrame *frame = m_createdFrames[frameIdx];
+ const QVector<ApiTraceCall*> apiCalls =
+ fetchFrameContents(frame);
+ for (int i = 0; i < apiCalls.count(); ++i) {
+ if (apiCalls[i]->index() == call->no) {
+ emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
+ break;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+int TraceLoader::callInFrame(int callIdx) const
+{
+ unsigned numCalls = 0;
+
+ for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
+ const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+ unsigned firstCall = numCalls;
+ unsigned endCall = numCalls + frameBookmark.numberOfCalls;
+ if (firstCall <= callIdx && endCall > callIdx) {
+ return frameIdx;
+ }
+ numCalls = endCall;
+ }
+ Q_ASSERT(!"call not in the trace");
+ return 0;
+}
+
+bool TraceLoader::callContains(Trace::Call *call,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity)
+{
+ /*
+ * FIXME: do string comparison directly on Trace::Call
+ */
+ ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
+ 0, this);
+ bool result = apiCall->contains(str, sensitivity);
+ delete apiCall;
+ return result;
+}
+
+QVector<ApiTraceCall*>
+TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
+{
+ Q_ASSERT(currentFrame);
+
+ if (currentFrame->isLoaded()) {
+ return currentFrame->calls();
+ }
+
+ if (m_parser.supportsOffsets()) {
+ unsigned frameIdx = currentFrame->number;
+ int numOfCalls = numberOfCallsInFrame(frameIdx);
+
+ if (numOfCalls) {
+ quint64 binaryDataSize = 0;
+ QVector<ApiTraceCall*> calls(numOfCalls);
+ const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+
+ m_parser.setBookmark(frameBookmark.start);
+
+ Trace::Call *call;
+ int parsedCalls = 0;
+ while ((call = m_parser.parse_call())) {
+ ApiTraceCall *apiCall =
+ apiCallFromTraceCall(call, m_helpHash,
+ currentFrame, this);
+ calls[parsedCalls] = apiCall;
+ Q_ASSERT(calls[parsedCalls]);
+ if (apiCall->hasBinaryData()) {
+ QByteArray data =
+ apiCall->arguments()[
+ apiCall->binaryDataIndex()].toByteArray();
+ binaryDataSize += data.size();
+ }
+
+ ++parsedCalls;
+
+ delete call;
+
+ if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
+ break;
+ }
+
+ }
+ assert(parsedCalls == numOfCalls);
+ Q_ASSERT(parsedCalls == calls.size());
+ calls.squeeze();
+
+ Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
+ emit frameContentsLoaded(currentFrame,
+ calls, binaryDataSize);
+ return calls;
+ }
+ }
+ return QVector<ApiTraceCall*>();
+}
+
+void TraceLoader::findFrameStart(ApiTraceFrame *frame)
+{
+ if (!frame->isLoaded()) {
+ loadFrame(frame);
+ }
+ emit foundFrameStart(frame);
+}
+
+void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
+{
+ if (!frame->isLoaded()) {
+ loadFrame(frame);
+ }
+ emit foundFrameEnd(frame);
+}
+
+void TraceLoader::findCallIndex(int index)
+{
+ int frameIdx = callInFrame(index);
+ ApiTraceFrame *frame = m_createdFrames[frameIdx];
+ QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
+ QVector<ApiTraceCall*>::const_iterator itr;
+ ApiTraceCall *call = 0;
+ for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
+ if ((*itr)->index() == index) {
+ call = *itr;
+ }
+ }
+ Q_ASSERT(call);
+ emit foundCallIndex(call);
+}
+
+#include "traceloader.moc"
diff --git a/gui/traceloader.h b/gui/traceloader.h
new file mode 100644
index 0000000..4b88ec6
--- /dev/null
+++ b/gui/traceloader.h
@@ -0,0 +1,101 @@
+#ifndef TRACELOADER_H
+#define TRACELOADER_H
+
+
+#include "apitrace.h"
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+
+class TraceLoader : public QObject
+{
+ Q_OBJECT
+public:
+ TraceLoader(QObject *parent=0);
+ ~TraceLoader();
+
+
+ ApiTraceCallSignature *signature(unsigned id);
+ void addSignature(unsigned id, ApiTraceCallSignature *signature);
+
+ ApiTraceEnumSignature *enumSignature(unsigned id);
+ void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature);
+
+public slots:
+ void loadTrace(const QString &filename);
+ void loadFrame(ApiTraceFrame *frame);
+ void setFrameMarker(ApiTrace::FrameMarker marker);
+ void searchNext(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void searchPrev(int startFrame,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ void findFrameStart(ApiTraceFrame *frame);
+ void findFrameEnd(ApiTraceFrame *frame);
+ void findCallIndex(int index);
+
+signals:
+ void startedParsing();
+ void parsed(int percent);
+ void finishedParsing();
+
+ void framesLoaded(const QList<ApiTraceFrame*> &frames);
+ void frameContentsLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize);
+
+ void searchResult(ApiTrace::SearchResult result, ApiTraceCall *call);
+ void foundFrameStart(ApiTraceFrame *frame);
+ void foundFrameEnd(ApiTraceFrame *frame);
+ void foundCallIndex(ApiTraceCall *call);
+private:
+ struct FrameBookmark {
+ FrameBookmark()
+ : numberOfCalls(0)
+ {}
+ FrameBookmark(const Trace::ParseBookmark &s)
+ : start(s),
+ numberOfCalls(0)
+ {}
+
+ Trace::ParseBookmark start;
+ int numberOfCalls;
+ };
+ bool isCallAFrameMarker(const Trace::Call *call) const;
+ int numberOfFrames() const;
+ int numberOfCallsInFrame(int frameIdx) const;
+
+ void loadHelpFile();
+ void scanTrace();
+ void parseTrace();
+
+ int callInFrame(int callIdx) const;
+ bool callContains(Trace::Call *call,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+ QVector<ApiTraceCall*> fetchFrameContents(ApiTraceFrame *frame);
+ bool searchCallsBackwards(const QList<Trace::Call*> &calls,
+ int frameIdx,
+ const QString &str,
+ Qt::CaseSensitivity sensitivity);
+
+private:
+ Trace::Parser m_parser;
+ QString m_fileName;
+ ApiTrace::FrameMarker m_frameMarker;
+
+ typedef QMap<int, FrameBookmark> FrameBookmarks;
+ FrameBookmarks m_frameBookmarks;
+ QList<ApiTraceFrame*> m_createdFrames;
+
+ QHash<QString, QUrl> m_helpHash;
+
+ QVector<ApiTraceCallSignature*> m_signatures;
+ QVector<ApiTraceEnumSignature*> m_enumSignatures;
+};
+
+#endif
diff --git a/image_pnm.cpp b/image_pnm.cpp
deleted file mode 100644
index 6625f3d..0000000
--- a/image_pnm.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-/**
- * http://en.wikipedia.org/wiki/Netpbm_format
- */
-void
-Image::writePNM(std::ostream &os) const {
- assert(channels == 1 || channels >= 3);
-
- os << (channels == 1 ? "P5" : "P6") << "\n";
- os << width << " " << height << "\n";
- os << "255" << "\n";
-
- const unsigned char *row;
-
- if (channels == 1 || channels == 3) {
- for (row = start(); row != end(); row += stride()) {
- os.write((const char *)row, width*channels);
- }
- } else {
- unsigned char pixel[3] = {0, 0, 0};
- for (row = start(); row != end(); row += stride()) {
- for (unsigned x = 0; x < width; ++x) {
- for (unsigned channel = 0; channel < channels; ++channel) {
- pixel[channel] = row[x*channels + channel];
- }
- os.write((const char *)pixel, sizeof pixel);
- }
- }
- }
-}
-
-
-} /* namespace Image */
diff --git a/scripts/README b/scripts/README
deleted file mode 100644
index 576e48f..0000000
--- a/scripts/README
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory contains several utilitarian scripts for common development
-tasks using apitrace tools.
-
-See their code for more details about their usage.
diff --git a/scripts/highlight.py b/scripts/highlight.py
new file mode 100644
index 0000000..986bd1d
--- /dev/null
+++ b/scripts/highlight.py
@@ -0,0 +1,194 @@
+##########################################################################
+#
+# Copyright 2011 Jose Fonseca
+# Copyright 2008-2009 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+import sys
+import platform
+
+
+class PlainHighlighter:
+ '''Plain formatter'''
+
+ black = None
+ red = None
+ green = None
+ yellow = None
+ blue = None
+ magenta = None
+ cyan = None
+ white = None
+
+ def __init__(self, stream):
+ self.stream = stream
+
+ def write(self, text):
+ self.stream.write(text)
+
+ def flush(self):
+ self.stream.flush()
+
+ def normal(self):
+ pass
+
+ def color(self, color):
+ pass
+
+ def bold(self):
+ pass
+
+ def italic(self):
+ pass
+
+
+class AnsiHighlighter(PlainHighlighter):
+ '''Highlighter for plain-text files which outputs ANSI escape codes. See
+ http://en.wikipedia.org/wiki/ANSI_escape_code for more information
+ concerning ANSI escape codes.
+ '''
+
+ _csi = '\33['
+
+ _normal = '0m'
+ _bold = '1m'
+ _italic = '3m'
+
+ black = 0
+ red = 1
+ green = 2
+ yellow = 3
+ blue = 4
+ magenta = 5
+ cyan = 6
+ white = 7
+
+ def __init__(self, stream):
+ PlainHighlighter.__init__(self, stream)
+ self.isatty = stream.isatty()
+
+ def _escape(self, code):
+ if self.isatty:
+ self.stream.write(self._csi + code)
+
+ def normal(self):
+ self._escape(self._normal)
+
+ def color(self, color):
+ self._escape(str(30 + color) + 'm')
+
+ def bold(self):
+ self._escape(self._bold)
+
+ def italic(self):
+ self._escape(self._italic)
+
+
+class WindowsConsoleHighlighter(PlainHighlighter):
+ '''Highlighter for the Windows Console. See
+ http://code.activestate.com/recipes/496901/ for more information.
+ '''
+
+ INVALID_HANDLE_VALUE = -1
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ STD_ERROR_HANDLE = -12
+
+ FOREGROUND_BLUE = 0x01
+ FOREGROUND_GREEN = 0x02
+ FOREGROUND_RED = 0x04
+ FOREGROUND_INTENSITY = 0x08
+ BACKGROUND_BLUE = 0x10
+ BACKGROUND_GREEN = 0x20
+ BACKGROUND_RED = 0x40
+ BACKGROUND_INTENSITY = 0x80
+
+ COMMON_LVB_LEADING_BYTE = 0x0100
+ COMMON_LVB_TRAILING_BYTE = 0x0200
+ COMMON_LVB_GRID_HORIZONTAL = 0x0400
+ COMMON_LVB_GRID_LVERTICAL = 0x0800
+ COMMON_LVB_GRID_RVERTICAL = 0x1000
+ COMMON_LVB_REVERSE_VIDEO = 0x4000
+ COMMON_LVB_UNDERSCORE = 0x8000
+
+ _normal = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+ _bold = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+ _italic = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+
+ black = 0
+ red = FOREGROUND_RED
+ green = FOREGROUND_GREEN
+ blue = FOREGROUND_BLUE
+ white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
+
+ def __init__(self, stream):
+ PlainHighlighter.__init__(self, stream)
+
+ if stream is sys.stdin:
+ nStdHandle = self.STD_INPUT_HANDLE
+ elif stream is sys.stdout:
+ nStdHandle = self.STD_OUTPUT_HANDLE
+ elif stream is sys.stderr:
+ nStdHandle = self.STD_ERROR_HANDLE
+ else:
+ nStdHandle = None
+
+ if nStdHandle is not None:
+ import ctypes
+ self._handle = ctypes.windll.kernel32.GetStdHandle(nStdHandle)
+ else:
+ self._handle = INVALID_HANDLE_VALUE
+
+ self._attribute = self.white
+
+ def _setAttribute(self, attr):
+ if self._handle != INVALID_HANDLE_VALUE:
+ import ctypes
+ ctypes.windll.kernel32.SetConsoleTextAttribute(self._handle, attr)
+ self._attribute = attr
+
+ def normal(self):
+ self._setAttribute(self._normal)
+
+ def color(self, color):
+ intensity = self._attribute & FOREGROUND_INTENSITY
+ self._setAttribute(color | intensity)
+
+ def bold(self):
+ self._setAttribute(self._attribute | FOREGROUND_INTENSITY)
+
+ def italic(self):
+ pass
+
+
+def Highlighter(stream = sys.stdout):
+ if platform.system() == 'Windows':
+ return WindowsConsoleHighlighter(stream)
+ else:
+ return AnsiHighlighter(stream)
+
+
+__all__ = [
+ 'Highlighter',
+]
diff --git a/scripts/retracediff.py b/scripts/retracediff.py
index b4bad08..0b6a3b0 100755
--- a/scripts/retracediff.py
+++ b/scripts/retracediff.py
@@ -30,14 +30,14 @@
import optparse
import os.path
-import re
-import shutil
import subprocess
import platform
import sys
-import tempfile
+
+from PIL import Image
from snapdiff import Comparer
+from highlight import Highlighter
import jsondiff
@@ -54,10 +54,10 @@ class Setup:
self.args = args
self.env = env
- def retrace(self, snapshot_dir):
+ def retrace(self):
cmd = [
options.retrace,
- '-s', snapshot_dir + os.path.sep,
+ '-s', '-',
'-S', options.snapshot_frequency,
] + self.args
p = subprocess.Popen(cmd, env=self.env, stdout=subprocess.PIPE, stderr=NULL)
@@ -73,16 +73,38 @@ class Setup:
p = subprocess.Popen(cmd, env=self.env, stdout=subprocess.PIPE, stderr=NULL)
state = jsondiff.load(p.stdout)
p.wait()
- return state
+ return state.get('parameters', {})
+
+ def diff_state(self, ref_call_no, src_call_no):
+ '''Compare the state between two calls.'''
+
+ ref_state = self.dump_state(ref_call_no)
+ src_state = self.dump_state(src_call_no)
+ sys.stdout.flush()
+ differ = jsondiff.Differ(sys.stdout)
+ differ.visit(ref_state, src_state)
+ sys.stdout.write('\n')
-def diff_state(setup, ref_call_no, src_call_no):
- ref_state = setup.dump_state(ref_call_no)
- src_state = setup.dump_state(src_call_no)
- sys.stdout.flush()
- differ = jsondiff.Differ(sys.stdout)
- differ.visit(ref_state, src_state)
- sys.stdout.write('\n')
+
+def read_pnm(stream):
+ '''Read a PNM from the stream, and return the image object, and the comment.'''
+
+ magic = stream.readline()
+ if not magic:
+ return None, None
+ assert magic.rstrip() == 'P6'
+ comment = ''
+ line = stream.readline()
+ while line.startswith('#'):
+ comment += line[1:]
+ line = stream.readline()
+ width, height = map(int, line.strip().split())
+ maximum = int(stream.readline().strip())
+ assert maximum == 255
+ data = stream.read(height * width * 3)
+ image = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', 0, 1)
+ return image, comment
def parse_env(optparser, entries):
@@ -115,15 +137,15 @@ def main():
optparser.add_option(
'--ref-env', metavar='NAME=VALUE',
type='string', action='append', dest='ref_env', default=[],
- help='reference environment variable')
+ help='add variable to reference environment')
optparser.add_option(
'--src-env', metavar='NAME=VALUE',
type='string', action='append', dest='src_env', default=[],
- help='reference environment variable')
+ help='add variable to source environment')
optparser.add_option(
'--diff-prefix', metavar='PATH',
type='string', dest='diff_prefix', default='.',
- help='reference environment variable')
+ help='prefix for the difference images')
optparser.add_option(
'-t', '--threshold', metavar='BITS',
type="float", dest="threshold", default=12.0,
@@ -131,7 +153,7 @@ def main():
optparser.add_option(
'-S', '--snapshot-frequency', metavar='FREQUENCY',
type="string", dest="snapshot_frequency", default='draw',
- help="snapshot frequency [default: %default]")
+ help="snapshot frequency: frame, framebuffer, or draw [default: %default]")
(options, args) = optparser.parse_args(sys.argv[1:])
ref_env = parse_env(optparser, options.ref_env)
@@ -142,62 +164,64 @@ def main():
ref_setup = Setup(args, ref_env)
src_setup = Setup(args, src_env)
- image_re = re.compile('^Wrote (.*\.png)$')
+ highligher = Highlighter(sys.stdout)
+
+ highligher.write('call\tprecision\n')
- last_good = -1
last_bad = -1
- ref_snapshot_dir = tempfile.mkdtemp()
+ last_good = 0
+ ref_proc = ref_setup.retrace()
try:
- src_snapshot_dir = tempfile.mkdtemp()
+ src_proc = src_setup.retrace()
try:
- ref_proc = ref_setup.retrace(ref_snapshot_dir)
- try:
- src_proc = src_setup.retrace(src_snapshot_dir)
- try:
- for ref_line in ref_proc.stdout:
- # Get the reference image
- ref_line = ref_line.rstrip()
- mo = image_re.match(ref_line)
- if mo:
- ref_image = mo.group(1)
- for src_line in src_proc.stdout:
- # Get the source image
- src_line = src_line.rstrip()
- mo = image_re.match(src_line)
- if mo:
- src_image = mo.group(1)
-
- root, ext = os.path.splitext(os.path.basename(src_image))
- call_no = int(root)
-
- # Compare the two images
- comparer = Comparer(ref_image, src_image)
- precision = comparer.precision()
-
- sys.stdout.write('%u %f\n' % (call_no, precision))
-
- if precision < options.threshold:
- if options.diff_prefix:
- comparer.write_diff(os.path.join(options.diff_prefix, root + '.diff.png'))
- if last_bad < last_good:
- diff_state(src_setup, last_good, call_no)
- last_bad = call_no
- else:
- last_good = call_no
-
- sys.stdout.flush()
-
- os.unlink(src_image)
- break
- os.unlink(ref_image)
- finally:
- src_proc.terminate()
- finally:
- ref_proc.terminate()
+ while True:
+ # Get the reference image
+ ref_image, ref_comment = read_pnm(ref_proc.stdout)
+ if ref_image is None:
+ break
+
+ # Get the source image
+ src_image, src_comment = read_pnm(src_proc.stdout)
+ if src_image is None:
+ break
+
+ assert ref_comment == src_comment
+
+ call_no = int(ref_comment.strip())
+
+ # Compare the two images
+ comparer = Comparer(ref_image, src_image)
+ precision = comparer.precision()
+
+ mismatch = precision < options.threshold
+
+ if mismatch:
+ highligher.color(highligher.red)
+ highligher.bold()
+ highligher.write('%u\t%f\n' % (call_no, precision))
+ if mismatch:
+ highligher.normal()
+
+ if mismatch:
+ if options.diff_prefix:
+ prefix = os.path.join(options.diff_prefix, '%010u' % call_no)
+ prefix_dir = os.path.dirname(prefix)
+ if not os.path.isdir(prefix_dir):
+ os.makedirs(prefix_dir)
+ ref_image.save(prefix + '.ref.png')
+ src_image.save(prefix + '.src.png')
+ comparer.write_diff(prefix + '.diff.png')
+ if last_bad < last_good:
+ src_setup.diff_state(last_good, call_no)
+ last_bad = call_no
+ else:
+ last_good = call_no
+
+ highligher.flush()
finally:
- shutil.rmtree(ref_snapshot_dir)
+ src_proc.terminate()
finally:
- shutil.rmtree(src_snapshot_dir)
+ ref_proc.terminate()
if __name__ == '__main__':
diff --git a/scripts/snapdiff.py b/scripts/snapdiff.py
index 60d9ae9..0ed3937 100755
--- a/scripts/snapdiff.py
+++ b/scripts/snapdiff.py
@@ -48,8 +48,15 @@ class Comparer:
'''Image comparer.'''
def __init__(self, ref_image, src_image, alpha = False):
- self.ref_im = Image.open(ref_image)
- self.src_im = Image.open(src_image)
+ if isinstance(ref_image, basestring):
+ self.ref_im = Image.open(ref_image)
+ else:
+ self.ref_im = ref_image
+
+ if isinstance(src_image, basestring):
+ self.src_im = Image.open(src_image)
+ else:
+ self.src_im = src_image
# Ignore
if not alpha:
diff --git a/thirdparty/glext/glext.h b/thirdparty/glext/glext.h
index 555e670..0940021 100644
--- a/thirdparty/glext/glext.h
+++ b/thirdparty/glext/glext.h
@@ -6,7 +6,7 @@ extern "C" {
#endif
/*
-** Copyright (c) 2007-2010 The Khronos Group Inc.
+** Copyright (c) 2007-2011 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
@@ -29,9 +29,9 @@ extern "C" {
*/
/* Header file version number, required by OpenGL ABI for Linux */
-/* glext.h last updated $Date: 2011-06-06 12:06:38 -0700 (Mon, 06 Jun 2011) $ */
+/* glext.h last updated $Date: 2011-08-08 00:34:29 -0700 (Mon, 08 Aug 2011) $ */
/* Current version at http://www.opengl.org/registry/ */
-#define GL_GLEXT_VERSION 70
+#define GL_GLEXT_VERSION 72
/* Function declaration macros - to move into glplatform.h */
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
@@ -1047,6 +1047,124 @@ extern "C" {
/* reuse GL_UNDEFINED_VERTEX */
#endif
+#ifndef GL_VERSION_4_2
+/* Reuse tokens from ARB_base_instance (none) */
+/* Reuse tokens from ARB_shading_language_420pack (none) */
+/* Reuse tokens from ARB_transform_feedback_instanced (none) */
+/* Reuse tokens from ARB_compressed_texture_pixel_storage */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */
+/* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */
+/* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */
+/* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */
+/* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */
+/* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */
+/* Reuse tokens from ARB_conservative_depth (none) */
+/* Reuse tokens from ARB_internalformat_query */
+/* reuse GL_NUM_SAMPLE_COUNTS */
+/* Reuse tokens from ARB_map_buffer_alignment */
+/* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */
+/* Reuse tokens from ARB_shader_atomic_counters */
+/* reuse GL_ATOMIC_COUNTER_BUFFER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_START */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */
+/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */
+/* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */
+/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */
+/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */
+/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */
+/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */
+/* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */
+/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */
+/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */
+/* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */
+/* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */
+/* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */
+/* Reuse tokens from ARB_shader_image_load_store */
+/* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */
+/* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */
+/* reuse GL_UNIFORM_BARRIER_BIT */
+/* reuse GL_TEXTURE_FETCH_BARRIER_BIT */
+/* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */
+/* reuse GL_COMMAND_BARRIER_BIT */
+/* reuse GL_PIXEL_BUFFER_BARRIER_BIT */
+/* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */
+/* reuse GL_BUFFER_UPDATE_BARRIER_BIT */
+/* reuse GL_FRAMEBUFFER_BARRIER_BIT */
+/* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */
+/* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */
+/* reuse GL_ALL_BARRIER_BITS */
+/* reuse GL_MAX_IMAGE_UNITS */
+/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */
+/* reuse GL_IMAGE_BINDING_NAME */
+/* reuse GL_IMAGE_BINDING_LEVEL */
+/* reuse GL_IMAGE_BINDING_LAYERED */
+/* reuse GL_IMAGE_BINDING_LAYER */
+/* reuse GL_IMAGE_BINDING_ACCESS */
+/* reuse GL_IMAGE_1D */
+/* reuse GL_IMAGE_2D */
+/* reuse GL_IMAGE_3D */
+/* reuse GL_IMAGE_2D_RECT */
+/* reuse GL_IMAGE_CUBE */
+/* reuse GL_IMAGE_BUFFER */
+/* reuse GL_IMAGE_1D_ARRAY */
+/* reuse GL_IMAGE_2D_ARRAY */
+/* reuse GL_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_INT_IMAGE_1D */
+/* reuse GL_INT_IMAGE_2D */
+/* reuse GL_INT_IMAGE_3D */
+/* reuse GL_INT_IMAGE_2D_RECT */
+/* reuse GL_INT_IMAGE_CUBE */
+/* reuse GL_INT_IMAGE_BUFFER */
+/* reuse GL_INT_IMAGE_1D_ARRAY */
+/* reuse GL_INT_IMAGE_2D_ARRAY */
+/* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_INT_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_1D */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D */
+/* reuse GL_UNSIGNED_INT_IMAGE_3D */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */
+/* reuse GL_UNSIGNED_INT_IMAGE_CUBE */
+/* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */
+/* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */
+/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */
+/* reuse GL_MAX_IMAGE_SAMPLES */
+/* reuse GL_IMAGE_BINDING_FORMAT */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */
+/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */
+/* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */
+/* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */
+/* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */
+/* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */
+/* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */
+/* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */
+/* Reuse tokens from ARB_shading_language_packing (none) */
+/* Reuse tokens from ARB_texture_storage */
+/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
+#endif
+
#ifndef GL_ARB_multitexture
#define GL_TEXTURE0_ARB 0x84C0
#define GL_TEXTURE1_ARB 0x84C1
@@ -2140,6 +2258,143 @@ extern "C" {
#ifndef GL_ARB_shader_stencil_export
#endif
+#ifndef GL_ARB_base_instance
+#endif
+
+#ifndef GL_ARB_shading_language_420pack
+#endif
+
+#ifndef GL_ARB_transform_feedback_instanced
+#endif
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
+#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
+#endif
+
+#ifndef GL_ARB_conservative_depth
+#endif
+
+#ifndef GL_ARB_internalformat_query
+#define GL_NUM_SAMPLE_COUNTS 0x9380
+#endif
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
+#endif
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
+#endif
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_IMAGE_BINDING_NAME 0x8F3A
+#define GL_IMAGE_BINDING_LEVEL 0x8F3B
+#define GL_IMAGE_BINDING_LAYERED 0x8F3C
+#define GL_IMAGE_BINDING_LAYER 0x8F3D
+#define GL_IMAGE_BINDING_ACCESS 0x8F3E
+#define GL_IMAGE_1D 0x904C
+#define GL_IMAGE_2D 0x904D
+#define GL_IMAGE_3D 0x904E
+#define GL_IMAGE_2D_RECT 0x904F
+#define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_BUFFER 0x9051
+#define GL_IMAGE_1D_ARRAY 0x9052
+#define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#define GL_IMAGE_2D_MULTISAMPLE 0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+#define GL_INT_IMAGE_1D 0x9057
+#define GL_INT_IMAGE_2D 0x9058
+#define GL_INT_IMAGE_3D 0x9059
+#define GL_INT_IMAGE_2D_RECT 0x905A
+#define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_BUFFER 0x905C
+#define GL_INT_IMAGE_1D_ARRAY 0x905D
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_MAX_IMAGE_SAMPLES 0x906D
+#define GL_IMAGE_BINDING_FORMAT 0x906E
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
+#endif
+
+#ifndef GL_ARB_shading_language_packing
+#endif
+
+#ifndef GL_ARB_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
+#endif
+
#ifndef GL_EXT_abgr
#define GL_ABGR_EXT 0x8000
#endif
@@ -5053,6 +5308,11 @@ extern "C" {
#ifndef GL_AMD_multi_draw_indirect
#endif
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA
+#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB
+#endif
+
/*************************************************************/
@@ -5912,7 +6172,7 @@ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB,
#ifndef GL_VERSION_4_1
#define GL_VERSION_4_1 1
-/* OpenGL 4.1 also reuses entry points from these extensions: */
+/* OpenGL 4.1 reuses entry points from these extensions: */
/* ARB_ES2_compatibility */
/* ARB_get_program_binary */
/* ARB_separate_shader_objects */
@@ -5921,6 +6181,22 @@ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB,
/* ARB_viewport_array */
#endif
+#ifndef GL_VERSION_4_2
+#define GL_VERSION_4_2 1
+/* OpenGL 4.2 reuses entry points from these extensions: */
+/* ARB_base_instance */
+/* ARB_shading_language_420pack (no entry points) */
+/* ARB_transform_feedback_instanced */
+/* ARB_compressed_texture_pixel_storage (no entry points) */
+/* ARB_conservative_depth (no entry points) */
+/* ARB_internalformat_query */
+/* ARB_map_buffer_alignment (no entry points) */
+/* ARB_shader_atomic_counters */
+/* ARB_shader_image_load_store */
+/* ARB_shading_language_packing (no entry points) */
+/* ARB_texture_storage */
+#endif
+
#ifndef GL_ARB_multitexture
#define GL_ARB_multitexture 1
#ifdef GL_GLEXT_PROTOTYPES
@@ -6846,6 +7122,10 @@ typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum
typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
#endif
+#ifndef GL_ARB_shader_bit_encoding
+#define GL_ARB_shader_bit_encoding 1
+#endif
+
#ifndef GL_ARB_texture_rgb10_a2ui
#define GL_ARB_texture_rgb10_a2ui 1
#endif
@@ -7352,6 +7632,92 @@ typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint locati
#define GL_ARB_shader_stencil_export 1
#endif
+#ifndef GL_ARB_base_instance
+#define GL_ARB_base_instance 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
+#endif
+
+#ifndef GL_ARB_shading_language_420pack
+#define GL_ARB_shading_language_420pack 1
+#endif
+
+#ifndef GL_ARB_transform_feedback_instanced
+#define GL_ARB_transform_feedback_instanced 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount);
+GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei primcount);
+#endif
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_ARB_compressed_texture_pixel_storage 1
+#endif
+
+#ifndef GL_ARB_conservative_depth
+#define GL_ARB_conservative_depth 1
+#endif
+
+#ifndef GL_ARB_internalformat_query
+#define GL_ARB_internalformat_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+#endif
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_ARB_map_buffer_alignment 1
+#endif
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ARB_shader_atomic_counters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_ARB_shader_image_load_store 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
+#endif
+
+#ifndef GL_ARB_shading_language_packing
+#define GL_ARB_shading_language_packing 1
+#endif
+
+#ifndef GL_ARB_texture_storage
+#define GL_ARB_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
#ifndef GL_EXT_abgr
#define GL_EXT_abgr 1
#endif
@@ -11110,6 +11476,10 @@ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const
typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
#endif
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_EXT_framebuffer_multisample_blit_scaled 1
+#endif
+
#ifdef __cplusplus
}