diff options
author | José Fonseca <jose.r.fonseca@gmail.com> | 2011-09-23 08:33:13 +0100 |
---|---|---|
committer | José Fonseca <jose.r.fonseca@gmail.com> | 2011-09-23 08:33:13 +0100 |
commit | ae2b4d32ed56e3ac193cc7205aeb58082c448ce8 (patch) | |
tree | 7225d26bd1400dacb64ed680fd1514611f6cf025 | |
parent | af7d231ddf7f7fef342782932e85479044de1757 (diff) | |
parent | 892cad6f24175221d2e7bdf3c7fe6c34b64ee50a (diff) |
Merge branch 'master' into d3d10
Conflicts:
CMakeLists.txt
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | BUGS.markdown | 115 | ||||
-rwxr-xr-x | CMakeLists.txt | 70 | ||||
-rw-r--r-- | INSTALL.markdown | 69 | ||||
-rw-r--r-- | NEWS.markdown | 34 | ||||
-rw-r--r-- | README.markdown | 258 | ||||
-rw-r--r-- | TODO.markdown | 8 | ||||
-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.cpp | 112 | ||||
-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.cpp | 139 | ||||
-rw-r--r-- | common/trace_loader.hpp | 65 | ||||
-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.py | 52 | ||||
-rw-r--r-- | d3d8.py | 25 | ||||
-rw-r--r-- | d3d8trace.py | 52 | ||||
-rw-r--r-- | d3d9.py | 25 | ||||
-rw-r--r-- | d3d9trace.py | 51 | ||||
-rw-r--r-- | ddraw.py | 1 | ||||
-rw-r--r-- | ddrawtrace.py | 81 | ||||
-rw-r--r-- | glapi.py | 123 | ||||
-rw-r--r-- | glparams.py | 284 | ||||
-rw-r--r-- | glretrace.hpp | 1 | ||||
-rw-r--r-- | glretrace.py | 50 | ||||
-rw-r--r-- | glretrace_main.cpp | 35 | ||||
-rw-r--r-- | glsize.hpp | 4 | ||||
-rw-r--r-- | glstate.cpp | 4 | ||||
-rw-r--r-- | glstate.py | 13 | ||||
-rw-r--r-- | gltypes.py | 19 | ||||
-rw-r--r-- | glxapi.py | 4 | ||||
-rw-r--r-- | gui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | gui/apicalldelegate.cpp | 2 | ||||
-rw-r--r-- | gui/apisurface.cpp | 1 | ||||
-rw-r--r-- | gui/apitrace.cpp | 381 | ||||
-rw-r--r-- | gui/apitrace.h | 68 | ||||
-rw-r--r-- | gui/apitracecall.cpp | 275 | ||||
-rw-r--r-- | gui/apitracecall.h | 113 | ||||
-rw-r--r-- | gui/apitracefilter.cpp | 6 | ||||
-rw-r--r-- | gui/apitracefilter.h | 1 | ||||
-rw-r--r-- | gui/apitracemodel.cpp | 131 | ||||
-rw-r--r-- | gui/apitracemodel.h | 8 | ||||
-rw-r--r-- | gui/argumentseditor.cpp | 20 | ||||
-rw-r--r-- | gui/argumentseditor.h | 2 | ||||
-rw-r--r-- | gui/loaderthread.cpp | 112 | ||||
-rw-r--r-- | gui/loaderthread.h | 34 | ||||
-rw-r--r-- | gui/main.cpp | 8 | ||||
-rw-r--r-- | gui/mainwindow.cpp | 450 | ||||
-rw-r--r-- | gui/mainwindow.h | 22 | ||||
-rw-r--r-- | gui/retracer.cpp | 18 | ||||
-rw-r--r-- | gui/retracer.h | 16 | ||||
-rw-r--r-- | gui/saverthread.cpp | 180 | ||||
-rw-r--r-- | gui/saverthread.h | 12 | ||||
-rw-r--r-- | gui/traceloader.cpp | 496 | ||||
-rw-r--r-- | gui/traceloader.h | 101 | ||||
-rw-r--r-- | image_pnm.cpp | 67 | ||||
-rw-r--r-- | scripts/README | 4 | ||||
-rw-r--r-- | scripts/highlight.py | 194 | ||||
-rwxr-xr-x | scripts/retracediff.py | 158 | ||||
-rwxr-xr-x | scripts/snapdiff.py | 11 | ||||
-rw-r--r-- | thirdparty/glext/glext.h | 378 |
79 files changed, 4569 insertions, 1321 deletions
@@ -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_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 @@ -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) @@ -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) + @@ -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) + @@ -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) @@ -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); @@ -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); @@ -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) @@ -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 +]) + @@ -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>" + " " + "<span style=\"font-style:italic;font-size:small;font-weight:lighter;\"> " + "(%2 calls)</span>") + .arg(number) + .arg(m_loaded ? m_calls.count() : m_callsToLoad); //mark the frame if it uploads more than a meg a frame if (m_binaryDataSize > (1024*1024)) { richText = QObject::tr( - "<span style=\"font-weight:bold;\">" - "Frame %1</span>" + "%1" "<span style=\"font-style:italic;\">" " (%2MB)</span>") - .arg(number) + .arg(richText) .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2); - } else { - richText = - QObject::tr( - "<span style=\"font-weight:bold\">Frame %1</span>") - .arg(number); } if (!m_staticText) @@ -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 ®exp); 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) <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) Frame ") - .arg(frame->number); - int binaryDataSize = frame->binaryDataSize() / 1024; - if (frame->state().isEmpty()) - return QObject::tr( - "<b>%1 </b>(binary data size = %2kB)") - .arg(text) - .arg(binaryDataSize); - else - return QObject::tr( - "<b>%1 (binary data size = %2kB)</b>" - "<br/>%3") - .arg(text) - .arg(binaryDataSize) - .arg(stateText); + QString thumbStr, sizeStr; + + if (frame->hasState()) { + static const char *imgTempl = + "<img style=\"float:left;\" " + "src=\"data:image/png;base64,%1\"/>\n"; + static const char *sizeTempl = + ", %1kb"; + + ApiFramebuffer fbo = frame->state()->colorBuffer(); + QImage thumb = fbo.thumb(); + if (!thumb.isNull()) { + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + thumb.save(&buffer, "PNG"); + thumbStr = tr(imgTempl).arg( + QString(buffer.data().toBase64())); + } + + int binaryDataSize = frame->binaryDataSize() / 1024; + if (binaryDataSize > 0) { + sizeStr = tr(sizeTempl).arg(binaryDataSize); + } + } + + int numCalls = frame->isLoaded() + ? frame->numChildren() + : frame->numChildrenToLoad(); + + return tr(htmlTempl) + .arg(thumbStr) + .arg(frame->number) + .arg(numCalls) + .arg(sizeStr); } } case ApiTraceModel::EventRole: @@ -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 } |