From: José Fonseca Date: Wed, 6 Mar 2013 11:46:41 +0000 (+0000) Subject: Merge branch 'directxtex' X-Git-Url: https://git.notmuchmail.org/git?a=commitdiff_plain;h=d7c738e13decf8a8a891008c51b437ccbe3434fb;hp=1e40126d7a03c43538a07e37e2e63d8882c07e7c;p=apitrace Merge branch 'directxtex' --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 46514aa..3b932e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,8 +106,8 @@ else (WIN32) endif () if (MSVC) - # C99 includes for msvc - include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/msvc) + # C99 includes for MSVC + include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/msinttypes) # Enable math constants defines add_definitions (-D_USE_MATH_DEFINES) @@ -181,6 +181,42 @@ endif () set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +############################################################################## +# Installation directories + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # Debian multiarch support + execute_process(COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH + OUTPUT_VARIABLE ARCH_SUBDIR + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + CHECK_INCLUDE_FILES(proc/readproc.h READPROC_H_FOUND) + if (READPROC_H_FOUND) + add_definitions (-DHAVE_READPROC_H) + endif () +endif() + +if (WIN32 OR APPLE) + # On Windows/MacOSX, applications are usually installed on a directory of + # their own + set (DOC_INSTALL_DIR doc) + set (LIB_INSTALL_DIR lib) + set (LIB_ARCH_INSTALL_DIR lib) +else () + set (DOC_INSTALL_DIR share/doc/${CMAKE_PROJECT_NAME}) + set (LIB_INSTALL_DIR lib/${CMAKE_PROJECT_NAME}) + if (ARCH_SUBDIR) + set (LIB_ARCH_INSTALL_DIR lib/${ARCH_SUBDIR}/${CMAKE_PROJECT_NAME}) + else () + set (LIB_ARCH_INSTALL_DIR lib/${CMAKE_PROJECT_NAME}) + endif () +endif () + +set (SCRIPTS_INSTALL_DIR ${LIB_INSTALL_DIR}/scripts) +set (WRAPPER_INSTALL_DIR ${LIB_ARCH_INSTALL_DIR}/wrappers) + + ############################################################################## # Bundled dependencies # @@ -191,13 +227,13 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set (ZLIB_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/zlib) set (ZLIB_LIBRARIES z_bundled) -add_subdirectory (thirdparty/zlib EXCLUDE_FROM_ALL) +add_subdirectory (thirdparty/zlib) include_directories (${ZLIB_INCLUDE_DIRS}) set (SNAPPY_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/snappy) set (SNAPPY_LIBRARIES snappy_bundled) -add_subdirectory (thirdparty/snappy EXCLUDE_FROM_ALL) +add_subdirectory (thirdparty/snappy) include_directories (${SNAPPY_INCLUDE_DIRS}) @@ -205,10 +241,10 @@ set (PNG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/libpng) set (PNG_DEFINITIONS "") set (PNG_LIBRARIES png_bundled) -add_subdirectory (thirdparty/libpng EXCLUDE_FROM_ALL) +add_subdirectory (thirdparty/libpng) if (MSVC) - add_subdirectory (thirdparty/getopt EXCLUDE_FROM_ALL) + add_subdirectory (thirdparty/getopt) include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/getopt) set (GETOPT_LIBRARIES getopt_bundled) endif () @@ -224,7 +260,7 @@ endif () # binaries at all. if (QT4_FOUND) add_definitions (-DQJSON_EXPORT=) - add_subdirectory (thirdparty/qjson EXCLUDE_FROM_ALL) + add_subdirectory (thirdparty/qjson) set (QJSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty) set (QJSON_LIBRARY_DIRS) set (QJSON_LIBRARIES qjson_bundled) @@ -238,51 +274,6 @@ endif () include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/khronos) -############################################################################## -# Installation directories - -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - # Debian multiarch support - execute_process(COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH - OUTPUT_VARIABLE ARCH_SUBDIR - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif() - -if (WIN32 OR APPLE) - # On Windows/MacOSX, applications are usually installed on a directory of - # their own - set (DOC_INSTALL_DIR doc) - set (LIB_INSTALL_DIR lib) - set (LIB_ARCH_INSTALL_DIR lib) -else () - set (DOC_INSTALL_DIR share/doc/${CMAKE_PROJECT_NAME}) - set (LIB_INSTALL_DIR lib/${CMAKE_PROJECT_NAME}) - if (ARCH_SUBDIR) - set (LIB_ARCH_INSTALL_DIR lib/${ARCH_SUBDIR}/${CMAKE_PROJECT_NAME}) - else () - set (LIB_ARCH_INSTALL_DIR lib/${CMAKE_PROJECT_NAME}) - endif () -endif () - -set (SCRIPTS_INSTALL_DIR ${LIB_INSTALL_DIR}/scripts) -set (WRAPPER_INSTALL_DIR ${LIB_ARCH_INSTALL_DIR}/wrappers) - -# Expose the binary/install directories to source -# -# TODO: Use the same directory layout, for both build and install directories, -# so that binaries can find each other using just relative paths. -# -add_definitions( - -DAPITRACE_BINARY_DIR="${CMAKE_BINARY_DIR}" - -DAPITRACE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" - -DAPITRACE_PROGRAMS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/bin" - -DAPITRACE_SCRIPTS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${SCRIPTS_INSTALL_DIR}" - -DAPITRACE_WRAPPERS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${WRAPPER_INSTALL_DIR}" -) - - ############################################################################## # Common libraries / utilities @@ -362,11 +353,22 @@ endif () install ( PROGRAMS - ${CMAKE_CURRENT_SOURCE_DIR}/scripts/tracediff.py - ${CMAKE_CURRENT_SOURCE_DIR}/scripts/jsondiff.py - ${CMAKE_CURRENT_SOURCE_DIR}/scripts/snapdiff.py + scripts/highlight.py + scripts/jsondiff.py + scripts/profileshader.py + scripts/retracediff.py + scripts/snapdiff.py + scripts/tracecheck.py + scripts/tracediff.py + scripts/unpickle.py DESTINATION ${SCRIPTS_INSTALL_DIR} ) +if (WIN32) + install ( + PROGRAMS scripts/convert.py + DESTINATION ${SCRIPTS_INSTALL_DIR} + ) +endif () ############################################################################## # GUI @@ -382,11 +384,22 @@ endif () install ( FILES BUGS.markdown - LICENSE NEWS.markdown README.markdown DESTINATION ${DOC_INSTALL_DIR} ) +install ( + FILES LICENSE + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE.txt +) +if (MSVC) + install ( + FILES thirdparty/msinttypes/LICENSE + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-msinttypes.txt + ) +endif () set (CPACK_PACKAGE_VERSION_MAJOR "3") set (CPACK_PACKAGE_VERSION_MINOR "0") diff --git a/INSTALL.markdown b/INSTALL.markdown index 2228bdf..ed965b1 100644 --- a/INSTALL.markdown +++ b/INSTALL.markdown @@ -70,6 +70,10 @@ Build as: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/android.toolchain.cmake -DANDROID_API_LEVEL=9 -H. -Bbuild make -C build +You can also choose a particular ABI by passing `ANDROID_ABI` variable to +cmake, e.g., `-DANDROID_ABI=x86`. + + Windows ------- diff --git a/NEWS.markdown b/NEWS.markdown index 53a3f0f..736ec34 100644 --- a/NEWS.markdown +++ b/NEWS.markdown @@ -17,7 +17,7 @@ Version 3.0 * Top-level `apitrace` command. -* Trace and retrace support for EGL, GLES1, and GLES2 APIs on Linux. +* Trace and replay support for EGL, GLES1, and GLES2 APIs on Linux. * Ability to trim traces. @@ -57,4 +57,4 @@ Version 1.0 Pre-history =========== -* OpenGL retrace support. +* OpenGL replay support. diff --git a/README.markdown b/README.markdown index b1eb083..5fa3ab9 100644 --- a/README.markdown +++ b/README.markdown @@ -5,7 +5,7 @@ About **apitrace** * trace OpenGL, OpenGL ES, Direct3D, and DirectDraw APIs calls to a file; -* retrace OpenGL and OpenGL ES calls from a file; +* replay OpenGL and OpenGL ES calls from a file; * inspect OpenGL state at any call while retracing; @@ -18,7 +18,7 @@ Obtaining **apitrace** ====================== To obtain apitrace either [download the latest -binaries](https://github.com/apitrace/apitrace/downloads) for your platform if +binaries](http://apitrace.github.com/#download) for your platform if available, or follow the instructions in INSTALL.markdown to build it yourself. On 64bits Linux and Windows platforms you'll need apitrace binaries that match the architecture (32bits or 64bits) of the application being traced. @@ -49,10 +49,10 @@ View the trace with Replay an OpenGL trace with - apitrace retrace application.trace + apitrace replay application.trace Pass the `--sb` option to use a single buffered visual. Pass `--help` to -`apitrace retrace` for more options. +`apitrace replay` for more options. Basic GUI usage @@ -152,10 +152,9 @@ To trace the application inside gdb, invoke gdb as: ### Android ### The following instructions should work at least for Android Ice Scream -Sandwitch: +Sandwitch. -For standalone applications the instructions above for Linux should -work. To trace applications started from within the Android VM process +To trace applications started from within the Android VM process (`app_process` aka zygote) you'll have to wrap this process and enable tracing dynamically for the application to be traced. @@ -206,6 +205,15 @@ tracing dynamically for the application to be traced. Launch the application for example from the application menu. +To trace standalone applications do: + + adb push /path/to/apitrace/build/wrappers/egltrace.so /data + adb shell + # cd /data/local/tmp + # LD_PRELOAD=/data/egltrace.so test-opengl-gl2_basic + adb pull /data/local/tmp/test-opengl-gl2_basic.trace + apitrace replay test-opengl-gl2_basic.trace + ### Mac OS X ### Run the application you want to trace as @@ -302,7 +310,7 @@ Dump GL state at a particular call You can get a dump of the bound GL state at call 12345 by doing: - apitrace retrace -D 12345 application.trace > 12345.json + apitrace replay -D 12345 application.trace > 12345.json This is precisely the mechanism the GUI obtains its own state. @@ -359,7 +367,7 @@ table which displays profiling results per shader. For example, to record all profiling data and utilise the per shader script: - apitrace retrace --pgpu --pcpu --ppd foo.trace | ./scripts/profileshader.py + apitrace replay --pgpu --pcpu --ppd foo.trace | ./scripts/profileshader.py Advanced usage for OpenGL implementors diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index a01d3ae..5f8e116 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,3 +1,14 @@ +# Expose the binary/install directories to source +# +# TODO: Use the same directory layout, for both build and install directories, +# so that binaries can find each other using just relative paths. +# +add_definitions( + -DAPITRACE_PROGRAMS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/bin" + -DAPITRACE_SCRIPTS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${SCRIPTS_INSTALL_DIR}" + -DAPITRACE_WRAPPERS_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${WRAPPER_INSTALL_DIR}" +) + add_executable (apitrace cli_main.cpp cli_diff.cpp @@ -12,6 +23,7 @@ add_executable (apitrace cli_trace.cpp cli_trim.cpp cli_resources.cpp + trace_analyzer.cpp ) target_link_libraries (apitrace diff --git a/cli/cli_dump_images.cpp b/cli/cli_dump_images.cpp index 0e2dd8c..86cf75c 100644 --- a/cli/cli_dump_images.cpp +++ b/cli/cli_dump_images.cpp @@ -29,6 +29,8 @@ #include #include // for CHAR_MAX #include + +#include #include #include "os_string.hpp" @@ -44,17 +46,20 @@ usage(void) std::cout << "usage apitrace dump-images [OPTIONS] TRACE_FILE\n" << synopsis << "\n" "\n" - " -h, --help show this help message and exit\n" - " --calls=CALLSET dump images only for specified calls\n" - " (default value is \"*/frame\" which\n" - " which dumps an image for each frame)\n" - " -o, --output=PREFIX prefix to use in naming output files\n" - " (default is trace filename without extension)\n" + " -h, --help show this help message and exit\n" + " --calls=CALLSET dump images only for specified calls\n" + " (default value is \"*/frame\" which\n" + " which dumps an image for each frame)\n" + " --call-nos[=BOOL] use call numbers in image filenames,\n" + " otherwise use sequental numbers (default=yes)\n" + " -o, --output=PREFIX prefix to use in naming output files\n" + " (default is trace filename without extension)\n" "\n"; } enum { CALLS_OPT = CHAR_MAX + 1, + CALL_NOS_OPT, }; const static char * @@ -64,6 +69,7 @@ const static struct option longOptions[] = { {"help", no_argument, 0, 'h'}, {"calls", required_argument, 0, CALLS_OPT}, + {"call-nos", optional_argument, 0, CALL_NOS_OPT}, {"output", required_argument, 0, 'o'}, {0, 0, 0, 0} }; @@ -75,6 +81,7 @@ command(int argc, char *argv[]) const char *calls = NULL; const char *traceName = NULL; const char *output = NULL; + std::string call_nos; int opt; while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) { @@ -85,6 +92,10 @@ command(int argc, char *argv[]) case CALLS_OPT: calls = optarg; break; + case CALL_NOS_OPT: + call_nos = "--call-nos="; + call_nos.append(optarg); + break; case 'o': output = optarg; break; @@ -126,6 +137,9 @@ command(int argc, char *argv[]) opts.push_back(calls); else opts.push_back("*/frame"); + if (!call_nos.empty()) { + opts.push_back(call_nos.c_str()); + } return executeRetrace(opts, traceName); } diff --git a/cli/cli_main.cpp b/cli/cli_main.cpp index 040adcf..d6db619 100644 --- a/cli/cli_main.cpp +++ b/cli/cli_main.cpp @@ -79,6 +79,18 @@ static const Command * commands[] = { &help_command }; +/* Aliases provide a mechanism to allow compatibility with old command + * names (such as "retrace") for current commands (such as the replay + * command). */ +typedef struct { + const char *name; + const Command *command; +} Alias; + +static const Alias aliases[] = { + { "retrace", &retrace_command } +}; + static void usage(void) { @@ -151,6 +163,7 @@ main(int argc, char **argv) { const char *command_name; const Command *command; + const Alias *alias; int i; for (i = 1; i < argc; ++i) { @@ -186,6 +199,13 @@ main(int argc, char **argv) return (command->function) (argc, argv); } + for (i = 0; i < ARRAY_SIZE(aliases); i++) { + alias = &aliases[i]; + + if (strcmp(command_name, alias->name) == 0) + return (alias->command->function) (argc, argv); + } + std::cerr << "Error: unknown command " << command_name << " (see \"apitrace help\").\n"; diff --git a/cli/cli_retrace.cpp b/cli/cli_retrace.cpp index d22f719..db799b9 100644 --- a/cli/cli_retrace.cpp +++ b/cli/cli_retrace.cpp @@ -144,7 +144,7 @@ command(int argc, char *argv[]) } const Command retrace_command = { - "retrace", + "replay", synopsis, usage, command diff --git a/cli/cli_trace.cpp b/cli/cli_trace.cpp index 2646ffd..f87a383 100644 --- a/cli/cli_trace.cpp +++ b/cli/cli_trace.cpp @@ -133,6 +133,7 @@ traceProgram(trace::API api, } #if defined(_WIN32) + useInject = true; if (useInject) { args.push_back("inject"); args.push_back(wrapperPath); @@ -219,7 +220,7 @@ usage(void) " -v, --verbose verbose output\n" " -a, --api=API specify API to trace (" #ifdef _WIN32 - "gl, d3d7, d3d8, d3d9, or d3d10" + "gl, d3d7, d3d8, d3d9, or dxgi (for d3d10 and higher) " #else "gl or egl" #endif diff --git a/cli/cli_trim.cpp b/cli/cli_trim.cpp index eea5553..5625a2c 100644 --- a/cli/cli_trim.cpp +++ b/cli/cli_trim.cpp @@ -24,15 +24,18 @@ * **************************************************************************/ - +#include #include #include // for CHAR_MAX #include +#include + #include "cli.hpp" #include "os_string.hpp" +#include "trace_analyzer.hpp" #include "trace_callset.hpp" #include "trace_parser.hpp" #include "trace_writer.hpp" @@ -46,53 +49,350 @@ usage(void) << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n" << synopsis << "\n" "\n" - " -h, --help show this help message and exit\n" - " --calls=CALLSET only retain specified calls\n" - " --thread=THREAD_ID only retain calls from specified thread\n" - " -o, --output=TRACE_FILE output trace file\n" + " -h, --help Show detailed help for trim options and exit\n" + " --calls=CALLSET Include specified calls in the trimmed output.\n" + " --frames=FRAMESET Include specified frames in the trimmed output.\n" + " --deps Include additional calls to satisfy dependencies\n" + " --prune Omit uninteresting calls from the trace output\n" + " -a, --auto Trim automatically to calls specified in --calls/--frames\n" + " Equivalent to both --deps and --prune\n" + " --print-callset Print the final set of calls included in output\n" + " --trim-spec=SPEC Only performing trimming as described in SPEC\n" + " --thread=THREAD_ID Only retain calls from specified thread\n" + " -o, --output=TRACE_FILE Output trace file\n" + ; +} + +static void +help() +{ + std::cout + << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n" + << synopsis << "\n" + "\n" + " -h, --help Show this help message and exit\n" + "\n" + " --calls=CALLSET Include specified calls in the trimmed output.\n" + " --frames=FRAMESET Include specified frames in the trimmed output.\n" + "\n" + " --deps Perform dependency analysis and include dependent\n" + " calls as needed, (even if those calls were not\n" + " explicitly requested with --calls or --frames).\n" + "\n" + " --prune Omit calls with no side effects, even if the call\n" + " is within the range specified by --calls/--frames.\n" + "\n" + " -a, --auto Use dependency analysis and pruning\n" + " of uninteresting calls the resulting trace may\n" + " include more and less calls than specified.\n" + " This option is equivalent\n" + " to passing both --deps and --prune.\n" + "\n" + " --print-callset Print to stdout the final set of calls included\n" + " in the trim output. This can be useful for\n" + " tweaking the trimmed callset from --auto on the\n" + " command-line.\n" + " Use --calls=@FILE to read callset from a file.\n" + " --trim-spec=SPEC Specifies which classes of calls will be trimmed.\n" + " This option only has an effect if dependency\n" + " analysis is enabled. The argument is a comma-\n" + " separated list of names from the following:\n" + "\n" + " no-side-effects Calls with no side effects\n" + " textures Calls to setup unused textures\n" + " shaders Calls to setup unused shaders\n" + " drawing Calls that draw\n" + "\n" + " The default trim specification includes all of\n" + " the above, (as much as possible will be trimmed).\n" + "\n" + " --thread=THREAD_ID Only retain calls from specified thread\n" + "\n" + " -o, --output=TRACE_FILE Output trace file\n" "\n" ; } enum { CALLS_OPT = CHAR_MAX + 1, + FRAMES_OPT, + DEPS_OPT, + PRUNE_OPT, THREAD_OPT, + PRINT_CALLSET_OPT, + TRIM_SPEC_OPT }; const static char * -shortOptions = "ho:"; +shortOptions = "aho:x"; const static struct option longOptions[] = { {"help", no_argument, 0, 'h'}, {"calls", required_argument, 0, CALLS_OPT}, + {"frames", required_argument, 0, FRAMES_OPT}, + {"deps", no_argument, 0, DEPS_OPT}, + {"prune", no_argument, 0, PRUNE_OPT}, + {"auto", no_argument, 0, 'a'}, {"thread", required_argument, 0, THREAD_OPT}, {"output", required_argument, 0, 'o'}, + {"print-callset", no_argument, 0, PRINT_CALLSET_OPT}, + {"trim-spec", required_argument, 0, TRIM_SPEC_OPT}, {0, 0, 0, 0} }; +struct stringCompare { + bool operator() (const char *a, const char *b) const { + return strcmp(a, b) < 0; + } +}; + +struct trim_options { + /* Calls to be included in trace. */ + trace::CallSet calls; + + /* Frames to be included in trace. */ + trace::CallSet frames; + + /* Whether dependency analysis should be performed. */ + bool dependency_analysis; + + /* Whether uninteresting calls should be pruned.. */ + bool prune_uninteresting; + + /* Output filename */ + std::string output; + + /* Emit only calls from this thread (-1 == all threads) */ + int thread; + + /* Print resulting callset */ + int print_callset; + + /* What kind of trimming to perform. */ + TrimFlags trim_flags; +}; + +static int +trim_trace(const char *filename, struct trim_options *options) +{ + trace::ParseBookmark beginning; + trace::Parser p; + TraceAnalyzer analyzer(options->trim_flags); + std::set *required; + unsigned frame; + int call_range_first, call_range_last; + + if (!p.open(filename)) { + std::cerr << "error: failed to open " << filename << "\n"; + return 1; + } + + /* Mark the beginning so we can return here for pass 2. */ + p.getBookmark(beginning); + + /* In pass 1, analyze which calls are needed. */ + frame = 0; + trace::Call *call; + while ((call = p.parse_call())) { + + /* There's no use doing any work past the last call or frame + * requested by the user. */ + if (call->no > options->calls.getLast() || + frame > options->frames.getLast()) { + + delete call; + break; + } + + /* If requested, ignore all calls not belonging to the specified thread. */ + if (options->thread != -1 && call->thread_id != options->thread) { + goto NEXT; + } + + /* Also, prune if uninteresting (unless the user asked for no pruning. */ + if (options->prune_uninteresting && call->flags & trace::CALL_FLAG_VERBOSE) { + goto NEXT; + } + + /* If this call is included in the user-specified call set, + * then require it (and all dependencies) in the trimmed + * output. */ + if (options->calls.contains(*call) || + options->frames.contains(frame, call->flags)) { + + analyzer.require(call); + } + + /* Regardless of whether we include this call or not, we do + * some dependency tracking (unless disabled by the user). We + * do this even for calls we have included in the output so + * that any state updates get performed. */ + if (options->dependency_analysis) { + analyzer.analyze(call); + } + + NEXT: + if (call->flags & trace::CALL_FLAG_END_FRAME) + frame++; + + delete call; + } + + /* Prepare output file and writer for output. */ + if (options->output.empty()) { + os::String base(filename); + base.trimExtension(); + + options->output = std::string(base.str()) + std::string("-trim.trace"); + } + + trace::Writer writer; + if (!writer.open(options->output.c_str())) { + std::cerr << "error: failed to create " << filename << "\n"; + return 1; + } + + /* Reset bookmark for pass 2. */ + p.setBookmark(beginning); + + /* In pass 2, emit the calls that are required. */ + required = analyzer.get_required(); + + frame = 0; + call_range_first = -1; + call_range_last = -1; + while ((call = p.parse_call())) { + + /* There's no use doing any work past the last call or frame + * requested by the user. */ + if (call->no > options->calls.getLast() || + frame > options->frames.getLast()) { + + break; + } + + if (required->find(call->no) != required->end()) { + writer.writeCall(call); + + if (options->print_callset) { + if (call_range_first < 0) { + call_range_first = call->no; + printf ("%d", call_range_first); + } else if (call->no != call_range_last + 1) { + if (call_range_last != call_range_first) + printf ("-%d", call_range_last); + call_range_first = call->no; + printf (",%d", call_range_first); + } + call_range_last = call->no; + } + } + + if (call->flags & trace::CALL_FLAG_END_FRAME) { + frame++; + } + + delete call; + } + + if (options->print_callset) { + if (call_range_last != call_range_first) + printf ("-%d\n", call_range_last); + } + + std::cerr << "Trimmed trace is available as " << options->output << "\n"; + + return 0; +} + +static int +parse_trim_spec(const char *trim_spec, TrimFlags *flags) +{ + std::string spec(trim_spec), word; + size_t start = 0, comma = 0; + *flags = 0; + + while (start < spec.size()) { + comma = spec.find(',', start); + + if (comma == std::string::npos) + word = std::string(spec, start); + else + word = std::string(spec, start, comma - start); + + if (strcmp(word.c_str(), "no-side-effects") == 0) + *flags |= TRIM_FLAG_NO_SIDE_EFFECTS; + else if (strcmp(word.c_str(), "textures") == 0) + *flags |= TRIM_FLAG_TEXTURES; + else if (strcmp(word.c_str(), "shaders") == 0) + *flags |= TRIM_FLAG_SHADERS; + else if (strcmp(word.c_str(), "drawing") == 0) + *flags |= TRIM_FLAG_DRAWING; + else { + return 1; + } + + if (comma == std::string::npos) + break; + + start = comma + 1; + } + + return 0; +} + static int command(int argc, char *argv[]) { - std::string output; - trace::CallSet calls(trace::FREQUENCY_ALL); - int thread = -1; - int i; + struct trim_options options; + + options.calls = trace::CallSet(trace::FREQUENCY_NONE); + options.frames = trace::CallSet(trace::FREQUENCY_NONE); + options.dependency_analysis = false; + options.prune_uninteresting = false; + options.output = ""; + options.thread = -1; + options.print_callset = 0; + options.trim_flags = -1; int opt; while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) { switch (opt) { case 'h': - usage(); + help(); return 0; case CALLS_OPT: - calls = trace::CallSet(optarg); + options.calls = trace::CallSet(optarg); + break; + case FRAMES_OPT: + options.frames = trace::CallSet(optarg); + break; + case DEPS_OPT: + options.dependency_analysis = true; + break; + case PRUNE_OPT: + options.prune_uninteresting = true; + break; + case 'a': + options.dependency_analysis = true; + options.prune_uninteresting = true; break; case THREAD_OPT: - thread = atoi(optarg); + options.thread = atoi(optarg); break; case 'o': - output = optarg; + options.output = optarg; + break; + case PRINT_CALLSET_OPT: + options.print_callset = 1; + break; + case TRIM_SPEC_OPT: + if (parse_trim_spec(optarg, &options.trim_flags)) { + std::cerr << "error: illegal value for trim-spec: " << optarg << "\n"; + std::cerr << "See \"apitrace help trim\" for help.\n"; + return 1; + } break; default: std::cerr << "error: unexpected option `" << opt << "`\n"; @@ -101,49 +401,42 @@ command(int argc, char *argv[]) } } + /* If neither of --calls nor --frames was set, default to the + * entire set of calls. */ + if (options.calls.empty() && options.frames.empty()) { + options.calls = trace::CallSet(trace::FREQUENCY_ALL); + } + if (optind >= argc) { std::cerr << "error: apitrace trim requires a trace file as an argument.\n"; usage(); return 1; } - for (i = optind; i < argc; ++i) { - trace::Parser p; - if (!p.open(argv[i])) { - return 1; - } - - if (output.empty()) { - os::String base(argv[i]); - base.trimExtension(); - - output = std::string(base.str()) + std::string("-trim.trace"); - } - - trace::Writer writer; - if (!writer.open(output.c_str())) { - std::cerr << "error: failed to create " << argv[i] << "\n"; - return 1; - } - - trace::Call *call; - while ((call = p.parse_call())) { - if (calls.contains(*call) && - (thread == -1 || call->thread_id == thread)) { - writer.writeCall(call); - } - delete call; + if (argc > optind + 1) { + std::cerr << "error: extraneous arguments:"; + for (int i = optind + 1; i < argc; i++) { + std::cerr << " " << argv[i]; } + std::cerr << "\n"; + usage(); + return 1; + } - std::cout << "Trimmed trace is available as " << output << "\n"; + if (options.dependency_analysis) { + std::cerr << + "Note: The dependency analysis in \"apitrace trim\" is still experimental.\n" + " We hope that it will be useful, but it may lead to incorrect results.\n" + " If you find a trace that misbehaves while trimming, please share that\n" + " by sending email to apitrace@lists.freedesktop.org, cworth@cworth.org\n"; } - return 0; + return trim_trace(argv[optind], &options); } const Command trim_command = { "trim", synopsis, - usage, + help, command }; diff --git a/cli/trace_analyzer.cpp b/cli/trace_analyzer.cpp new file mode 100644 index 0000000..730dab9 --- /dev/null +++ b/cli/trace_analyzer.cpp @@ -0,0 +1,773 @@ +/************************************************************************** + * Copyright 2012 Intel corporation + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include + +#include "trace_analyzer.hpp" + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define STRNCMP_LITERAL(var, literal) strncmp((var), (literal), sizeof (literal) -1) + +/* Rendering often has no side effects, but it can in some cases, +* (such as when transform feedback is active, or when rendering +* targets a framebuffer object). */ +bool +TraceAnalyzer::renderingHasSideEffect(void) +{ + return transformFeedbackActive || framebufferObjectActive; +} + +/* Provide: Record that the given call affects the given resource + * as a side effect. */ +void +TraceAnalyzer::provide(std::string resource, trace::CallNo call_no) +{ + resources[resource].insert(call_no); +} + +/* Like provide, but with a simply-formatted string, (appending an + * integer to the given string). */ +void +TraceAnalyzer::providef(std::string resource, + int resource_no, + trace::CallNo call_no) +{ + std::stringstream ss; + ss << resource << resource_no; + provide(ss.str(), call_no); +} + +/* Link: Establish a dependency between resource 'resource' and + * resource 'dependency'. This dependency is captured by name so + * that if the list of calls that provide 'dependency' grows + * before 'resource' is consumed, those calls will still be + * captured. */ +void +TraceAnalyzer::link(std::string resource, std::string dependency) +{ + dependencies[resource].insert(dependency); +} + +/* Like link, but with a simply-formatted string, (appending an + * integer to the given string). */ +void +TraceAnalyzer::linkf(std::string resource, std::string dependency, int dep_no) +{ + + std::stringstream ss; + ss << dependency << dep_no; + link(resource, ss.str()); +} + +/* Unlink: Remove dependency from 'resource' on 'dependency'. */ +void +TraceAnalyzer::unlink(std::string resource, std::string dependency) +{ + dependencies[resource].erase(dependency); + if (dependencies[resource].size() == 0) { + dependencies.erase(resource); + } +} + +/* Like unlink, but with a simply-formated string, (appending an + * integer to the given string). */ +void +TraceAnalyzer::unlinkf(std::string resource, std::string dependency, int dep_no) +{ + + std::stringstream ss; + ss << dependency << dep_no; + unlink(resource, ss.str()); +} + +/* Unlink all: Remove dependencies from 'resource' to all other + * resources. */ +void +TraceAnalyzer::unlinkAll(std::string resource) +{ + dependencies.erase(resource); +} + +/* Resolve: Recursively compute all calls providing 'resource', + * (including linked dependencies of 'resource' on other + * resources). */ +std::set +TraceAnalyzer::resolve(std::string resource) +{ + std::set *deps; + std::set::iterator dep; + + std::set *calls; + std::set::iterator call; + + std::set result, deps_set; + + /* Recursively chase dependencies. */ + if (dependencies.count(resource)) { + deps = &dependencies[resource]; + for (dep = deps->begin(); dep != deps->end(); dep++) { + deps_set = resolve(*dep); + for (call = deps_set.begin(); call != deps_set.end(); call++) { + result.insert(*call); + } + } + } + + /* Also look for calls that directly provide 'resource' */ + if (resources.count(resource)) { + calls = &resources[resource]; + for (call = calls->begin(); call != calls->end(); call++) { + result.insert(*call); + } + } + + return result; +} + +/* Consume: Resolve all calls that provide the given resource, and + * add them to the required list. Then clear the call list for + * 'resource' along with any dependencies. */ +void +TraceAnalyzer::consume(std::string resource) +{ + + std::set calls; + std::set::iterator call; + + calls = resolve(resource); + + dependencies.erase(resource); + resources.erase(resource); + + for (call = calls.begin(); call != calls.end(); call++) { + required.insert(*call); + } +} + +void +TraceAnalyzer::stateTrackPreCall(trace::Call *call) +{ + + const char *name = call->name(); + + if (strcmp(name, "glBegin") == 0) { + insideBeginEnd = true; + return; + } + + if (strcmp(name, "glBeginTransformFeedback") == 0) { + transformFeedbackActive = true; + return; + } + + if (strcmp(name, "glActiveTexture") == 0) { + activeTextureUnit = static_cast(call->arg(0).toSInt()); + return; + } + + if (strcmp(name, "glBindTexture") == 0) { + GLenum target; + GLuint texture; + + target = static_cast(call->arg(0).toSInt()); + texture = call->arg(1).toUInt(); + + if (texture == 0) { + texture_map.erase(target); + } else { + texture_map[target] = texture; + } + + return; + } + + if (strcmp(name, "glUseProgram") == 0) { + activeProgram = call->arg(0).toUInt(); + } + + if (strcmp(name, "glBindFramebuffer") == 0) { + GLenum target; + GLuint framebuffer; + + target = static_cast(call->arg(0).toSInt()); + framebuffer = call->arg(1).toUInt(); + + if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) { + if (framebuffer == 0) { + framebufferObjectActive = false; + } else { + framebufferObjectActive = true; + } + } + return; + } + + if (strcmp(name, "glNewList") == 0) { + GLuint list = call->arg(0).toUInt(); + + insideNewEndList = list; + } +} + +void +TraceAnalyzer::stateTrackPostCall(trace::Call *call) +{ + + const char *name = call->name(); + + if (strcmp(name, "glEnd") == 0) { + insideBeginEnd = false; + return; + } + + if (strcmp(name, "glEndTransformFeedback") == 0) { + transformFeedbackActive = false; + return; + } + + /* If this swapbuffers was included in the trace then it will + * have already consumed all framebuffer dependencies. If not, + * then clear them now so that they don't carry over into the + * next frame. */ + if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET && + call->flags & trace::CALL_FLAG_END_FRAME) { + dependencies.erase("framebuffer"); + resources.erase("framebuffer"); + return; + } + + if (strcmp(name, "glEndList") == 0) { + insideNewEndList = 0; + } +} + +bool +TraceAnalyzer::callHasNoSideEffects(trace::Call *call, const char *name) +{ + /* If call is flagged as no side effects, then we are done here. */ + if (call->flags & trace::CALL_FLAG_NO_SIDE_EFFECTS) { + return true; + } + + /* Similarly, swap-buffers calls don't have interesting side effects. */ + if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET && + call->flags & trace::CALL_FLAG_END_FRAME) { + return true; + } + + /* Not known as a no-side-effect call. Return false for more analysis. */ + return false; +} + +bool +TraceAnalyzer::recordTextureSideEffects(trace::Call *call, const char *name) +{ + if (strcmp(name, "glGenTextures") == 0) { + const trace::Array *textures = dynamic_cast(&call->arg(1)); + size_t i; + GLuint texture; + + if (textures) { + for (i = 0; i < textures->size(); i++) { + texture = textures->values[i]->toUInt(); + providef("texture-", texture, call->no); + } + } + return true; + } + + /* FIXME: When we start tracking framebuffer objects as their own + * resources, we will want to link the FBO to the given texture + * resource, (and to this call). For now, just link render state + * to the texture, and force this call to be required. */ + if (strcmp(name, "glFramebufferTexture2D") == 0) { + GLuint texture; + + texture = call->arg(3).toUInt(); + + linkf("render-state", "texture-", texture); + + provide("state", call->no); + } + + if (strcmp(name, "glBindTexture") == 0) { + GLenum target; + GLuint texture; + + std::stringstream ss_target, ss_texture; + + target = static_cast(call->arg(0).toSInt()); + texture = call->arg(1).toUInt(); + + ss_target << "texture-unit-" << activeTextureUnit << "-target-" << target; + ss_texture << "texture-" << texture; + + resources.erase(ss_target.str()); + provide(ss_target.str(), call->no); + + unlinkAll(ss_target.str()); + link(ss_target.str(), ss_texture.str()); + + /* FIXME: This really shouldn't be necessary. The effect + * this provide() has is that all glBindTexture calls will + * be preserved in the output trace (never trimmed). Carl + * has a trace ("btr") where a glBindTexture call should + * not be necessary at all, (it's immediately followed + * with a glBindTexture to a different texture and no + * intervening texture-related calls), yet this 'provide' + * makes the difference between a trim_stress test failing + * and passing. + * + * More investigation is necessary, but for now, be + * conservative and don't trim. */ + provide("state", call->no); + + return true; + } + + /* FIXME: Need to handle glMultiTexImage and friends. */ + if (STRNCMP_LITERAL(name, "glTexImage") == 0 || + STRNCMP_LITERAL(name, "glTexSubImage") == 0 || + STRNCMP_LITERAL(name, "glCopyTexImage") == 0 || + STRNCMP_LITERAL(name, "glCopyTexSubImage") == 0 || + STRNCMP_LITERAL(name, "glCompressedTexImage") == 0 || + STRNCMP_LITERAL(name, "glCompressedTexSubImage") == 0 || + strcmp(name, "glInvalidateTexImage") == 0 || + strcmp(name, "glInvalidateTexSubImage") == 0) { + + std::set *calls; + std::set::iterator c; + std::stringstream ss_target, ss_texture; + + GLenum target = static_cast(call->arg(0).toSInt()); + + ss_target << "texture-unit-" << activeTextureUnit << "-target-" << target; + ss_texture << "texture-" << texture_map[target]; + + /* The texture resource depends on this call and any calls + * providing the given texture target. */ + provide(ss_texture.str(), call->no); + + if (resources.count(ss_target.str())) { + calls = &resources[ss_target.str()]; + for (c = calls->begin(); c != calls->end(); c++) { + provide(ss_texture.str(), *c); + } + } + + return true; + } + + if (strcmp(name, "glEnable") == 0) { + GLenum cap; + + cap = static_cast(call->arg(0).toSInt()); + + if (cap == GL_TEXTURE_1D || + cap == GL_TEXTURE_2D || + cap == GL_TEXTURE_3D || + cap == GL_TEXTURE_CUBE_MAP) + { + std::stringstream ss; + + ss << "texture-unit-" << activeTextureUnit << "-target-" << cap; + + link("render-state", ss.str()); + } + + provide("state", call->no); + return true; + } + + if (strcmp(name, "glDisable") == 0) { + GLenum cap; + + cap = static_cast(call->arg(0).toSInt()); + + if (cap == GL_TEXTURE_1D || + cap == GL_TEXTURE_2D || + cap == GL_TEXTURE_3D || + cap == GL_TEXTURE_CUBE_MAP) + { + std::stringstream ss; + + ss << "texture-unit-" << activeTextureUnit << "-target-" << cap; + + unlink("render-state", ss.str()); + } + + provide("state", call->no); + return true; + } + + /* No known texture-related side effects. Return false for more analysis. */ + return false; +} + +bool +TraceAnalyzer::recordShaderSideEffects(trace::Call *call, const char *name) +{ + if (strcmp(name, "glCreateShader") == 0 || + strcmp(name, "glCreateShaderObjectARB") == 0) { + + GLuint shader = call->ret->toUInt(); + providef("shader-", shader, call->no); + return true; + } + + if (strcmp(name, "glShaderSource") == 0 || + strcmp(name, "glShaderSourceARB") == 0 || + strcmp(name, "glCompileShader") == 0 || + strcmp(name, "glCompileShaderARB") == 0 || + strcmp(name, "glGetShaderiv") == 0 || + strcmp(name, "glGetShaderInfoLog") == 0) { + + GLuint shader = call->arg(0).toUInt(); + providef("shader-", shader, call->no); + return true; + } + + if (strcmp(name, "glCreateProgram") == 0 || + strcmp(name, "glCreateProgramObjectARB") == 0) { + + GLuint program = call->ret->toUInt(); + providef("program-", program, call->no); + return true; + } + + if (strcmp(name, "glAttachShader") == 0 || + strcmp(name, "glAttachObjectARB") == 0) { + + GLuint program, shader; + std::stringstream ss_program, ss_shader; + + program = call->arg(0).toUInt(); + shader = call->arg(1).toUInt(); + + ss_program << "program-" << program; + ss_shader << "shader-" << shader; + + link(ss_program.str(), ss_shader.str()); + provide(ss_program.str(), call->no); + + return true; + } + + if (strcmp(name, "glDetachShader") == 0 || + strcmp(name, "glDetachObjectARB") == 0) { + + GLuint program, shader; + std::stringstream ss_program, ss_shader; + + program = call->arg(0).toUInt(); + shader = call->arg(1).toUInt(); + + ss_program << "program-" << program; + ss_shader << "shader-" << shader; + + unlink(ss_program.str(), ss_shader.str()); + + return true; + } + + if (strcmp(name, "glUseProgram") == 0 || + strcmp(name, "glUseProgramObjectARB") == 0) { + + GLuint program; + + program = call->arg(0).toUInt(); + + unlinkAll("render-program-state"); + + if (program == 0) { + unlink("render-state", "render-program-state"); + provide("state", call->no); + } else { + std::stringstream ss; + + ss << "program-" << program; + + link("render-state", "render-program-state"); + link("render-program-state", ss.str()); + + provide(ss.str(), call->no); + } + + return true; + } + + if (strcmp(name, "glGetUniformLocation") == 0 || + strcmp(name, "glGetUniformLocationARB") == 0 || + strcmp(name, "glGetFragDataLocation") == 0 || + strcmp(name, "glGetFragDataLocationEXT") == 0 || + strcmp(name, "glGetSubroutineUniformLocation") == 0 || + strcmp(name, "glGetProgramResourceLocation") == 0 || + strcmp(name, "glGetProgramResourceLocationIndex") == 0 || + strcmp(name, "glGetVaryingLocationNV") == 0) { + + GLuint program = call->arg(0).toUInt(); + + providef("program-", program, call->no); + + return true; + } + + /* For any call that accepts 'location' as its first argument, + * perform a lookup in our location->program map and add a + * dependence on the program we find there. */ + if (call->sig->num_args > 0 && + strcmp(call->sig->arg_names[0], "location") == 0) { + + providef("program-", activeProgram, call->no); + + /* We can't easily tell if this uniform is being used to + * associate a sampler in the shader with a texture + * unit. The conservative option is to assume that it is + * and create a link from the active program to any bound + * textures for the given unit number. + * + * FIXME: We should be doing the same thing for calls to + * glUniform1iv. */ + if (strcmp(name, "glUniform1i") == 0 || + strcmp(name, "glUniform1iARB") == 0) { + + GLint max_unit = MAX(GL_MAX_TEXTURE_COORDS, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); + + GLint unit = call->arg(1).toSInt(); + std::stringstream ss_program; + std::stringstream ss_texture; + + if (unit < max_unit) { + + ss_program << "program-" << activeProgram; + + ss_texture << "texture-unit-" << GL_TEXTURE0 + unit << "-target-"; + + /* We don't know what target(s) might get bound to + * this texture unit, so conservatively link to + * all. Only bound textures will actually get inserted + * into the output call stream. */ + linkf(ss_program.str(), ss_texture.str(), GL_TEXTURE_1D); + linkf(ss_program.str(), ss_texture.str(), GL_TEXTURE_2D); + linkf(ss_program.str(), ss_texture.str(), GL_TEXTURE_3D); + linkf(ss_program.str(), ss_texture.str(), GL_TEXTURE_CUBE_MAP); + } + } + + return true; + } + + /* FIXME: We cut a huge swath by assuming that any unhandled + * call that has a first argument named "program" should not + * be included in the trimmed output unless the program of + * that number is also included. + * + * This heuristic is correct for many cases, but we should + * actually carefully verify if this includes some calls + * inappropriately, or if it misses some. + */ + if (strcmp(name, "glLinkProgram") == 0 || + strcmp(name, "glLinkProgramARB") == 0 || + (call->sig->num_args > 0 && + (strcmp(call->sig->arg_names[0], "program") == 0 || + strcmp(call->sig->arg_names[0], "programObj") == 0))) { + + GLuint program = call->arg(0).toUInt(); + providef("program-", program, call->no); + return true; + } + + /* No known shader-related side effects. Return false for more analysis. */ + return false; +} + +bool +TraceAnalyzer::recordDrawingSideEffects(trace::Call *call, const char *name) +{ + /* Handle all rendering operations, (even though only glEnd is + * flagged as a rendering operation we treat everything from + * glBegin through glEnd as a rendering operation). */ + if (call->flags & trace::CALL_FLAG_RENDER || + insideBeginEnd) { + + std::set calls; + std::set::iterator c; + + provide("framebuffer", call->no); + + calls = resolve("render-state"); + + for (c = calls.begin(); c != calls.end(); c++) { + provide("framebuffer", *c); + } + + /* In some cases, rendering has side effects beyond the + * framebuffer update. */ + if (renderingHasSideEffect()) { + provide("state", call->no); + for (c = calls.begin(); c != calls.end(); c++) { + provide("state", *c); + } + } + + return true; + } + + /* Though it's not flagged as a "RENDER" operation, we also want + * to trim swapbuffers calls when trimming drawing operations. */ + if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET && + call->flags & trace::CALL_FLAG_END_FRAME) { + return true; + } + + /* No known drawing-related side effects. Return false for more analysis. */ + return false; +} + +void +TraceAnalyzer::recordSideEffects(trace::Call *call) +{ + + const char *name = call->name(); + + /* FIXME: If we encode the list of commands that are executed + * immediately (as opposed to those that are compiled into a + * display list) then we could generate a "display-list-X" + * resource just as we do for "texture-X" resources and only + * emit it in the trace if a glCallList(X) is emitted. For + * now, simply punt and include anything within glNewList and + * glEndList in the trim output. This guarantees that display + * lists will work, but does not trim out unused display + * lists. */ + if (insideNewEndList != 0) { + provide("state", call->no); + + /* Also, any texture bound inside a display list is + * conservatively considered required. */ + if (strcmp(name, "glBindTexture") == 0) { + GLuint texture = call->arg(1).toUInt(); + + linkf("state", "texture-", texture); + } + + return; + } + + if (trimFlags & TRIM_FLAG_NO_SIDE_EFFECTS) { + + if (callHasNoSideEffects(call, name)) { + return; + } + } + + if (trimFlags & TRIM_FLAG_TEXTURES) { + + if (recordTextureSideEffects(call, name)) { + return; + } + } + + if (trimFlags & TRIM_FLAG_SHADERS) { + + if (recordShaderSideEffects(call, name)) { + return; + } + } + + if (trimFlags & TRIM_FLAG_DRAWING) { + + if (recordDrawingSideEffects(call, name)) { + return; + } + } + + /* By default, assume this call affects the state somehow. */ + resources["state"].insert(call->no); +} + +void +TraceAnalyzer::requireDependencies(trace::Call *call) +{ + + /* Swap-buffers calls depend on framebuffer state. */ + if (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET && + call->flags & trace::CALL_FLAG_END_FRAME) { + consume("framebuffer"); + } + + /* By default, just assume this call depends on generic state. */ + consume("state"); +} + +TraceAnalyzer::TraceAnalyzer(TrimFlags trimFlagsOpt = -1): + transformFeedbackActive(false), + framebufferObjectActive(false), + insideBeginEnd(false), + insideNewEndList(0), + activeTextureUnit(GL_TEXTURE0), + trimFlags(trimFlagsOpt) +{ + /* Nothing needed. */ +} + +TraceAnalyzer::~TraceAnalyzer() +{ + /* Nothing needed. */ +} + +/* Analyze this call by tracking state and recording all the + * resources provided by this call as side effects.. */ +void +TraceAnalyzer::analyze(trace::Call *call) +{ + + stateTrackPreCall(call); + + recordSideEffects(call); + + stateTrackPostCall(call); +} + +/* Require this call and all of its dependencies to be included in + * the final trace. */ +void +TraceAnalyzer::require(trace::Call *call) +{ + + /* First, find and insert all calls that this call depends on. */ + requireDependencies(call); + + /* Then insert this call itself. */ + required.insert(call->no); +} + +/* Return a set of all the required calls, (both those calls added + * explicitly with require() and those implicitly depended + * upon. */ +std::set * +TraceAnalyzer::get_required(void) +{ + return &required; +} diff --git a/cli/trace_analyzer.hpp b/cli/trace_analyzer.hpp new file mode 100644 index 0000000..ef89ad7 --- /dev/null +++ b/cli/trace_analyzer.hpp @@ -0,0 +1,113 @@ +/************************************************************************** + * Copyright 2012 Intel corporation + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include + +#include +#include + +#include "trace_callset.hpp" +#include "trace_parser.hpp" + +typedef unsigned TrimFlags; + +/** + * Trim flags + */ +enum { + + /* Whether to trim calls that have no side effects. */ + TRIM_FLAG_NO_SIDE_EFFECTS = (1 << 0), + + /* Whether to trim calls to setup textures that are never used. */ + TRIM_FLAG_TEXTURES = (1 << 1), + + /* Whether to trim calls to setup shaders that are never used. */ + TRIM_FLAG_SHADERS = (1 << 2), + + /* Whether to trim drawing operations outside of the desired call-set. */ + TRIM_FLAG_DRAWING = (1 << 3), +}; + +class TraceAnalyzer { +private: + std::map > resources; + std::map > dependencies; + + std::map texture_map; + + std::set required; + + bool transformFeedbackActive; + bool framebufferObjectActive; + bool insideBeginEnd; + GLuint insideNewEndList; + GLenum activeTextureUnit; + GLuint activeProgram; + unsigned int trimFlags; + + void provide(std::string resource, trace::CallNo call_no); + void providef(std::string resource, int resource_no, trace::CallNo call_no); + + void link(std::string resource, std::string dependency); + void linkf(std::string resource, std::string dependency, int dep_no); + + void unlink(std::string resource, std::string dependency); + void unlinkf(std::string resource, std::string dependency, int dep_no); + void unlinkAll(std::string resource); + + void stateTrackPreCall(trace::Call *call); + + void recordSideEffects(trace::Call *call); + bool callHasNoSideEffects(trace::Call *call, const char *name); + bool recordTextureSideEffects(trace::Call *call, const char *name); + bool recordShaderSideEffects(trace::Call *call, const char *name); + bool recordDrawingSideEffects(trace::Call *call, const char *name); + + void stateTrackPostCall(trace::Call *call); + + bool renderingHasSideEffect(void); + std::set resolve(std::string resource); + + void consume(std::string resource); + void requireDependencies(trace::Call *call); + +public: + TraceAnalyzer(TrimFlags trimFlags); + ~TraceAnalyzer(); + + /* Analyze this call by tracking state and recording all the + * resources provided by this call as side effects.. */ + void analyze(trace::Call *call); + + /* Require this call and all of its dependencies to be included in + * the final trace. */ + void require(trace::Call *call); + + /* Return a set of all the required calls, (both those calls added + * explicitly with require() and those implicitly depended + * upon. */ + std::set *get_required(void); +}; diff --git a/common/os_memory.hpp b/common/os_memory.hpp new file mode 100644 index 0000000..4774412 --- /dev/null +++ b/common/os_memory.hpp @@ -0,0 +1,67 @@ +/************************************************************************** + * + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Shuang He + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +/* + * Simple OS time measurement abstraction. + */ + +#ifndef _OS_MEMORY_HPP_ +#define _OS_MEMORY_HPP_ + +#ifdef HAVE_READPROC_H +#include + +namespace os { + inline long long + getVsize(void) { + proc_t proc; + look_up_our_self(&proc); + return proc.vsize; + } + + inline long long + getRss(void) { + proc_t proc; + look_up_our_self(&proc); + return proc.rss; + } +} /* namespace os */ + +#else +namespace os { + inline long long + getVsize(void) { + return 0; + } + + inline long long + getRss(void) { + return 0; + } +} /* namespace os */ +#endif + +#endif /* _OS_MEMORY_HPP_ */ diff --git a/common/os_thread.hpp b/common/os_thread.hpp index 9dc656e..2c3f732 100644 --- a/common/os_thread.hpp +++ b/common/os_thread.hpp @@ -312,7 +312,7 @@ namespace os { DWORD id = 0; _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id); #else - pthread_create(&_native_handle, NULL, ( void *(*) (void *))f, arg); + pthread_create(&_native_handle, NULL, (void *(*) (void *))f, (void *)arg); #endif } diff --git a/common/trace_callset.cpp b/common/trace_callset.cpp index 3c33087..93d145f 100644 --- a/common/trace_callset.cpp +++ b/common/trace_callset.cpp @@ -224,7 +224,7 @@ public: }; -CallSet::CallSet(const char *string) +CallSet::CallSet(const char *string): limits(std::numeric_limits::min(), std::numeric_limits::max()) { if (*string == '@') { FileCallSetParser parser(*this, &string[1]); @@ -236,7 +236,7 @@ CallSet::CallSet(const char *string) } -CallSet::CallSet(CallFlags freq) { +CallSet::CallSet(CallFlags freq): limits(std::numeric_limits::min(), std::numeric_limits::max()) { if (freq != FREQUENCY_NONE) { CallNo start = std::numeric_limits::min(); CallNo stop = std::numeric_limits::max(); diff --git a/common/trace_callset.hpp b/common/trace_callset.hpp index b679d94..4a4a52d 100644 --- a/common/trace_callset.hpp +++ b/common/trace_callset.hpp @@ -48,6 +48,7 @@ #define _TRACE_CALLSET_HPP_ +#include #include #include "trace_model.hpp" @@ -106,12 +107,15 @@ namespace trace { // A collection of call ranges class CallSet { + private: + CallRange limits; + public: // TODO: use binary tree to speed up lookups typedef std::list< CallRange > RangeList; RangeList ranges; - CallSet() {} + CallSet(): limits(std::numeric_limits::min(), std::numeric_limits::max()) {} CallSet(CallFlags freq); @@ -128,6 +132,16 @@ namespace trace { if (range.start <= range.stop && range.freq != FREQUENCY_NONE) { + if (empty()) { + limits.start = range.start; + limits.stop = range.stop; + } else { + if (range.start < limits.start) + limits.start = range.start; + if (range.stop > limits.stop) + limits.stop = range.stop; + } + RangeList::iterator it = ranges.begin(); while (it != ranges.end() && it->start < range.start) { ++it; @@ -155,6 +169,14 @@ namespace trace { contains(const trace::Call &call) { return contains(call.no, call.flags); } + + CallNo getFirst() { + return limits.start; + } + + CallNo getLast() { + return limits.stop; + } }; diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp index f3aea7e..095af67 100644 --- a/common/trace_parser.cpp +++ b/common/trace_parser.cpp @@ -30,6 +30,7 @@ #include #include "trace_file.hpp" +#include "trace_dump.hpp" #include "trace_parser.hpp" @@ -176,9 +177,15 @@ Call *Parser::parse_call(Mode mode) { int c = read_byte(); switch (c) { case trace::EVENT_ENTER: +#if TRACE_VERBOSE + std::cerr << "\tENTER\n"; +#endif parse_enter(mode); break; case trace::EVENT_LEAVE: +#if TRACE_VERBOSE + std::cerr << "\tLEAVE\n"; +#endif call = parse_leave(mode); adjust_call_flags(call); return call; @@ -466,11 +473,20 @@ bool Parser::parse_call_details(Call *call, Mode mode) { int c = read_byte(); switch (c) { case trace::CALL_END: +#if TRACE_VERBOSE + std::cerr << "\tCALL_END\n"; +#endif return true; case trace::CALL_ARG: +#if TRACE_VERBOSE + std::cerr << "\tCALL_ARG\n"; +#endif parse_arg(call, mode); break; case trace::CALL_RET: +#if TRACE_VERBOSE + std::cerr << "\tCALL_RET\n"; +#endif call->ret = parse_value(mode); break; default: @@ -570,7 +586,9 @@ Value *Parser::parse_value(void) { } #if TRACE_VERBOSE if (value) { - std::cerr << "\tVALUE " << value << "\n"; + std::cerr << "\tVALUE "; + trace::dump(value, std::cerr); + std::cerr << "\n"; } #endif return value; diff --git a/common/trace_parser_flags.cpp b/common/trace_parser_flags.cpp index 1ff2b0b..bad9f5e 100644 --- a/common/trace_parser_flags.cpp +++ b/common/trace_parser_flags.cpp @@ -81,8 +81,8 @@ callFlagTable[] = { { "ID3D11DeviceContext::DrawInstancedIndirect", CALL_FLAG_RENDER }, { "ID3D11DeviceContext::OMSetRenderTargets", CALL_FLAG_SWAP_RENDERTARGET }, { "ID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews", CALL_FLAG_SWAP_RENDERTARGET }, - { "IDXGISwapChain::Present", CALL_FLAG_END_FRAME }, - { "IDXGISwapChainDWM::Present", CALL_FLAG_END_FRAME }, + { "IDXGISwapChain::Present", CALL_FLAG_SWAPBUFFERS }, + { "IDXGISwapChainDWM::Present", CALL_FLAG_SWAPBUFFERS }, { "IDirect3D9::CheckDeviceFormat", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "IDirect3D9::EnumAdapterModes", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "IDirect3D9::GetAdapterModeCount", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, @@ -100,7 +100,7 @@ callFlagTable[] = { { "IDirect3DDevice9::DrawTriPatch", CALL_FLAG_RENDER }, { "IDirect3DDevice9::GetDeviceCaps", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "IDirect3DDevice9::GetRenderTargetData", CALL_FLAG_END_FRAME }, - { "IDirect3DDevice9::Present", CALL_FLAG_END_FRAME }, + { "IDirect3DDevice9::Present", CALL_FLAG_SWAPBUFFERS }, { "IDirect3DDevice9::SetRenderTarget", CALL_FLAG_SWAP_RENDERTARGET }, { "IDirect3DDevice9Ex::Clear", CALL_FLAG_RENDER }, { "IDirect3DDevice9Ex::DrawIndexedPrimitive", CALL_FLAG_RENDER }, @@ -111,10 +111,11 @@ callFlagTable[] = { { "IDirect3DDevice9Ex::DrawTriPatch", CALL_FLAG_RENDER }, { "IDirect3DDevice9Ex::GetDeviceCaps", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "IDirect3DDevice9Ex::GetRenderTargetData", CALL_FLAG_END_FRAME }, - { "IDirect3DDevice9Ex::Present", CALL_FLAG_END_FRAME }, + { "IDirect3DDevice9Ex::Present", CALL_FLAG_SWAPBUFFERS }, + { "IDirect3DDevice9Ex::PresentEx", CALL_FLAG_SWAPBUFFERS }, { "IDirect3DDevice9Ex::SetRenderTarget", CALL_FLAG_SWAP_RENDERTARGET }, - { "IDirect3DSwapChain9::Present", CALL_FLAG_END_FRAME }, - { "IDirect3DSwapChain9Ex::Present", CALL_FLAG_END_FRAME }, + { "IDirect3DSwapChain9::Present", CALL_FLAG_SWAPBUFFERS }, + { "IDirect3DSwapChain9Ex::Present", CALL_FLAG_SWAPBUFFERS }, { "eglGetProcAddress", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "eglQueryString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "eglSwapBuffers", CALL_FLAG_SWAPBUFFERS }, diff --git a/common/trace_profiler.cpp b/common/trace_profiler.cpp index 0f90ee2..773e7cc 100644 --- a/common/trace_profiler.cpp +++ b/common/trace_profiler.cpp @@ -1,6 +1,7 @@ /************************************************************************** * * Copyright 2012 VMware, Inc. + * Copyright 2013 Intel, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,9 +35,12 @@ Profiler::Profiler() : baseGpuTime(0), baseCpuTime(0), minCpuTime(1000), + baseVsizeUsage(0), + baseRssUsage(0), cpuTimes(false), gpuTimes(true), - pixelsDrawn(false) + pixelsDrawn(false), + memoryUsage(false) { } @@ -44,13 +48,14 @@ Profiler::~Profiler() { } -void Profiler::setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_) +void Profiler::setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_, bool memoryUsage_) { cpuTimes = cpuTimes_; gpuTimes = gpuTimes_; pixelsDrawn = pixelsDrawn_; + memoryUsage = memoryUsage_; - std::cout << "# call no gpu_start gpu_dura cpu_start cpu_dura pixels program name" << std::endl; + std::cout << "# call no gpu_start gpu_dura cpu_start cpu_dura vsize_start vsize_dura rss_start rss_dura pixels program name" << std::endl; } int64_t Profiler::getBaseCpuTime() @@ -63,6 +68,16 @@ int64_t Profiler::getBaseGpuTime() return baseGpuTime; } +int64_t Profiler::getBaseVsizeUsage() +{ + return baseVsizeUsage; +} + +int64_t Profiler::getBaseRssUsage() +{ + return baseRssUsage; +} + void Profiler::setBaseCpuTime(int64_t cpuStart) { baseCpuTime = cpuStart; @@ -73,6 +88,16 @@ void Profiler::setBaseGpuTime(int64_t gpuStart) baseGpuTime = gpuStart; } +void Profiler::setBaseVsizeUsage(int64_t vsizeStart) +{ + baseVsizeUsage = vsizeStart; +} + +void Profiler::setBaseRssUsage(int64_t rssStart) +{ + baseRssUsage = rssStart; +} + bool Profiler::hasBaseTimes() { return baseCpuTime != 0 || baseGpuTime != 0; @@ -83,7 +108,9 @@ void Profiler::addCall(unsigned no, unsigned program, int64_t pixels, int64_t gpuStart, int64_t gpuDuration, - int64_t cpuStart, int64_t cpuDuration) + int64_t cpuStart, int64_t cpuDuration, + int64_t vsizeStart, int64_t vsizeDuration, + int64_t rssStart, int64_t rssDuration) { if (gpuTimes && gpuStart) { gpuStart -= baseGpuTime; @@ -109,12 +136,23 @@ void Profiler::addCall(unsigned no, pixels = 0; } + if (!memoryUsage || !vsizeStart || !rssStart) { + vsizeStart = 0; + vsizeDuration = 0; + rssStart = 0; + rssDuration = 0; + } + std::cout << "call" << " " << no << " " << gpuStart << " " << gpuDuration << " " << cpuStart << " " << cpuDuration + << " " << vsizeStart + << " " << vsizeDuration + << " " << rssStart + << " " << rssDuration << " " << pixels << " " << program << " " << name @@ -132,6 +170,8 @@ void Profiler::parseLine(const char* in, Profile* profile) std::string type; static int64_t lastGpuTime; static int64_t lastCpuTime; + static int64_t lastVsizeUsage; + static int64_t lastRssUsage; if (in[0] == '#' || strlen(in) < 4) return; @@ -139,6 +179,8 @@ void Profiler::parseLine(const char* in, Profile* profile) if (profile->programs.size() == 0 && profile->calls.size() == 0 && profile->frames.size() == 0) { lastGpuTime = 0; lastCpuTime = 0; + lastVsizeUsage = 0; + lastRssUsage = 0; } line >> type; @@ -151,6 +193,10 @@ void Profiler::parseLine(const char* in, Profile* profile) >> call.gpuDuration >> call.cpuStart >> call.cpuDuration + >> call.vsizeStart + >> call.vsizeDuration + >> call.rssStart + >> call.rssDuration >> call.pixels >> call.program >> call.name; @@ -163,6 +209,14 @@ void Profiler::parseLine(const char* in, Profile* profile) lastCpuTime = call.cpuStart + call.cpuDuration; } + if (lastVsizeUsage < call.vsizeStart + call.vsizeDuration) { + lastVsizeUsage = call.vsizeStart + call.vsizeDuration; + } + + if (lastRssUsage < call.rssStart + call.rssDuration) { + lastRssUsage = call.rssStart + call.rssDuration; + } + profile->calls.push_back(call); if (call.pixels >= 0) { @@ -174,6 +228,8 @@ void Profiler::parseLine(const char* in, Profile* profile) program.cpuTotal += call.cpuDuration; program.gpuTotal += call.gpuDuration; program.pixelTotal += call.pixels; + program.vsizeTotal += call.vsizeDuration; + program.rssTotal += call.rssDuration; program.calls.push_back(profile->calls.size() - 1); } } else if (type.compare("frame_end") == 0) { @@ -183,15 +239,21 @@ void Profiler::parseLine(const char* in, Profile* profile) if (frame.no == 0) { frame.gpuStart = 0; frame.cpuStart = 0; + frame.vsizeStart = 0; + frame.rssStart = 0; frame.calls.begin = 0; } else { frame.gpuStart = profile->frames.back().gpuStart + profile->frames.back().gpuDuration; frame.cpuStart = profile->frames.back().cpuStart + profile->frames.back().cpuDuration; + frame.vsizeStart = profile->frames.back().vsizeStart + profile->frames.back().vsizeDuration; + frame.rssStart = profile->frames.back().rssStart + profile->frames.back().rssDuration; frame.calls.begin = profile->frames.back().calls.end + 1; } frame.gpuDuration = lastGpuTime - frame.gpuStart; frame.cpuDuration = lastCpuTime - frame.cpuStart; + frame.vsizeDuration = lastVsizeUsage - frame.vsizeStart; + frame.rssDuration = lastRssUsage - frame.rssStart; frame.calls.end = profile->calls.size() - 1; profile->frames.push_back(frame); diff --git a/common/trace_profiler.hpp b/common/trace_profiler.hpp index d833242..e3ae016 100644 --- a/common/trace_profiler.hpp +++ b/common/trace_profiler.hpp @@ -1,6 +1,7 @@ /************************************************************************** * * Copyright 2012 VMware, Inc. + * Copyright 2013 Intel, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -45,6 +46,11 @@ struct Profile { int64_t cpuStart; int64_t cpuDuration; + int64_t vsizeStart; + int64_t vsizeDuration; + int64_t rssStart; + int64_t rssDuration; + int64_t pixels; std::string name; @@ -59,6 +65,11 @@ struct Profile { int64_t cpuStart; int64_t cpuDuration; + int64_t vsizeStart; + int64_t vsizeDuration; + int64_t rssStart; + int64_t rssDuration; + /* Indices to profile->calls array */ struct { unsigned begin; @@ -72,6 +83,8 @@ struct Profile { uint64_t gpuTotal; uint64_t cpuTotal; uint64_t pixelTotal; + int64_t vsizeTotal; + int64_t rssTotal; /* Indices to profile->calls array */ std::vector calls; @@ -88,14 +101,16 @@ public: Profiler(); ~Profiler(); - void setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_); + void setup(bool cpuTimes_, bool gpuTimes_, bool pixelsDrawn_, bool memoryUsage_); void addCall(unsigned no, const char* name, unsigned program, int64_t pixels, int64_t gpuStart, int64_t gpuDuration, - int64_t cpuStart, int64_t cpuDuration); + int64_t cpuStart, int64_t cpuDuration, + int64_t vsizeStart, int64_t vsizeDuration, + int64_t rssStart, int64_t rssDuration); void addFrameEnd(); @@ -103,9 +118,13 @@ public: void setBaseCpuTime(int64_t cpuStart); void setBaseGpuTime(int64_t gpuStart); + void setBaseVsizeUsage(int64_t vsizeStart); + void setBaseRssUsage(int64_t rssStart); int64_t getBaseCpuTime(); int64_t getBaseGpuTime(); + int64_t getBaseVsizeUsage(); + int64_t getBaseRssUsage(); static void parseLine(const char* line, Profile* profile); @@ -113,10 +132,13 @@ private: int64_t baseGpuTime; int64_t baseCpuTime; int64_t minCpuTime; + int64_t baseVsizeUsage; + int64_t baseRssUsage; bool cpuTimes; bool gpuTimes; bool pixelsDrawn; + bool memoryUsage; }; } diff --git a/dispatch/d3d8imports.hpp b/dispatch/d3d8imports.hpp new file mode 100644 index 0000000..d081379 --- /dev/null +++ b/dispatch/d3d8imports.hpp @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright 2012 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. + * + **************************************************************************/ + +/* + * Central place for all D3D8 includes, and respective OS dependent headers. + */ + +#ifndef _D3D8IMPORTS_HPP_ +#define _D3D8IMPORTS_HPP_ + +#include + +#include "compat.h" + +#include + +#endif /* _D3D8IMPORTS_HPP_ */ diff --git a/dispatch/d3d9imports.hpp b/dispatch/d3d9imports.hpp index a07d768..b4e8187 100644 --- a/dispatch/d3d9imports.hpp +++ b/dispatch/d3d9imports.hpp @@ -73,6 +73,10 @@ #define D3DFMT_NV12 ((D3DFORMAT)MAKEFOURCC('N','V','1','2')) #endif +#ifndef D3DFMT_YV12 +#define D3DFMT_YV12 ((D3DFORMAT)MAKEFOURCC('Y','V','1','2')) +#endif + #ifndef D3DFMT_RAWZ #define D3DFMT_RAWZ ((D3DFORMAT)MAKEFOURCC('R','A','W','Z')) #endif diff --git a/dispatch/dxgiint.h b/dispatch/dxgiint.h index f985ed1..13853b3 100644 --- a/dispatch/dxgiint.h +++ b/dispatch/dxgiint.h @@ -45,18 +45,18 @@ struct IDXGIFactoryDWM: public IUnknown virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGIOutput *pOutput, IDXGISwapChainDWM **ppSwapChain) = 0; }; -struct IDXGISwapChainDWM: public IDXGIDeviceSubObject -{ - virtual HRESULT STDMETHODCALLTYPE Present (UINT SyncInterval, UINT Flags) = 0; - virtual HRESULT STDMETHODCALLTYPE GetBuffer (UINT Buffer, REFIID riid, void **ppSurface) = 0; - virtual HRESULT STDMETHODCALLTYPE GetDesc (DXGI_SWAP_CHAIN_DESC *pDesc) = 0; - virtual HRESULT STDMETHODCALLTYPE ResizeBuffers (UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) = 0; - virtual HRESULT STDMETHODCALLTYPE ResizeTarget (const DXGI_MODE_DESC *pNewTargetParameters) = 0; - virtual HRESULT STDMETHODCALLTYPE GetContainingOutput (IDXGIOutput **ppOutput) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics (DXGI_FRAME_STATISTICS *pStats) = 0; - virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount (UINT *pLastPresentCount) = 0; - virtual HRESULT STDMETHODCALLTYPE SetFullscreenState (BOOL Fullscreen, IDXGIOutput *pTarget) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFullscreenState (BOOL *pFullscreen, IDXGIOutput **ppTarget) = 0; -}; +struct IDXGISwapChainDWM: public IDXGIDeviceSubObject +{ + virtual HRESULT STDMETHODCALLTYPE Present(UINT SyncInterval, UINT Flags) = 0; + virtual HRESULT STDMETHODCALLTYPE GetBuffer(UINT Buffer, REFIID riid, void **ppSurface) = 0; + virtual HRESULT STDMETHODCALLTYPE GetDesc(DXGI_SWAP_CHAIN_DESC *pDesc) = 0; + virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) = 0; + virtual HRESULT STDMETHODCALLTYPE ResizeTarget(const DXGI_MODE_DESC *pNewTargetParameters) = 0; + virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(IDXGIOutput **ppOutput) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) = 0; + virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) = 0; + virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(BOOL Fullscreen, IDXGIOutput *pTarget) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(BOOL *pFullscreen, IDXGIOutput **ppTarget) = 0; +}; #endif /* _DXGIINT_H_ */ diff --git a/dispatch/dxvaint.h b/dispatch/dxvaint.h index ad11304..8a5ecfd 100644 --- a/dispatch/dxvaint.h +++ b/dispatch/dxvaint.h @@ -44,8 +44,6 @@ #endif -typedef struct _DXVA2_PVP_SETKEY DXVA2_PVP_SETKEY; /* XXX */ - typedef struct _DXVA2_DECODEBUFFERDESC { IDirect3DSurface9 *pRenderTarget; DWORD CompressedBufferType; @@ -112,6 +110,16 @@ static const GUID IID_IDirect3DDXVAExtensionDevice9 = {0x00000000,0x0000,0x0000, static const GUID IID_IDirect3DDxva2Container9 = {0x126D0349,0x4787,0x4AA6,{0x8E,0x1B,0x40,0xC1,0x77,0xC6,0x0A,0x01}}; +typedef struct DECLSPEC_ALIGN(16) _DXVA2_PVP_KEY128 +{ + BYTE Data[16]; +} DXVA2_PVP_KEY128; + +typedef struct _DXVA2_PVP_SETKEY +{ + DXVA2_PVP_KEY128 ContentKey; +} DXVA2_PVP_SETKEY; + class IDirect3DDecodeDevice9 : public IUnknown { public: diff --git a/dispatch/eglimports.hpp b/dispatch/eglimports.hpp index 7f22e70..49cf177 100644 --- a/dispatch/eglimports.hpp +++ b/dispatch/eglimports.hpp @@ -52,6 +52,13 @@ #include +// OpenGL ES 2.0 + +// avoid conflicting with GL_NV_multisample_coverage +#define GL_NV_coverage_sample +#include "GLES2/gl2ext.h" + + // OpenGL ES 1.1 typedef int32_t GLfixed; typedef int32_t GLclampx; @@ -77,18 +84,8 @@ typedef int32_t GLclampx; #define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F #endif -// avoid conflict with GL_EXT_framebuffer_multisample -#define GL_EXT_multisampled_render_to_texture - #undef _glext_h_ #include "GLES/glext.h" -// OpenGL ES 2.0 - -// avoid conflicting with GL_NV_multisample_coverage -#define GL_NV_coverage_sample -#include "GLES2/gl2ext.h" - - #endif /* _EGLIMPORTS_HPP_ */ diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp index 6a8ebe2..a69ce2f 100644 --- a/gui/apitrace.cpp +++ b/gui/apitrace.cpp @@ -393,6 +393,9 @@ void ApiTrace::loaderSearchResult(const ApiTrace::SearchRequest &request, void ApiTrace::findFrameStart(ApiTraceFrame *frame) { + if (!frame) + return; + if (frame->isLoaded()) { emit foundFrameStart(frame); } else { @@ -402,6 +405,9 @@ void ApiTrace::findFrameStart(ApiTraceFrame *frame) void ApiTrace::findFrameEnd(ApiTraceFrame *frame) { + if (!frame) + return; + if (frame->isLoaded()) { emit foundFrameEnd(frame); } else { diff --git a/gui/graphing/histogramview.cpp b/gui/graphing/histogramview.cpp index 0b94577..2dd3d8e 100644 --- a/gui/graphing/histogramview.cpp +++ b/gui/graphing/histogramview.cpp @@ -228,8 +228,8 @@ void HistogramView::paintEvent(QPaintEvent *) qint64 HistogramView::itemAtPosition(QPoint pos) { double dvdx = m_viewWidth / (double)width(); - qint64 left = qFloor(dvdx) * (pos.x() - 1) + m_viewLeft; - qint64 right = qCeil(dvdx) * (pos.x() + 1) + m_viewLeft; + qint64 left = qFloor(dvdx * (pos.x() - 1)) + m_viewLeft; + qint64 right = qCeil(dvdx * (pos.x() + 1)) + m_viewLeft; qint64 longestIndex = 0; qint64 longestValue = 0; diff --git a/gui/main.cpp b/gui/main.cpp index 0ed50ed..471dec7 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -3,6 +3,9 @@ #include "apitrace.h" #include "apitracecall.h" +#include "os_string.hpp" +#include "os_process.hpp" + #include #include #include @@ -32,6 +35,15 @@ int main(int argc, char **argv) qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType >(); + +#ifndef Q_OS_WIN + os::String currentProcess = os::getProcessName(); + currentProcess.trimFilename(); + QString path = qgetenv("PATH"); + path = QLatin1String(currentProcess.str()) + QLatin1String(":") + path; + qputenv("PATH", path.toLatin1()); +#endif + QStringList args = app.arguments(); int i = 1; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index caf9e37..d6ebd2f 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -48,6 +48,7 @@ MainWindow::MainWindow() m_nonDefaultsLookupEvent(0) { m_ui.setupUi(this); + updateActionsState(false); initObjects(); initConnections(); } @@ -228,11 +229,7 @@ void MainWindow::replayProfile() void MainWindow::replayStop() { m_retracer->quit(); - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionProfile->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); - m_ui.actionShowThumbnails->setEnabled(true); + updateActionsState(true, true); } void MainWindow::newTraceFile(const QString &fileName) @@ -243,18 +240,11 @@ void MainWindow::newTraceFile(const QString &fileName) m_trace->setFileName(fileName); if (fileName.isEmpty()) { - m_ui.actionReplay->setEnabled(false); - m_ui.actionProfile->setEnabled(false); - m_ui.actionLookupState->setEnabled(false); - m_ui.actionShowThumbnails->setEnabled(false); + updateActionsState(false); setWindowTitle(tr("QApiTrace")); } else { + updateActionsState(true); QFileInfo info(fileName); - m_ui.actionReplay->setEnabled(true); - m_ui.actionProfile->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); - m_ui.actionShowThumbnails->setEnabled(true); - m_ui.actionTrim->setEnabled(true); setWindowTitle( tr("QApiTrace - %1").arg(info.fileName())); } @@ -262,12 +252,7 @@ void MainWindow::newTraceFile(const QString &fileName) void MainWindow::replayFinished(const QString &message) { - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionProfile->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); - m_ui.actionShowThumbnails->setEnabled(true); - + updateActionsState(true); m_progressBar->hide(); statusBar()->showMessage(message, 2000); m_stateEvent = 0; @@ -280,11 +265,7 @@ void MainWindow::replayFinished(const QString &message) void MainWindow::replayError(const QString &message) { - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionProfile->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); - m_ui.actionShowThumbnails->setEnabled(true); + updateActionsState(true); m_stateEvent = 0; m_nonDefaultsLookupEvent = 0; @@ -936,6 +917,47 @@ void MainWindow::initConnections() this, SLOT(slotJumpTo(int))); } +void MainWindow::updateActionsState(bool traceLoaded, bool stopped) +{ + if (traceLoaded) { + /* Edit */ + m_ui.actionFind ->setEnabled(true); + m_ui.actionGo ->setEnabled(true); + m_ui.actionGoFrameStart ->setEnabled(true); + m_ui.actionGoFrameEnd ->setEnabled(true); + + /* Trace */ + if (stopped) { + m_ui.actionStop->setEnabled(false); + m_ui.actionReplay->setEnabled(true); + } + else { + m_ui.actionStop->setEnabled(true); + m_ui.actionReplay->setEnabled(false); + } + + m_ui.actionProfile ->setEnabled(true); + m_ui.actionLookupState ->setEnabled(true); + m_ui.actionShowThumbnails->setEnabled(true); + m_ui.actionTrim ->setEnabled(true); + } + else { + /* Edit */ + m_ui.actionFind ->setEnabled(false); + m_ui.actionGo ->setEnabled(false); + m_ui.actionGoFrameStart ->setEnabled(false); + m_ui.actionGoFrameEnd ->setEnabled(false); + + /* Trace */ + m_ui.actionReplay ->setEnabled(false); + m_ui.actionProfile ->setEnabled(false); + m_ui.actionStop ->setEnabled(false); + m_ui.actionLookupState ->setEnabled(false); + m_ui.actionShowThumbnails->setEnabled(false); + m_ui.actionTrim ->setEnabled(false); + } +} + void MainWindow::closeEvent(QCloseEvent * event) { m_profileDialog->close(); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 2248127..78267ef 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -98,6 +98,7 @@ private slots: private: void initObjects(); void initConnections(); + void updateActionsState(bool traceLoaded, bool stopped = true); void newTraceFile(const QString &fileName); void replayTrace(bool dumpState, bool dumpThumbnails); void trimEvent(); diff --git a/gui/retracer.cpp b/gui/retracer.cpp index 738367e..2928ed6 100644 --- a/gui/retracer.cpp +++ b/gui/retracer.cpp @@ -137,19 +137,6 @@ Retracer::Retracer(QObject *parent) m_profilePixels(false) { qRegisterMetaType >(); - -#ifdef Q_OS_WIN - QString format = QLatin1String("%1;"); -#else - QString format = QLatin1String("%1:"); -#endif - QString buildPath = format.arg(APITRACE_BINARY_DIR); - m_processEnvironment = QProcessEnvironment::systemEnvironment(); - m_processEnvironment.insert("PATH", buildPath + - m_processEnvironment.value("PATH")); - - qputenv("PATH", - m_processEnvironment.value("PATH").toLatin1()); } QString Retracer::fileName() const diff --git a/gui/retracer.h b/gui/retracer.h index e889d88..af1a3d9 100644 --- a/gui/retracer.h +++ b/gui/retracer.h @@ -65,8 +65,6 @@ private: bool m_profileGpu; bool m_profileCpu; bool m_profilePixels; - - QProcessEnvironment m_processEnvironment; }; #endif diff --git a/gui/tracedialog.cpp b/gui/tracedialog.cpp index fcfdf46..b8e438d 100644 --- a/gui/tracedialog.cpp +++ b/gui/tracedialog.cpp @@ -50,7 +50,7 @@ void TraceDialog::browse() tr("Find the application"), QDir::currentPath()); - if (isFileOk(fileName)) { + if (!fileName.isEmpty() && isFileOk(fileName)) { applicationEdit->setText(fileName); } } diff --git a/gui/traceprocess.cpp b/gui/traceprocess.cpp index 6f4d0b9..8d57e52 100644 --- a/gui/traceprocess.cpp +++ b/gui/traceprocess.cpp @@ -15,16 +15,6 @@ TraceProcess::TraceProcess(QObject *parent) this, SLOT(traceFinished())); connect(m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(traceError(QProcess::ProcessError))); - -#ifdef Q_OS_WIN - QString format = QLatin1String("%1;"); -#else - QString format = QLatin1String("%1:"); -#endif - QString buildPath = format.arg(APITRACE_BINARY_DIR); - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("PATH", buildPath + env.value("PATH")); - qputenv("PATH", env.value("PATH").toLatin1()); } TraceProcess::~TraceProcess() diff --git a/gui/trimprocess.cpp b/gui/trimprocess.cpp index c23475d..34639c6 100644 --- a/gui/trimprocess.cpp +++ b/gui/trimprocess.cpp @@ -15,16 +15,6 @@ TrimProcess::TrimProcess(QObject *parent) this, SLOT(trimFinished())); connect(m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(trimError(QProcess::ProcessError))); - -#ifdef Q_OS_WIN - QString format = QLatin1String("%1;"); -#else - QString format = QLatin1String("%1:"); -#endif - QString buildPath = format.arg(APITRACE_BINARY_DIR); - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("PATH", buildPath + env.value("PATH")); - qputenv("PATH", env.value("PATH").toLatin1()); } TrimProcess::~TrimProcess() diff --git a/gui/ui/mainwindow.ui b/gui/ui/mainwindow.ui index 7cbb3d1..06f4503 100644 --- a/gui/ui/mainwindow.ui +++ b/gui/ui/mainwindow.ui @@ -124,7 +124,7 @@ 0 - + about:blank @@ -493,9 +493,6 @@ - - false - :/resources/media-playback-start.png:/resources/media-playback-start.png @@ -508,9 +505,6 @@ - - false - :/resources/media-playback-stop.png:/resources/media-playback-stop.png @@ -520,9 +514,6 @@ - - false - :/resources/media-record.png:/resources/media-record.png @@ -535,9 +526,6 @@ - - false - Show &Thumbnails @@ -546,9 +534,6 @@ - - false - Tr&im @@ -567,7 +552,10 @@ :/resources/document-new.png:/resources/document-new.png - New + &New... + + + Ctrl+N @@ -576,7 +564,7 @@ :/resources/edit-find.png:/resources/edit-find.png - Find + &Find Ctrl+F @@ -638,9 +626,6 @@ - - false - &Profile diff --git a/gui/ui/tracedialog.ui b/gui/ui/tracedialog.ui index a3e5240..f6eccf4 100644 --- a/gui/ui/tracedialog.ui +++ b/gui/ui/tracedialog.ui @@ -47,7 +47,7 @@ - Browse + Browse... false diff --git a/helpers/d3dcommonsize.hpp b/helpers/d3dcommonsize.hpp index d4c4862..b1f7b28 100644 --- a/helpers/d3dcommonsize.hpp +++ b/helpers/d3dcommonsize.hpp @@ -163,6 +163,7 @@ _getLockSize(D3DFORMAT Format, UINT Width, UINT Height, INT RowPitch, UINT Depth #if DIRECT3D_VERSION >= 0x900 case D3DFMT_NV12: + case D3DFMT_YV12: return (Height + ((Height + 1) / 2)) * RowPitch; case D3DFMT_NULL: diff --git a/helpers/glsize.hpp b/helpers/glsize.hpp index b4ec251..c4fe9bf 100644 --- a/helpers/glsize.hpp +++ b/helpers/glsize.hpp @@ -329,11 +329,19 @@ _glArrayPointer_size(GLint size, GLenum type, GLsizei stride, GLsizei count) #define _glVertexAttribPointerARB_size(size, type, normalized, stride, count) _glArrayPointer_size(size, type, stride, count) #define _glVertexAttribPointerNV_size(size, type, stride, count) _glArrayPointer_size(size, type, stride, count) +/** + * Same as glGetIntegerv, but passing the result in the return value. + */ +static inline GLint +_glGetInteger(GLenum pname) { + GLint param = 0; + _glGetIntegerv(pname, ¶m); + return param; +} + static inline GLint _element_array_buffer_binding(void) { - GLint element_array_buffer = 0; - _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &element_array_buffer); - return element_array_buffer; + return _glGetInteger(GL_ELEMENT_ARRAY_BUFFER_BINDING); } static inline GLuint diff --git a/inject/inject.h b/inject/inject.h index 058ada6..e915e4f 100644 --- a/inject/inject.h +++ b/inject/inject.h @@ -91,6 +91,11 @@ getModuleName(char *szModuleName, size_t n, const char *szFilename) { } +#define USE_SHARED_MEM 1 + + +#if USE_SHARED_MEM + #define SHARED_MEM_SIZE 4096 static LPVOID pSharedMem = NULL; @@ -179,3 +184,5 @@ GetSharedMem(LPSTR lpszDst, size_t n) { *lpszDst = '\0'; } + +#endif /* USE_SHARED_MEM */ diff --git a/inject/injectee.cpp b/inject/injectee.cpp index 86992b8..c60bc45 100644 --- a/inject/injectee.cpp +++ b/inject/injectee.cpp @@ -57,10 +57,7 @@ static CRITICAL_SECTION Mutex = {(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0}; static void debugPrintf(const char *format, ...) { -#if VERBOSITY > 0 - static char buf[4096]; - - EnterCriticalSection(&Mutex); + char buf[512]; va_list ap; va_start(ap, format); @@ -68,9 +65,6 @@ debugPrintf(const char *format, ...) va_end(ap); OutputDebugStringA(buf); - - LeaveCriticalSection(&Mutex); -#endif } @@ -205,13 +199,15 @@ replaceModule(HMODULE hModule, while (pOriginalFirstThunk->u1.Function) { PIMAGE_IMPORT_BY_NAME pImport = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hModule + pOriginalFirstThunk->u1.AddressOfData); const char* szFunctionName = (const char* )pImport->Name; - debugPrintf(" hooking %s->%s!%s\n", szModule, - getImportDescriptionName(hModule, pImportDescriptor), - szFunctionName); + if (VERBOSITY > 0) { + debugPrintf(" hooking %s->%s!%s\n", szModule, + getImportDescriptionName(hModule, pImportDescriptor), + szFunctionName); + } PROC pNewProc = GetProcAddress(hNewModule, szFunctionName); if (!pNewProc) { - debugPrintf(" warning: no replacement for %s\n", szFunctionName); + debugPrintf("warning: no replacement for %s\n", szFunctionName); } else { LPVOID *lpOldAddress = (LPVOID *)(&pFirstThunk->u1.Function); replaceAddress(lpOldAddress, (LPVOID)pNewProc); @@ -257,9 +253,9 @@ replaceImport(HMODULE hModule, const char *pszDllName, HMODULE hNewModule) { -#if NOOP - return TRUE; -#endif + if (NOOP) { + return TRUE; + } PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = getImportDescriptor(hModule, szModule, pszDllName); if (pImportDescriptor == NULL) { @@ -339,15 +335,17 @@ hookAllModules(void) MODULEENTRY32 me32; me32.dwSize = sizeof me32; - static bool first = true; - if (first) { - if (Module32First(hModuleSnap, &me32)) { - debugPrintf(" modules:\n"); - do { - debugPrintf(" %s\n", me32.szExePath); - } while (Module32Next(hModuleSnap, &me32)); + if (VERBOSITY > 0) { + static bool first = true; + if (first) { + if (Module32First(hModuleSnap, &me32)) { + debugPrintf(" modules:\n"); + do { + debugPrintf(" %s\n", me32.szExePath); + } while (Module32Next(hModuleSnap, &me32)); + } + first = false; } - first = false; } if (Module32First(hModuleSnap, &me32)) { @@ -382,24 +380,26 @@ MyLoadLibraryA(LPCSTR lpLibFileName) debugPrintf("%s(\"%s\")\n", __FUNCTION__, lpLibFileName); } - const char *szBaseName = getBaseName(lpLibFileName); - for (unsigned i = 0; i < numReplacements; ++i) { - if (stricmp(szBaseName, replacements[i].szMatchModule) == 0) { - debugPrintf("%s(\"%s\")\n", __FUNCTION__, lpLibFileName); + if (VERBOSITY > 0) { + const char *szBaseName = getBaseName(lpLibFileName); + for (unsigned i = 0; i < numReplacements; ++i) { + if (stricmp(szBaseName, replacements[i].szMatchModule) == 0) { + debugPrintf("%s(\"%s\")\n", __FUNCTION__, lpLibFileName); #ifdef __GNUC__ - void *caller = __builtin_return_address (0); - - HMODULE hModule = 0; - BOOL bRet = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR)caller, - &hModule); - assert(bRet); - char szCaller[256]; - DWORD dwRet = GetModuleFileNameA(hModule, szCaller, sizeof szCaller); - assert(dwRet); - debugPrintf(" called from %s\n", szCaller); + void *caller = __builtin_return_address (0); + + HMODULE hModule = 0; + BOOL bRet = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)caller, + &hModule); + assert(bRet); + char szCaller[256]; + DWORD dwRet = GetModuleFileNameA(hModule, szCaller, sizeof szCaller); + assert(dwRet); + debugPrintf(" called from %s\n", szCaller); #endif - break; + break; + } } } @@ -456,29 +456,33 @@ MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { } } -#if !NOOP - char szModule[256]; - DWORD dwRet = GetModuleFileNameA(hModule, szModule, sizeof szModule); - assert(dwRet); - const char *szBaseName = getBaseName(szModule); + if (!NOOP) { + char szModule[256]; + DWORD dwRet = GetModuleFileNameA(hModule, szModule, sizeof szModule); + assert(dwRet); + const char *szBaseName = getBaseName(szModule); - for (unsigned i = 0; i < numReplacements; ++i) { + for (unsigned i = 0; i < numReplacements; ++i) { - if (stricmp(szBaseName, replacements[i].szMatchModule) == 0) { - debugPrintf(" %s(\"%s\", \"%s\")\n", __FUNCTION__, szModule, lpProcName); - FARPROC pProcAddress = GetProcAddress(replacements[i].hReplaceModule, lpProcName); - if (pProcAddress) { - if (VERBOSITY >= 2) { - debugPrintf(" replacing %s!%s\n", szBaseName, lpProcName); + if (stricmp(szBaseName, replacements[i].szMatchModule) == 0) { + if (VERBOSITY > 0) { + debugPrintf(" %s(\"%s\", \"%s\")\n", __FUNCTION__, szModule, lpProcName); + } + FARPROC pProcAddress = GetProcAddress(replacements[i].hReplaceModule, lpProcName); + if (pProcAddress) { + if (VERBOSITY >= 2) { + debugPrintf(" replacing %s!%s\n", szBaseName, lpProcName); + } + return pProcAddress; + } else { + if (VERBOSITY > 0) { + debugPrintf(" ignoring %s!%s\n", szBaseName, lpProcName); + } + break; } - return pProcAddress; - } else { - debugPrintf(" ignoring %s!%s\n", szBaseName, lpProcName); - break; } } } -#endif return GetProcAddress(hModule, lpProcName); } @@ -493,14 +497,18 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) switch (fdwReason) { case DLL_PROCESS_ATTACH: - debugPrintf("DLL_PROCESS_ATTACH\n"); + if (VERBOSITY > 0) { + debugPrintf("DLL_PROCESS_ATTACH\n"); + } g_hThisModule = hinstDLL; { char szProcess[MAX_PATH]; GetModuleFileNameA(NULL, szProcess, sizeof szProcess); - debugPrintf(" attached to %s\n", szProcess); + if (VERBOSITY > 0) { + debugPrintf(" attached to %s\n", szProcess); + } } /* @@ -513,7 +521,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) * - http://msdn.microsoft.com/en-us/library/ms682583 */ -#if 0 +#if !USE_SHARED_MEM szNewDllName = getenv("INJECT_DLL"); if (!szNewDllName) { debugPrintf("warning: INJECT_DLL not set\n"); @@ -524,7 +532,9 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) GetSharedMem(szSharedMemCopy, sizeof szSharedMemCopy); szNewDllName = szSharedMemCopy; #endif - debugPrintf(" injecting %s\n", szNewDllName); + if (VERBOSITY > 0) { + debugPrintf(" injecting %s\n", szNewDllName); + } hNewModule = LoadLibraryA(szNewDllName); if (!hNewModule) { @@ -565,7 +575,9 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) break; case DLL_PROCESS_DETACH: - debugPrintf("DLL_PROCESS_DETACH\n"); + if (VERBOSITY > 0) { + debugPrintf("DLL_PROCESS_DETACH\n"); + } break; } return TRUE; diff --git a/inject/injector.cpp b/inject/injector.cpp index 04e0959..5c62a72 100644 --- a/inject/injector.cpp +++ b/inject/injector.cpp @@ -116,7 +116,7 @@ main(int argc, char *argv[]) } const char *szDll = argv[1]; -#if 0 +#if !USE_SHARED_MEM SetEnvironmentVariableA("INJECT_DLL", szDll); #else SetSharedMem(szDll); diff --git a/retrace/CMakeLists.txt b/retrace/CMakeLists.txt index 2665990..5f831a4 100644 --- a/retrace/CMakeLists.txt +++ b/retrace/CMakeLists.txt @@ -102,6 +102,9 @@ if (WIN32 OR APPLE OR X11_FOUND) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries (glretrace rt) + if (READPROC_H_FOUND) + target_link_libraries (glretrace proc) + endif () endif () endif () @@ -127,6 +130,9 @@ if (ENABLE_EGL AND X11_FOUND AND NOT WIN32 AND NOT APPLE) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries (eglretrace rt) + if (READPROC_H_FOUND) + target_link_libraries (eglretrace proc) + endif () endif () install (TARGETS eglretrace RUNTIME DESTINATION bin) @@ -136,6 +142,10 @@ if (WIN32) if (DirectX_D3D8_INCLUDE_DIR) include_directories (BEFORE SYSTEM ${DirectX_D3D8_INCLUDE_DIR}) set (HAVE_D3D8 1) + set (D3DSTATE_SOURCES ${D3DSTATE_SOURCES} + d3d8state.cpp + d3d8state_images.cpp + ) else () set (HAVE_D3D8 0) endif () diff --git a/retrace/d3d8state.cpp b/retrace/d3d8state.cpp new file mode 100644 index 0000000..60bdb6d --- /dev/null +++ b/retrace/d3d8state.cpp @@ -0,0 +1,134 @@ +/************************************************************************** + * + * Copyright 2011-2012 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 + +#include + +#include "d3d8imports.hpp" +#include "d3dshader.hpp" +#include "d3dstate.hpp" +#include "json.hpp" + + +namespace d3dstate { + + +typedef HRESULT (STDMETHODCALLTYPE IDirect3DDevice8::*GetShaderFunctionMethod)(DWORD Handle, void* pData, DWORD* pSizeOfData); + + +struct VertexShaderGetter +{ + HRESULT GetShader(IDirect3DDevice8 *pDevice, DWORD *pHandle) { + return pDevice->GetVertexShader(pHandle); + } + HRESULT GetShaderFunction(IDirect3DDevice8 *pDevice, DWORD Handle, void* pData, DWORD* pSizeOfData) { + return pDevice->GetVertexShaderFunction(Handle, pData, pSizeOfData); + } +}; + +struct PixelShaderGetter +{ + HRESULT GetShader(IDirect3DDevice8 *pDevice, DWORD *pHandle) { + return pDevice->GetPixelShader(pHandle); + } + HRESULT GetShaderFunction(IDirect3DDevice8 *pDevice, DWORD Handle, void* pData, DWORD* pSizeOfData) { + return pDevice->GetPixelShaderFunction(Handle, pData, pSizeOfData); + } +}; + +template +inline void +dumpShader(JSONWriter &json, IDirect3DDevice8 *pDevice, const char *name) { + Getter getter; + HRESULT hr; + + DWORD dwShader = 0; + hr = getter.GetShader(pDevice, &dwShader); + if (FAILED(hr) || !dwShader) { + return; + } + + DWORD SizeOfData = 0; + + hr = getter.GetShaderFunction(pDevice, dwShader, NULL, &SizeOfData); + if (SUCCEEDED(hr)) { + void *pData; + pData = malloc(SizeOfData); + if (pData) { + hr = getter.GetShaderFunction(pDevice, dwShader, pData, &SizeOfData); + if (SUCCEEDED(hr)) { + IDisassemblyBuffer *pDisassembly = NULL; + hr = DisassembleShader((const DWORD *)pData, &pDisassembly); + if (SUCCEEDED(hr)) { + json.beginMember(name); + json.writeString((const char *)pDisassembly->GetBufferPointer() /*, pDisassembly->GetBufferSize() */); + json.endMember(); + pDisassembly->Release(); + } + + } + free(pData); + } + } +} + +static void +dumpShaders(JSONWriter &json, IDirect3DDevice8 *pDevice) +{ + json.beginMember("shaders"); + json.beginObject(); + + dumpShader(json, pDevice, "vertex"); + dumpShader(json, pDevice, "pixel"); + + json.endObject(); + json.endMember(); // shaders +} + +void +dumpDevice(std::ostream &os, IDirect3DDevice8 *pDevice) +{ + JSONWriter json(os); + + /* TODO */ + json.beginMember("parameters"); + json.beginObject(); + json.endObject(); + json.endMember(); // parameters + + dumpShaders(json, pDevice); + + json.beginMember("textures"); + json.beginObject(); + json.endObject(); + json.endMember(); // textures + + dumpFramebuffer(json, pDevice); +} + + +} /* namespace d3dstate */ diff --git a/retrace/d3d8state_images.cpp b/retrace/d3d8state_images.cpp new file mode 100644 index 0000000..89d4e06 --- /dev/null +++ b/retrace/d3d8state_images.cpp @@ -0,0 +1,164 @@ +/************************************************************************** + * + * Copyright 2011-2012 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 +#include + +#include "image.hpp" +#include "json.hpp" +#include "d3d8imports.hpp" +#include "d3dstate.hpp" + + +namespace d3dstate { + + +static image::Image * +getRenderTargetImage(IDirect3DDevice8 *pDevice, + IDirect3DSurface8 *pRenderTarget) { + image::Image *image = NULL; + D3DSURFACE_DESC Desc; + IDirect3DSurface8 *pStagingSurface = NULL; + D3DLOCKED_RECT LockedRect; + const unsigned char *src; + unsigned char *dst; + HRESULT hr; + + if (!pRenderTarget) { + return NULL; + } + + hr = pRenderTarget->GetDesc(&Desc); + assert(SUCCEEDED(hr)); + + if (Desc.Format != D3DFMT_X8R8G8B8 && + Desc.Format != D3DFMT_A8R8G8B8 && + Desc.Format != D3DFMT_R5G6B5) { + std::cerr << "warning: unsupported D3DFORMAT " << Desc.Format << "\n"; + goto no_staging; + } + + hr = pDevice->CreateImageSurface(Desc.Width, Desc.Height, Desc.Format, &pStagingSurface); + if (FAILED(hr)) { + goto no_staging; + } + + hr = pDevice->CopyRects(pRenderTarget, NULL, 0, pStagingSurface, NULL); + if (FAILED(hr)) { + goto no_rendertargetdata; + } + + hr = pStagingSurface->LockRect(&LockedRect, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) { + goto no_rendertargetdata; + } + + image = new image::Image(Desc.Width, Desc.Height, 3, true); + if (!image) { + goto no_image; + } + + dst = image->start(); + src = (const unsigned char *)LockedRect.pBits; + for (unsigned y = 0; y < Desc.Height; ++y) { + if (Desc.Format == D3DFMT_R5G6B5) { + for (unsigned x = 0; x < Desc.Width; ++x) { + uint32_t pixel = ((const uint16_t *)src)[x]; + dst[3*x + 0] = (( pixel & 0x1f) * (2*0xff) + 0x1f) / (2*0x1f); + dst[3*x + 1] = (((pixel >> 5) & 0x3f) * (2*0xff) + 0x3f) / (2*0x3f); + dst[3*x + 2] = (( pixel >> 11 ) * (2*0xff) + 0x1f) / (2*0x1f); + dst[3*x + 3] = 0xff; + } + } else { + for (unsigned x = 0; x < Desc.Width; ++x) { + dst[3*x + 0] = src[4*x + 2]; + dst[3*x + 1] = src[4*x + 1]; + dst[3*x + 2] = src[4*x + 0]; + } + } + + src += LockedRect.Pitch; + dst += image->stride(); + } + +no_image: + pStagingSurface->UnlockRect(); +no_rendertargetdata: + pStagingSurface->Release(); +no_staging: + return image; +} + + +image::Image * +getRenderTargetImage(IDirect3DDevice8 *pDevice) { + HRESULT hr; + + IDirect3DSurface8 *pRenderTarget = NULL; + hr = pDevice->GetRenderTarget(&pRenderTarget); + if (FAILED(hr)) { + return NULL; + } + assert(pRenderTarget); + + image::Image *image = NULL; + if (pRenderTarget) { + image = getRenderTargetImage(pDevice, pRenderTarget); + pRenderTarget->Release(); + } + + return image; +} + + +void +dumpFramebuffer(JSONWriter &json, IDirect3DDevice8 *pDevice) +{ + HRESULT hr; + + json.beginMember("framebuffer"); + json.beginObject(); + + IDirect3DSurface8 *pRenderTarget = NULL; + hr = pDevice->GetRenderTarget(&pRenderTarget); + if (SUCCEEDED(hr) && pRenderTarget) { + image::Image *image; + image = getRenderTargetImage(pDevice, pRenderTarget); + if (image) { + json.beginMember("RENDER_TARGET_0"); + json.writeImage(image, "UNKNOWN"); + json.endMember(); // RENDER_TARGET_* + } + + pRenderTarget->Release(); + } + + json.endObject(); + json.endMember(); // framebuffer +} + + +} /* namespace d3dstate */ diff --git a/retrace/d3d9retrace.py b/retrace/d3d9retrace.py index 9bc9628..ccd8a72 100644 --- a/retrace/d3d9retrace.py +++ b/retrace/d3d9retrace.py @@ -62,6 +62,11 @@ class D3DRetracer(Retracer): print r' d3d9Dumper.unbindDevice(_this);' else: print r' d3d9Dumper.bindDevice(_this);' + if interface.name in ('IDirect3DDevice8', 'IDirect3DDevice8Ex'): + if method.name == 'Release': + print r' d3d8Dumper.unbindDevice(_this);' + else: + print r' d3d8Dumper.bindDevice(_this);' # create windows as neccessary if method.name in ('CreateDevice', 'CreateDeviceEx', 'CreateAdditionalSwapChain'): @@ -69,6 +74,31 @@ class D3DRetracer(Retracer): print r' pPresentationParameters->hDeviceWindow = hWnd;' if 'hFocusWindow' in method.argNames(): print r' hFocusWindow = hWnd;' + + if method.name in ('CreateDevice', 'CreateDeviceEx'): + print r' switch (retrace::driver) {' + print r' case retrace::DRIVER_HARDWARE:' + print r' DeviceType = D3DDEVTYPE_HAL;' + print r' break;' + print r' case retrace::DRIVER_SOFTWARE:' + print r' case retrace::DRIVER_REFERENCE:' + print r' DeviceType = D3DDEVTYPE_REF;' + print r' break;' + print r' case retrace::DRIVER_NULL:' + if interface.name.startswith('IDirect3D9'): + print r' DeviceType = D3DDEVTYPE_NULLREF;' + else: + print r' retrace::warning(call) << "null driver not supported\n";' + print r' break;' + print r' case retrace::DRIVER_MODULE:' + print r' retrace::warning(call) << "driver module not supported\n";' + print r' break;' + print r' default:' + print r' assert(0);' + print r' /* fall-through */' + print r' case retrace::DRIVER_DEFAULT:' + print r' break;' + print r' }' if method.name in ('Reset', 'ResetEx'): print r' if (pPresentationParameters->Windowed) {' @@ -76,7 +106,7 @@ class D3DRetracer(Retracer): print r' }' # notify frame has been completed - if method.name == 'Present': + if method.name in ('Present', 'PresentEx'): print r' retrace::frameComplete(call);' print r' hDestWindowOverride = NULL;' @@ -91,6 +121,7 @@ class D3DRetracer(Retracer): # process events after presents if method.name == 'Present': print r' d3dretrace::processEvents();' + print r' Sleep(500);' if method.name in ('Lock', 'LockRect', 'LockBox'): print ' VOID *_pbData = NULL;' @@ -135,12 +166,11 @@ def main(): print elif moduleName == 'd3d8': from specs.d3d8 import d3d8 - print r'#include ' - print r'#include ' + print r'#include "d3d8imports.hpp"' print r'#include "d3d8size.hpp"' api.addModule(d3d8) print - #print '''static d3dretrace::D3DDumper d3d8Dumper;''' + print '''static d3dretrace::D3DDumper d3d8Dumper;''' print else: assert False diff --git a/retrace/d3d9state_images.cpp b/retrace/d3d9state_images.cpp index 81f7f7f..c21573c 100644 --- a/retrace/d3d9state_images.cpp +++ b/retrace/d3d9state_images.cpp @@ -25,6 +25,7 @@ #include +#include #include "image.hpp" #include "json.hpp" @@ -53,7 +54,9 @@ getRenderTargetImage(IDirect3DDevice9 *pDevice, hr = pRenderTarget->GetDesc(&Desc); assert(SUCCEEDED(hr)); - if (Desc.Format != D3DFMT_X8R8G8B8 && Desc.Format != D3DFMT_A8R8G8B8) { + if (Desc.Format != D3DFMT_X8R8G8B8 && + Desc.Format != D3DFMT_A8R8G8B8 && + Desc.Format != D3DFMT_R5G6B5) { std::cerr << "warning: unsupported D3DFORMAT " << Desc.Format << "\n"; goto no_staging; } @@ -81,11 +84,22 @@ getRenderTargetImage(IDirect3DDevice9 *pDevice, dst = image->start(); src = (const unsigned char *)LockedRect.pBits; for (unsigned y = 0; y < Desc.Height; ++y) { - for (unsigned x = 0; x < Desc.Width; ++x) { - dst[3*x + 0] = src[4*x + 2]; - dst[3*x + 1] = src[4*x + 1]; - dst[3*x + 2] = src[4*x + 0]; + if (Desc.Format == D3DFMT_R5G6B5) { + for (unsigned x = 0; x < Desc.Width; ++x) { + uint32_t pixel = ((const uint16_t *)src)[x]; + dst[3*x + 0] = (( pixel & 0x1f) * (2*0xff) + 0x1f) / (2*0x1f); + dst[3*x + 1] = (((pixel >> 5) & 0x3f) * (2*0xff) + 0x3f) / (2*0x3f); + dst[3*x + 2] = (( pixel >> 11 ) * (2*0xff) + 0x1f) / (2*0x1f); + dst[3*x + 3] = 0xff; + } + } else { + for (unsigned x = 0; x < Desc.Width; ++x) { + dst[3*x + 0] = src[4*x + 2]; + dst[3*x + 1] = src[4*x + 1]; + dst[3*x + 2] = src[4*x + 0]; + } } + src += LockedRect.Pitch; dst += image->stride(); } diff --git a/retrace/d3dretrace_dxgi.hpp b/retrace/d3dretrace_dxgi.hpp new file mode 100644 index 0000000..6fa4900 --- /dev/null +++ b/retrace/d3dretrace_dxgi.hpp @@ -0,0 +1,249 @@ +/************************************************************************** + * + * Copyright 2012 VMware Inc + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _D3DRETRACE_DXGI_HPP_ +#define _D3DRETRACE_DXGI_HPP_ + + +#include "dxgiint.h" + + +/* + * This module implements the IDXGIFactoryDWM and IDXGISwapChainDWM + * undocumented interfaces used by DWM, in terms of the standard IDXGIFactory + * and IDXGISwapChain interfaces, just for sake of d3dretrace. Retracing on + * top of the undocumented interfaces works, but it may interfere with running + * DWM and causes corruption of the desktop upon exit. + */ + + +#define FORCE_WINDOWED 1 + + +namespace d3dretrace { + + +class CDXGISwapChainDWM : public IDXGISwapChainDWM +{ +private: + IDXGISwapChain *m_pSwapChain; + +public: + CDXGISwapChainDWM(IDXGISwapChain *pSwapChain); + ~CDXGISwapChainDWM(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj); + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID Name, UINT DataSize, const void *pData); + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID Name, const IUnknown *pUnknown); + HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID Name, UINT *pDataSize, void *pData); + HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void **ppParent); + HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, void **ppDevice); + + HRESULT STDMETHODCALLTYPE Present(UINT SyncInterval, UINT Flags); + HRESULT STDMETHODCALLTYPE GetBuffer(UINT Buffer, REFIID riid, void **ppSurface); + HRESULT STDMETHODCALLTYPE GetDesc(DXGI_SWAP_CHAIN_DESC *pDesc); + HRESULT STDMETHODCALLTYPE ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); + HRESULT STDMETHODCALLTYPE ResizeTarget(const DXGI_MODE_DESC *pNewTargetParameters); + HRESULT STDMETHODCALLTYPE GetContainingOutput(IDXGIOutput **ppOutput); + HRESULT STDMETHODCALLTYPE GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats); + HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount); + HRESULT STDMETHODCALLTYPE SetFullscreenState(BOOL Fullscreen, IDXGIOutput *pTarget); + HRESULT STDMETHODCALLTYPE GetFullscreenState(BOOL *pFullscreen, IDXGIOutput **ppTarget); +}; + +CDXGISwapChainDWM::CDXGISwapChainDWM(IDXGISwapChain *pSwapChain) : + m_pSwapChain(pSwapChain) +{ +} + +CDXGISwapChainDWM::~CDXGISwapChainDWM() +{ + m_pSwapChain->SetFullscreenState(FALSE, NULL); + m_pSwapChain->Release(); +} + + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::QueryInterface(REFIID riid, void **ppvObj) +{ + return m_pSwapChain->QueryInterface(riid, ppvObj); +} + +ULONG STDMETHODCALLTYPE CDXGISwapChainDWM::AddRef(void) +{ + // FIXME + return 1; +} + +ULONG STDMETHODCALLTYPE CDXGISwapChainDWM::Release(void) +{ + // FIXME + return 1; +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::SetPrivateData(REFGUID Name, UINT DataSize, const void *pData) +{ + return m_pSwapChain->SetPrivateData(Name, DataSize, pData); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::SetPrivateDataInterface(REFGUID Name, const IUnknown *pUnknown) +{ + return m_pSwapChain->SetPrivateDataInterface(Name, pUnknown); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetPrivateData(REFGUID Name, UINT *pDataSize, void *pData) +{ + return m_pSwapChain->GetPrivateData(Name, pDataSize, pData); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetParent(REFIID riid, void **ppParent) +{ + return m_pSwapChain->GetParent(riid, ppParent); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetDevice(REFIID riid, void **ppDevice) +{ + return m_pSwapChain->GetDevice(riid, ppDevice); +} + + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::Present(UINT SyncInterval, UINT Flags) +{ + return m_pSwapChain->Present(SyncInterval, Flags); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetBuffer(UINT Buffer, REFIID riid, void **ppSurface) +{ + return m_pSwapChain->GetBuffer(Buffer, riid, ppSurface); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetDesc(DXGI_SWAP_CHAIN_DESC *pDesc) +{ + return m_pSwapChain->GetDesc(pDesc); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +{ + return m_pSwapChain->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::ResizeTarget(const DXGI_MODE_DESC *pNewTargetParameters) +{ + return m_pSwapChain->ResizeTarget(pNewTargetParameters); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetContainingOutput(IDXGIOutput **ppOutput) +{ + return m_pSwapChain->GetContainingOutput(ppOutput); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) +{ + return m_pSwapChain->GetFrameStatistics(pStats); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetLastPresentCount(UINT *pLastPresentCount) +{ + return m_pSwapChain->GetLastPresentCount(pLastPresentCount); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::SetFullscreenState(BOOL Fullscreen, IDXGIOutput *pTarget) +{ + return m_pSwapChain->SetFullscreenState(Fullscreen, pTarget); +} + +HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::GetFullscreenState(BOOL *pFullscreen, IDXGIOutput **ppTarget) +{ + return m_pSwapChain->GetFullscreenState(pFullscreen, ppTarget); +} + + + +class CDXGIFactoryDWM : public IDXGIFactoryDWM +{ +private: + IDXGIFactory *m_pFactory; + + ~CDXGIFactoryDWM(); + +public: + CDXGIFactoryDWM(IDXGIFactory *pFactory); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj); + ULONG STDMETHODCALLTYPE AddRef(void); + ULONG STDMETHODCALLTYPE Release(void); + HRESULT STDMETHODCALLTYPE CreateSwapChain(IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGIOutput *pOutput, IDXGISwapChainDWM **ppSwapChain); +}; + +CDXGIFactoryDWM::CDXGIFactoryDWM(IDXGIFactory *pFactory) : + m_pFactory(pFactory) +{} + +CDXGIFactoryDWM::~CDXGIFactoryDWM() +{ + m_pFactory->Release(); +} + + +HRESULT STDMETHODCALLTYPE CDXGIFactoryDWM::QueryInterface(REFIID riid, void **ppvObj) +{ + return m_pFactory->QueryInterface(riid, ppvObj); +} + +ULONG STDMETHODCALLTYPE CDXGIFactoryDWM::AddRef(void) +{ + // FIXME + return 1; +} + +ULONG STDMETHODCALLTYPE CDXGIFactoryDWM::Release(void) +{ + // FIXME + return 1; +} + +HRESULT STDMETHODCALLTYPE CDXGIFactoryDWM::CreateSwapChain(IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGIOutput *pOutput, IDXGISwapChainDWM **ppSwapChain) +{ + IDXGISwapChain *pSwapChain = NULL; + if (FORCE_WINDOWED) { + pDesc->Windowed = TRUE; + } + HRESULT hr = m_pFactory->CreateSwapChain(pDevice, pDesc, &pSwapChain); + if (SUCCEEDED(hr)) { + if (!FORCE_WINDOWED) { + pSwapChain->SetFullscreenState(TRUE, pOutput); + } + *ppSwapChain = new CDXGISwapChainDWM(pSwapChain); + } + return hr; +} + + + +} /* namespace d3dretrace */ + + +#endif /* _D3DRETRACE_DXGI_HPP_ */ diff --git a/retrace/d3dstate.hpp b/retrace/d3dstate.hpp index 3766a91..eb0e3cd 100644 --- a/retrace/d3dstate.hpp +++ b/retrace/d3dstate.hpp @@ -32,6 +32,7 @@ #include +struct IDirect3DDevice8; struct IDirect3DDevice9; struct ID3D10Device; struct ID3D11DeviceContext; @@ -50,6 +51,16 @@ namespace d3dstate { extern const GUID GUID_D3DSTATE; +image::Image * +getRenderTargetImage(IDirect3DDevice8 *pDevice); + +void +dumpFramebuffer(JSONWriter &json, IDirect3DDevice8 *pDevice); + +void +dumpDevice(std::ostream &os, IDirect3DDevice8 *pDevice); + + image::Image * getRenderTargetImage(IDirect3DDevice9 *pDevice); diff --git a/retrace/dxgiretrace.py b/retrace/dxgiretrace.py index 8de3c98..6a51a4d 100644 --- a/retrace/dxgiretrace.py +++ b/retrace/dxgiretrace.py @@ -29,6 +29,7 @@ import sys from dllretrace import DllRetracer as Retracer +import specs.dxgi from specs.stdapi import API from specs.dxgi import dxgi from specs.d3d10 import d3d10 @@ -45,13 +46,11 @@ class D3DRetracer(Retracer): print r''' static void createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) { - if (pSwapChainDesc->Windowed) { - UINT Width = pSwapChainDesc->BufferDesc.Width; - UINT Height = pSwapChainDesc->BufferDesc.Height; - if (!Width) Width = 1024; - if (!Height) Height = 768; - pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height); - } + UINT Width = pSwapChainDesc->BufferDesc.Width; + UINT Height = pSwapChainDesc->BufferDesc.Height; + if (!Width) Width = 1024; + if (!Height) Height = 768; + pSwapChainDesc->OutputWindow = d3dretrace::createWindow(Width, Height); } ''' @@ -163,6 +162,16 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) { else: print r' d3d11Dumper.bindDevice(_this);' + if interface.name == 'IDXGIFactory' and method.name == 'QueryInterface': + print r' if (riid == IID_IDXGIFactoryDWM) {' + print r' _this->AddRef();' + print r' *ppvObj = new d3dretrace::CDXGIFactoryDWM(_this);' + print r' _result = S_OK;' + print r' } else {' + Retracer.invokeInterfaceMethod(self, interface, method) + print r' }' + return + # create windows as neccessary if method.name == 'CreateSwapChain': print r' createWindow(pDesc);' @@ -205,6 +214,46 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) { print r' }' return + if interface.name.startswith('ID3D10Device') and method.name == 'OpenSharedResource': + print r' retrace::warning(call) << "replacing shared resource with checker pattern\n";' + print r' D3D10_TEXTURE2D_DESC Desc;' + print r' memset(&Desc, 0, sizeof Desc);' + print r' Desc.Width = 8;' + print r' Desc.Height = 8;' + print r' Desc.MipLevels = 1;' + print r' Desc.ArraySize = 1;' + print r' Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;' + print r' Desc.SampleDesc.Count = 1;' + print r' Desc.SampleDesc.Quality = 0;' + print r' Desc.Usage = D3D10_USAGE_DEFAULT;' + print r' Desc.BindFlags = D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET;' + print r' Desc.CPUAccessFlags = 0x0;' + print r' Desc.MiscFlags = 0 /* D3D10_RESOURCE_MISC_SHARED */;' + print r''' + const DWORD Checker[8][8] = { + { 0, ~0, 0, ~0, 0, ~0, 0, ~0, }, + {~0, 0, ~0, 0, ~0, 0, ~0, 0, }, + { 0, ~0, 0, ~0, 0, ~0, 0, ~0, }, + {~0, 0, ~0, 0, ~0, 0, ~0, 0, }, + { 0, ~0, 0, ~0, 0, ~0, 0, ~0, }, + {~0, 0, ~0, 0, ~0, 0, ~0, 0, }, + { 0, ~0, 0, ~0, 0, ~0, 0, ~0, }, + {~0, 0, ~0, 0, ~0, 0, ~0, 0, } + }; + const D3D10_SUBRESOURCE_DATA InitialData = {Checker, sizeof Checker[0], sizeof Checker}; + ''' + print r' _result = _this->CreateTexture2D(&Desc, &InitialData, (ID3D10Texture2D**)ppResource);' + self.checkResult(method.type) + return + + if method.name == 'Map': + # Reset _DO_NOT_WAIT flags. Otherwise they may fail, and we have no + # way to cope with it (other than retry). + mapFlagsArg = method.getArgByName('MapFlags') + for flag in mapFlagsArg.type.values: + if flag.endswith('_MAP_FLAG_DO_NOT_WAIT'): + print r' MapFlags &= ~%s;' % flag + Retracer.invokeInterfaceMethod(self, interface, method) # process events after presents @@ -239,6 +288,8 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) { def main(): + print r'#define INITGUID' + print print r'#include ' print print r'#include ' @@ -251,6 +302,7 @@ def main(): api = API() if moduleNames: + print r'#include "d3dretrace_dxgi.hpp"' api.addModule(dxgi) if 'd3d10' in moduleNames: diff --git a/retrace/glretrace.hpp b/retrace/glretrace.hpp index 95a6d75..7441b56 100644 --- a/retrace/glretrace.hpp +++ b/retrace/glretrace.hpp @@ -60,7 +60,7 @@ struct Context { extern bool insideList; extern bool insideGlBeginEnd; - +extern bool supportsARBShaderObjects; Context * getCurrentContext(void); diff --git a/retrace/glretrace_cgl.cpp b/retrace/glretrace_cgl.cpp index a075595..f0d0e2d 100644 --- a/retrace/glretrace_cgl.cpp +++ b/retrace/glretrace_cgl.cpp @@ -311,18 +311,23 @@ static void retrace_CGLTexImageIOSurface2D(trace::Call &call) { const retrace::Entry glretrace::cgl_callbacks[] = { {"CGLChoosePixelFormat", &retrace_CGLChoosePixelFormat}, - {"CGLDestroyPixelFormat", &retrace::ignore}, {"CGLCreateContext", &retrace_CGLCreateContext}, {"CGLDestroyContext", &retrace_CGLDestroyContext}, - {"CGLSetCurrentContext", &retrace_CGLSetCurrentContext}, - {"CGLGetCurrentContext", &retrace::ignore}, - {"CGLEnable", &retrace::ignore}, + {"CGLDestroyPixelFormat", &retrace::ignore}, {"CGLDisable", &retrace::ignore}, - {"CGLSetParameter", &retrace::ignore}, - {"CGLGetParameter", &retrace::ignore}, + {"CGLEnable", &retrace::ignore}, + {"CGLErrorString", &retrace::ignore}, {"CGLFlushDrawable", &retrace_CGLFlushDrawable}, - {"CGLUpdateContext", &retrace::ignore}, + {"CGLGetCurrentContext", &retrace::ignore}, + {"CGLGetOption", &retrace::ignore}, + {"CGLGetParameter", &retrace::ignore}, + {"CGLGetVersion", &retrace::ignore}, + {"CGLGetVirtualScreen", &retrace::ignore}, + {"CGLIsEnabled", &retrace::ignore}, + {"CGLSetCurrentContext", &retrace_CGLSetCurrentContext}, + {"CGLSetParameter", &retrace::ignore}, {"CGLTexImageIOSurface2D", &retrace_CGLTexImageIOSurface2D}, + {"CGLUpdateContext", &retrace::ignore}, {NULL, NULL}, }; diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp index 1418ca3..1591287 100755 --- a/retrace/glretrace_main.cpp +++ b/retrace/glretrace_main.cpp @@ -1,6 +1,8 @@ /************************************************************************** * * Copyright 2011 Jose Fonseca + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Shuang He * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -31,6 +33,7 @@ #include "glstate.hpp" #include "glretrace.hpp" #include "os_time.hpp" +#include "os_memory.hpp" /* Synchronous debug output may reduce performance however, * without it the callNo in the callback may be inaccurate @@ -42,16 +45,28 @@ namespace glretrace { bool insideList = false; bool insideGlBeginEnd = false; +bool supportsARBShaderObjects = false; + +enum { + GPU_START = 0, + GPU_DURATION, + OCCLUSION, + NUM_QUERIES, +}; struct CallQuery { - GLuint ids[3]; + GLuint ids[NUM_QUERIES]; unsigned call; bool isDraw; GLuint program; const trace::FunctionSig *sig; int64_t cpuStart; int64_t cpuEnd; + int64_t vsizeStart; + int64_t vsizeEnd; + int64_t rssStart; + int64_t rssEnd; }; static bool supportsElapsed = true; @@ -109,48 +124,55 @@ checkGlError(trace::Call &call) { } } -static void -getCurrentTimes(int64_t& cpuTime, int64_t& gpuTime) { - GLuint query; - +static inline int64_t +getCurrentTime(void) { if (retrace::profilingGpuTimes && supportsTimestamp) { - glGenQueries(1, &query); - glQueryCounter(query, GL_TIMESTAMP); - glGetQueryObjecti64vEXT(query, GL_QUERY_RESULT, &gpuTime); + /* Get the current GL time without stalling */ + GLint64 timestamp = 0; + glGetInteger64v(GL_TIMESTAMP, ×tamp); + return timestamp; } else { - gpuTime = 0; + return os::getTime(); } +} - if (retrace::profilingCpuTimes) { - cpuTime = os::getTime(); +static inline int64_t +getTimeFrequency(void) { + if (retrace::profilingGpuTimes && supportsTimestamp) { + return 1000000000; } else { - cpuTime = 0; + return os::timeFrequency; } +} - if (retrace::profilingGpuTimes && supportsTimestamp) { - glDeleteQueries(1, &query); - } +static inline void +getCurrentVsize(int64_t& vsize) { + vsize = os::getVsize(); +} + +static inline void +getCurrentRss(int64_t& rss) { + rss = os::getRss(); } static void completeCallQuery(CallQuery& query) { /* Get call start and duration */ - int64_t gpuStart = 0, gpuDuration = 0, cpuDuration = 0, pixels = 0; + int64_t gpuStart = 0, gpuDuration = 0, cpuDuration = 0, pixels = 0, vsizeDuration = 0, rssDuration = 0; if (query.isDraw) { if (retrace::profilingGpuTimes) { if (supportsTimestamp) { - glGetQueryObjecti64vEXT(query.ids[0], GL_QUERY_RESULT, &gpuStart); + glGetQueryObjecti64vEXT(query.ids[GPU_START], GL_QUERY_RESULT, &gpuStart); } - glGetQueryObjecti64vEXT(query.ids[1], GL_QUERY_RESULT, &gpuDuration); + glGetQueryObjecti64vEXT(query.ids[GPU_DURATION], GL_QUERY_RESULT, &gpuDuration); } if (retrace::profilingPixelsDrawn) { - glGetQueryObjecti64vEXT(query.ids[2], GL_QUERY_RESULT, &pixels); + glGetQueryObjecti64vEXT(query.ids[OCCLUSION], GL_QUERY_RESULT, &pixels); } - glDeleteQueries(3, query.ids); } else { pixels = -1; } @@ -159,8 +181,15 @@ completeCallQuery(CallQuery& query) { cpuDuration = query.cpuEnd - query.cpuStart; } + if (retrace::profilingMemoryUsage) { + vsizeDuration = query.vsizeEnd - query.vsizeStart; + rssDuration = query.rssEnd - query.rssStart; + } + + glDeleteQueries(NUM_QUERIES, query.ids); + /* Add call to profile */ - retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration); + retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration, query.vsizeStart, vsizeDuration, query.rssStart, rssDuration); } void @@ -183,20 +212,20 @@ beginProfile(trace::Call &call, bool isDraw) { query.sig = call.sig; query.program = currentContext ? currentContext->activeProgram : 0; + glGenQueries(NUM_QUERIES, query.ids); + /* GPU profiling only for draw calls */ if (isDraw) { - glGenQueries(3, query.ids); - if (retrace::profilingGpuTimes) { if (supportsTimestamp) { - glQueryCounter(query.ids[0], GL_TIMESTAMP); + glQueryCounter(query.ids[GPU_START], GL_TIMESTAMP); } - glBeginQuery(GL_TIME_ELAPSED, query.ids[1]); + glBeginQuery(GL_TIME_ELAPSED, query.ids[GPU_DURATION]); } if (retrace::profilingPixelsDrawn) { - glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]); + glBeginQuery(GL_SAMPLES_PASSED, query.ids[OCCLUSION]); } } @@ -204,18 +233,24 @@ beginProfile(trace::Call &call, bool isDraw) { /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { - callQueries.back().cpuStart = os::getTime(); + CallQuery& query = callQueries.back(); + query.cpuStart = getCurrentTime(); + } + + if (retrace::profilingMemoryUsage) { + CallQuery& query = callQueries.back(); + query.vsizeStart = os::getVsize(); + query.rssStart = os::getRss(); } } void endProfile(trace::Call &call, bool isDraw) { - GLint64 time = os::getTime(); /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { CallQuery& query = callQueries.back(); - query.cpuEnd = time; + query.cpuEnd = getCurrentTime(); } /* GPU profiling only for draw calls */ @@ -228,6 +263,12 @@ endProfile(trace::Call &call, bool isDraw) { glEndQuery(GL_SAMPLES_PASSED); } } + + if (retrace::profilingMemoryUsage) { + CallQuery& query = callQueries.back(); + query.vsizeEnd = os::getVsize(); + query.rssEnd = os::getRss(); + } } void @@ -240,6 +281,7 @@ initContext() { supportsElapsed = currentContext->hasExtension("GL_EXT_timer_query") || supportsTimestamp; supportsOcclusion = currentContext->hasExtension("GL_ARB_occlusion_query"); supportsDebugOutput = currentContext->hasExtension("GL_ARB_debug_output"); + supportsARBShaderObjects = currentContext->hasExtension("GL_ARB_shader_objects"); /* Check for timer query support */ if (retrace::profilingGpuTimes) { @@ -276,13 +318,19 @@ initContext() { /* Sync the gpu and cpu start times */ if (retrace::profilingCpuTimes || retrace::profilingGpuTimes) { if (!retrace::profiler.hasBaseTimes()) { - GLint64 gpuTime, cpuTime; - - getCurrentTimes(cpuTime, gpuTime); - retrace::profiler.setBaseCpuTime(cpuTime); - retrace::profiler.setBaseGpuTime(gpuTime); + GLint64 currentTime = getCurrentTime(); + retrace::profiler.setBaseCpuTime(currentTime); + retrace::profiler.setBaseGpuTime(currentTime); } } + + if (retrace::profilingMemoryUsage) { + GLint64 currentVsize, currentRss; + getCurrentVsize(currentVsize); + retrace::profiler.setBaseVsizeUsage(currentVsize); + getCurrentRss(currentRss); + retrace::profiler.setBaseRssUsage(currentRss); + } } void @@ -291,23 +339,6 @@ frame_complete(trace::Call &call) { /* Complete any remaining queries */ flushQueries(); - /* GPU time drifts due to being relative times, not absolute and can be - * affected by the gpu switch between processes. - * - * To attempt to compensate we resynchronise on frame end however there is - * still noticeable drift within a single frame which we do not account for. - */ - if (retrace::profilingCpuTimes || retrace::profilingGpuTimes) { - int64_t cpuTime, gpuTime, error; - - getCurrentTimes(cpuTime, gpuTime); - cpuTime = cpuTime - retrace::profiler.getBaseCpuTime(); - gpuTime = gpuTime - retrace::profiler.getBaseGpuTime(); - error = gpuTime - cpuTime * (1.0E9 / os::timeFrequency); - - retrace::profiler.setBaseGpuTime(retrace::profiler.getBaseGpuTime() + error); - } - /* Indicate end of current frame */ retrace::profiler.addFrameEnd(); } diff --git a/retrace/glstate.cpp b/retrace/glstate.cpp index 0d5a5f3..e2c6978 100644 --- a/retrace/glstate.cpp +++ b/retrace/glstate.cpp @@ -66,29 +66,56 @@ Context::Context(void) { void Context::resetPixelPackState(void) { + // Start with default state + pack_alignment = 4; + pack_image_height = 0; + pack_lsb_first = GL_FALSE; + pack_row_length = 0; + pack_skip_images = 0; + pack_skip_pixels = 0; + pack_skip_rows = 0; + pack_swap_bytes = GL_FALSE; + pixel_pack_buffer_binding = 0; + + // Get current state + glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment); if (!ES) { - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE); + glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &pack_image_height); + glGetIntegerv(GL_PACK_LSB_FIRST, &pack_lsb_first); + glGetIntegerv(GL_PACK_ROW_LENGTH, &pack_row_length); + glGetIntegerv(GL_PACK_SKIP_IMAGES, &pack_skip_images); + glGetIntegerv(GL_PACK_SKIP_PIXELS, &pack_skip_pixels); + glGetIntegerv(GL_PACK_SKIP_ROWS, &pack_skip_rows); + glGetIntegerv(GL_PACK_SWAP_BYTES, &pack_swap_bytes); + glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &pixel_pack_buffer_binding); + } + + // Reset state for compact images + glPixelStorei(GL_PACK_ALIGNMENT, 1); + if (!ES) { + glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_SKIP_IMAGES, 0); - } else { - packAlignment = 4; - glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); } - glPixelStorei(GL_PACK_ALIGNMENT, 1); } void Context::restorePixelPackState(void) { + glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment); if (!ES) { - glPopClientAttrib(); - } else { - glPixelStorei(GL_PACK_ALIGNMENT, packAlignment); + glPixelStorei(GL_PACK_IMAGE_HEIGHT, pack_image_height); + glPixelStorei(GL_PACK_LSB_FIRST, pack_lsb_first); + glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length); + glPixelStorei(GL_PACK_SKIP_IMAGES, pack_skip_images); + glPixelStorei(GL_PACK_SKIP_PIXELS, pack_skip_pixels); + glPixelStorei(GL_PACK_SKIP_ROWS, pack_skip_rows); + glPixelStorei(GL_PACK_SWAP_BYTES, pack_swap_bytes); + glBindBuffer(GL_PIXEL_PACK_BUFFER, pixel_pack_buffer_binding); } } diff --git a/retrace/glstate_images.cpp b/retrace/glstate_images.cpp index 7b0a424..598d56c 100644 --- a/retrace/glstate_images.cpp +++ b/retrace/glstate_images.cpp @@ -745,13 +745,22 @@ getDrawBufferImage() { if (draw_buffer == GL_NONE) { return NULL; } + } else { + // GL_COLOR_ATTACHMENT0 is implied + draw_buffer = GL_COLOR_ATTACHMENT0; } if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) { return NULL; } } else { - if (!context.ES) { + if (context.ES) { + // XXX: Draw buffer is always FRONT for single buffer context, BACK + // for double buffered contexts. There is no way to know which (as + // GL_DOUBLEBUFFER state is also unavailable), so always assume + // double-buffering. + draw_buffer = GL_BACK; + } else { glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer); if (draw_buffer == GL_NONE) { return NULL; @@ -968,16 +977,21 @@ dumpDrawableImages(JSONWriter &json, Context &context) GLint draw_buffer = GL_NONE; if (context.ES) { + // XXX: Draw buffer is always FRONT for single buffer context, BACK for + // double buffered contexts. There is no way to know which (as + // GL_DOUBLEBUFFER state is also unavailable), so always assume + // double-buffering. draw_buffer = GL_BACK; } else { glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer); - glReadBuffer(draw_buffer); } if (draw_buffer != GL_NONE) { + // Read from current draw buffer GLint read_buffer = GL_NONE; if (!context.ES) { glGetIntegerv(GL_READ_BUFFER, &read_buffer); + glReadBuffer(draw_buffer); } GLint alpha_bits = 0; @@ -990,6 +1004,7 @@ dumpDrawableImages(JSONWriter &json, Context &context) dumpReadBufferImage(json, width, height, format); json.endMember(); + // Restore original read buffer if (!context.ES) { glReadBuffer(read_buffer); } diff --git a/retrace/glstate_internal.hpp b/retrace/glstate_internal.hpp index a709da3..6b74b1d 100644 --- a/retrace/glstate_internal.hpp +++ b/retrace/glstate_internal.hpp @@ -44,13 +44,23 @@ struct Context Context(void); - GLint packAlignment; - void resetPixelPackState(void); void restorePixelPackState(void); + +private: + // Pack state + GLint pack_alignment; + GLint pack_image_height; + GLint pack_lsb_first; + GLint pack_row_length; + GLint pack_skip_images; + GLint pack_skip_pixels; + GLint pack_skip_rows; + GLint pack_swap_bytes; + GLint pixel_pack_buffer_binding; }; diff --git a/retrace/glstate_params.py b/retrace/glstate_params.py index 6db4b80..50693a9 100644 --- a/retrace/glstate_params.py +++ b/retrace/glstate_params.py @@ -156,12 +156,21 @@ class StateGetter(Visitor): elem_type = self.inflector.reduced_type(array.type) inflection = self.inflector.inflect(array.type) assert inflection.endswith('v') - print ' %s %s[%s + 1];' % (elem_type, temp_name, array.length) - print ' memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name) - print ' %s[%s] = (%s)0xdeadc0de;' % (temp_name, array.length, elem_type) + array_length = array.length + if array_length.isdigit(): + # Static integer length + print ' %s %s[%s + 1];' % (elem_type, temp_name, array_length) + else: + # Put the length in a variable to avoid recomputing it every time + print ' size_t _%s_length = %s;' % (temp_name, array_length) + array_length = '_%s_length' % temp_name + # Allocate a dynamic sized array + print ' %s *%s = _allocator.alloc<%s>(%s + 1);' % (elem_type, temp_name, elem_type, array_length) + print ' memset(%s, 0, %s * sizeof *%s);' % (temp_name, array_length, temp_name) + print ' %s[%s] = (%s)0xdeadc0de;' % (temp_name, array_length, elem_type) print ' %s(%s, %s);' % (inflection + self.suffix, ', '.join(args), temp_name) # Simple buffer overflow detection - print ' assert(%s[%s] == (%s)0xdeadc0de);' % (temp_name, array.length, elem_type) + print ' assert(%s[%s] == (%s)0xdeadc0de);' % (temp_name, array_length, elem_type) return temp_name def visitOpaque(self, pointer, args): @@ -257,6 +266,7 @@ class StateDumper: print '#include ' print print '#include "json.hpp"' + print '#include "scoped_allocator.hpp"' print '#include "glproc.hpp"' print '#include "glsize.hpp"' print '#include "glstate.hpp"' @@ -316,6 +326,9 @@ class StateDumper: print 'void dumpParameters(JSONWriter &json, Context &context)' print '{' + print ' ScopedAllocator _allocator;' + print ' (void)_allocator;' + print print ' json.beginMember("parameters");' print ' json.beginObject();' diff --git a/retrace/retrace.hpp b/retrace/retrace.hpp index 228c813..14317cf 100644 --- a/retrace/retrace.hpp +++ b/retrace/retrace.hpp @@ -1,6 +1,8 @@ /************************************************************************** * * Copyright 2011-2012 Jose Fonseca + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Shuang He * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -28,7 +30,6 @@ #include #include -#include #include #include @@ -38,6 +39,8 @@ #include "trace_parser.hpp" #include "trace_profiler.hpp" +#include "scoped_allocator.hpp" + namespace image { class Image; @@ -51,37 +54,9 @@ extern trace::Parser parser; extern trace::Profiler profiler; -/** - * Similar to alloca(), but implemented with malloc. - */ -class ScopedAllocator +class ScopedAllocator : public ::ScopedAllocator { -private: - uintptr_t next; - public: - inline - ScopedAllocator() : - next(0) { - } - - inline void * - alloc(size_t size) { - /* Always return valid address, even when size is zero */ - size = std::max(size, sizeof(uintptr_t)); - - uintptr_t * buf = static_cast(malloc(sizeof(uintptr_t) + size)); - if (!buf) { - return NULL; - } - - *buf = next; - next = reinterpret_cast(buf); - assert((next & 1) == 0); - - return static_cast(&buf[1]); - } - /** * Allocate an array with the same dimensions as the specified value. */ @@ -89,7 +64,7 @@ public: alloc(const trace::Value *value, size_t size) { const trace::Array *array = dynamic_cast(value); if (array) { - return alloc(array->size() * size); + return ::ScopedAllocator::alloc(array->size() * size); } const trace::Null *null = dynamic_cast(value); if (null) { @@ -99,32 +74,6 @@ public: return NULL; } - /** - * Prevent this pointer from being automatically freed. - */ - template< class T > - inline void - bind(T *ptr) { - if (ptr) { - reinterpret_cast(ptr)[-1] |= 1; - } - } - - inline - ~ScopedAllocator() { - while (next) { - uintptr_t temp = *reinterpret_cast(next); - - bool bind = temp & 1; - temp &= ~1; - - if (!bind) { - free(reinterpret_cast(next)); - } - - next = temp; - } - } }; @@ -145,6 +94,7 @@ extern bool profiling; extern bool profilingCpuTimes; extern bool profilingGpuTimes; extern bool profilingPixelsDrawn; +extern bool profilingMemoryUsage; /** * State dumping. diff --git a/retrace/retrace.py b/retrace/retrace.py index cd5ef1d..70926c0 100644 --- a/retrace/retrace.py +++ b/retrace/retrace.py @@ -166,7 +166,14 @@ class ValueDeserializer(stdapi.Visitor, stdapi.ExpanderMixin): print ' if (retrace::verbosity >= 2) {' print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue) print ' }' - print ' %s = %s;' % (lvalue, new_lvalue) + if (new_lvalue.startswith('_program_map') or new_lvalue.startswith('_shader_map')): + print 'if (glretrace::supportsARBShaderObjects) {' + print ' %s = _handleARB_map[%s];' % (lvalue, lvalue) + print '} else {' + print ' %s = %s;' % (lvalue, new_lvalue) + print '}' + else: + print ' %s = %s;' % (lvalue, new_lvalue) def visitBlob(self, blob, lvalue, rvalue): print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue) @@ -279,8 +286,15 @@ class SwizzledValueRegistrator(stdapi.Visitor, stdapi.ExpanderMixin): OpaqueValueDeserializer().visit(handle.type, '_origResult', rvalue); if handle.range is None: rvalue = "_origResult" - entry = lookupHandle(handle, rvalue) - print " %s = %s;" % (entry, lvalue) + entry = lookupHandle(handle, rvalue) + if (entry.startswith('_program_map') or entry.startswith('_shader_map')): + print 'if (glretrace::supportsARBShaderObjects) {' + print ' _handleARB_map[%s] = %s;' % (rvalue, lvalue) + print '} else {' + print ' %s = %s;' % (entry, lvalue) + print '}' + else: + print " %s = %s;" % (entry, lvalue) print ' if (retrace::verbosity >= 2) {' print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals()) print ' }' @@ -464,10 +478,9 @@ class Retracer: # On release our reference when we reach Release() == 0 call in the # trace. if method.name == 'Release': - print ' if (call.ret->toUInt()) {' - print ' return;' + print ' if (call.ret->toUInt() == 0) {' + print ' retrace::delObj(call.arg(0));' print ' }' - print ' retrace::delObj(call.arg(0));' arg_names = ", ".join(method.argNames()) if method.type is not stdapi.Void: diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp index 63d3dab..7cc3fca 100644 --- a/retrace/retrace_main.cpp +++ b/retrace/retrace_main.cpp @@ -1,6 +1,8 @@ /************************************************************************** * * Copyright 2011 Jose Fonseca + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Shuang He * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -35,6 +37,7 @@ #include "image.hpp" #include "trace_callset.hpp" #include "trace_dump.hpp" +#include "trace_option.hpp" #include "retrace.hpp" @@ -71,6 +74,8 @@ bool profiling = false; bool profilingGpuTimes = false; bool profilingCpuTimes = false; bool profilingPixelsDrawn = false; +bool profilingMemoryUsage = false; +bool useCallNos = true; unsigned frameNo = 0; unsigned callNo = 0; @@ -92,6 +97,8 @@ Dumper *dumper = &defaultDumper; */ static void takeSnapshot(unsigned call_no) { + static unsigned snapshot_no = 0; + assert(snapshotPrefix || comparePrefix); image::Image *ref = NULL; @@ -116,10 +123,13 @@ takeSnapshot(unsigned call_no) { if (snapshotPrefix) { if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) { char comment[21]; - snprintf(comment, sizeof comment, "%u", call_no); + snprintf(comment, sizeof comment, "%u", + useCallNos ? call_no : snapshot_no); src->writePNM(std::cout, comment); } else { - os::String filename = os::String::format("%s%010u.png", snapshotPrefix, call_no); + os::String filename = os::String::format("%s%010u.png", + snapshotPrefix, + useCallNos ? call_no : snapshot_no); if (src->writePNG(filename) && retrace::verbosity >= 0) { std::cout << "Wrote " << filename << "\n"; } @@ -133,6 +143,8 @@ takeSnapshot(unsigned call_no) { delete src; + snapshot_no++; + return; } @@ -505,8 +517,10 @@ usage(const char *argv0) { " --pcpu cpu profiling (cpu times per call)\n" " --pgpu gpu profiling (gpu times per draw call)\n" " --ppd pixels drawn profiling (pixels drawn per draw call)\n" + " --pmem memory usage profiling (vsize rss per call)\n" " -c, --compare=PREFIX compare against snapshots with given PREFIX\n" " -C, --calls=CALLSET calls to compare (default is every frame)\n" + " --call-nos[=BOOL] use call numbers in snapshot filenames\n" " --core use core profile\n" " --db use a double buffer visual (default)\n" " --driver=DRIVER force driver type (`hw`, `sw`, `ref`, `null`, or driver module name)\n" @@ -519,12 +533,14 @@ usage(const char *argv0) { } enum { - CORE_OPT = CHAR_MAX + 1, + CALL_NOS_OPT = CHAR_MAX + 1, + CORE_OPT, DB_OPT, DRIVER_OPT, PCPU_OPT, PGPU_OPT, PPD_OPT, + PMEM_OPT, SB_OPT, }; @@ -534,6 +550,7 @@ shortOptions = "bc:C:D:hs:S:vw"; const static struct option longOptions[] = { {"benchmark", no_argument, 0, 'b'}, + {"call-nos", optional_argument, 0, CALL_NOS_OPT }, {"calls", required_argument, 0, 'C'}, {"compare", required_argument, 0, 'c'}, {"core", no_argument, 0, CORE_OPT}, @@ -544,6 +561,7 @@ longOptions[] = { {"pcpu", no_argument, 0, PCPU_OPT}, {"pgpu", no_argument, 0, PGPU_OPT}, {"ppd", no_argument, 0, PPD_OPT}, + {"pmem", no_argument, 0, PMEM_OPT}, {"sb", no_argument, 0, SB_OPT}, {"snapshot-prefix", required_argument, 0, 's'}, {"snapshot", required_argument, 0, 'S'}, @@ -578,6 +596,9 @@ int main(int argc, char **argv) retrace::debug = false; retrace::verbosity = -1; break; + case CALL_NOS_OPT: + useCallNos = trace::boolOption(optarg); + break; case 'c': comparePrefix = optarg; if (compareFrequency.empty()) { @@ -661,6 +682,13 @@ int main(int argc, char **argv) retrace::profilingPixelsDrawn = true; break; + case PMEM_OPT: + retrace::debug = false; + retrace::profiling = true; + retrace::verbosity = -1; + + retrace::profilingMemoryUsage = true; + break; default: std::cerr << "error: unknown option " << opt << "\n"; usage(argv[0]); @@ -670,7 +698,7 @@ int main(int argc, char **argv) retrace::setUp(); if (retrace::profiling) { - retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn); + retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage); } os::setExceptionCallback(exceptionCallback); diff --git a/retrace/scoped_allocator.hpp b/retrace/scoped_allocator.hpp new file mode 100644 index 0000000..f44b74f --- /dev/null +++ b/retrace/scoped_allocator.hpp @@ -0,0 +1,101 @@ +/************************************************************************** + * + * Copyright 2011-2012 Jose Fonseca + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _SCOPED_ALLOCATOR_HPP_ +#define _SCOPED_ALLOCATOR_HPP_ + + +#include +#include +#include + + +/** + * Similar to alloca(), but implemented with malloc. + */ +class ScopedAllocator +{ +private: + uintptr_t next; + +public: + inline + ScopedAllocator() : + next(0) { + } + + inline void * + alloc(size_t size) { + /* Always return valid address, even when size is zero */ + size = std::max(size, sizeof(uintptr_t)); + + uintptr_t * buf = static_cast(malloc(sizeof(uintptr_t) + size)); + if (!buf) { + return NULL; + } + + *buf = next; + next = reinterpret_cast(buf); + assert((next & 1) == 0); + + return static_cast(&buf[1]); + } + + template< class T > + inline T * + alloc(size_t size = 1) { + return static_cast(alloc(sizeof(T) * size)); + } + + /** + * Prevent this pointer from being automatically freed. + */ + template< class T > + inline void + bind(T *ptr) { + if (ptr) { + reinterpret_cast(ptr)[-1] |= 1; + } + } + + inline + ~ScopedAllocator() { + while (next) { + uintptr_t temp = *reinterpret_cast(next); + + bool bind = temp & 1; + temp &= ~1; + + if (!bind) { + free(reinterpret_cast(next)); + } + + next = temp; + } + } +}; + + +#endif /* _SCOPED_ALLOCATOR_HPP_ */ diff --git a/scripts/apitrace.PIXExp b/scripts/apitrace.PIXExp new file mode 100644 index 0000000..c7b031e --- /dev/null +++ b/scripts/apitrace.PIXExp @@ -0,0 +1,2 @@ + +2020001EDID103%dEvent Type203%dEID303%dParent EID403%dChildren1106%dParent1002%dFlags5020x%08XEvent604%sStartTime705%I64iPath1301%sPath21401%sVersion1501%sTimeLastModified1601%sProcessID2303%dSessionStartTimeStamp2405%I64iFrame903%dDuration805%I64iMeasured Est. Draw Duration (ns)2705%I64iFPS1200%0.01fThisEventPos2105%I64iNextSiblingPos2205%I64iUser Event Name1701%sPackedCallPackage1907Object Pointer20020x%08XSession Start111(edid)2CalcOnLoad,Const,13(eid)4CalcOnLoad,Const,-15CalcOnLoad,Const,07CalcOnLoad,Const,08CalcOnLoad,Const,06CalcOnLoad,FormatText,0,Start Session13(expfilepath)14(runfilepath)24(sessionstarttimestamp)Session End221(edid)2CalcOnLoad,Const,23(eid)4CalcOnLoad,Const,-15CalcOnLoad,Const,07(time)8CalcOnLoad,Const,06CalcOnLoad,FormatText,0,End SessionProcess Start331(edid)2CalcOnLoad,Const,33(eid)4CalcOnLoad,Const,-15CalcOnLoad,Const,07CalcOnLoad,Const,08CalcOnLoad,Const,06CalcOnLoad,FormatText,0,Start Process13(processpath)15(processversion)16(processtimelastmodified)23(processid)Process End441(edid)2CalcOnLoad,Const,43(eid)4CalcOnLoad,Const,-15CalcOnLoad,Const,07(time)8CalcOnLoad,Const,06CalcOnLoad,FormatText,0,End Process13(processpath)Frame Begin551(edid)2CalcOnLoad,Const,53(eid)4(parenteid)11CalcOnLoad,Const,05(rowflags)7(time)9(frame)6CalcOnLoad,FormatText,1,Frame %d,3,MemberOf,ThisRow,Frame8Async,(duration)12CalcOnLoad,Divide,Const,1000000000.0,MemberOf,ThisRow,Duration21(frameeventfilepos)22(lastframeeventfilepos)User Event Begin761(edid)2CalcOnLoad,Const,73(eid)4(parenteid)10CalcOnLoad,Const,011CalcOnLoad,Const,05CalcOnLoad,Const,07(time)17(usereventname)6CalcOnLoad,FormatText,1,%s,1,MemberOf,ThisRow,User Event Name8Async,(duration)User Marker971(edid)2CalcOnLoad,Const,93(eid)4(parenteid)10CalcOnLoad,Const,011CalcOnLoad,Const,05CalcOnLoad,Const,07(time)17(usereventname)6CalcOnLoad,FormatText,1,User Marker: %s,1,MemberOf,ThisRow,User Event Name8CalcOnLoad,Const,0D3D Call1081(edid)2CalcOnLoad,Const,103(eid)4(parenteid)11CalcOnLoad,Const,010CalcOnLoad,Const,05CalcOnLoad,Const,07(time)6CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage19Async,(packedcallpkg)27Async,(drawduration)Object Creation1191(edid)2CalcOnLoad,Const,113(eid)4(parenteid)11CalcOnLoad,Const,010CalcOnLoad,Const,05CalcOnLoad,Const,07(time)6CalcOnLoad,FormatText,0,Object Creation20(objpointer)Object Population12101(edid)2CalcOnLoad,Const,123(eid)4(parenteid)11CalcOnLoad,Const,010CalcOnLoad,Const,05CalcOnLoad,Const,07(time)6CalcOnLoad,FormatText,0,Object Population20(objpointer)D3D Call (Sync)13111(edid)2CalcOnLoad,Const,133(eid)4(parenteid)11CalcOnLoad,Const,010CalcOnLoad,Const,05CalcOnLoad,Const,07(time)6CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage19(packedcallpkg)1010330 diff --git a/scripts/convert.py b/scripts/convert.py new file mode 100755 index 0000000..d5660c0 --- /dev/null +++ b/scripts/convert.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2012 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. +# +##########################################################################/ + +'''Convert traces to/from PIX. +''' + + +import optparse +import os.path +import subprocess +import platform +import sys + + +def convert(inTrace, outPixrun): + try: + programFiles = os.environ['ProgramFiles(x86)'] + except KeyError: + programFiles = os.environ['ProgramFiles'] + try: + dxsdkDir = os.environ['DXSDK_DIR'] + except KeyError: + dxsdkDir = os.path.join(programFiles, "Microsoft DirectX SDL (June 2010)") + pix = os.path.join(dxsdkDir, "Utilities", "bin", 'x86', 'PIXwin.exe') + + pixExp = os.path.join(os.path.dirname(__file__), 'apitrace.PIXExp') + + # http://social.msdn.microsoft.com/Forums/sv/devdocs/thread/15addc0c-036d-413a-854a-35637ccbb834 + # http://src.chromium.org/svn/trunk/o3d/tests/test_driver.py + cmd = [ + pix, + pixExp, + '-start', + '-runfile', os.path.abspath(outPixrun), + '-targetpath', os.path.abspath(options.retrace), + #'-targetstartfolder', ..., + '-targetargs', os.path.abspath(inTrace), + ] + + if options.verbose: + sys.stderr.write(' '.join(cmd) + '\n') + + ret = subprocess.call(cmd) + if ret: + sys.stderr.write('error: pix failued with exit code %u\n' % ret) + sys.exit(ret) + if os.path.exists(outPixrun): + sys.stderr.write('info: %s written\n' % outPixrun) + if False: + subprocess.call([pix, os.path.abspath(outPixrun)]) + else: + sys.stderr.write('error: %s not written\n' % outPixrun) + sys.exit(1) + + +def main(): + global options + + # Parse command line options + optparser = optparse.OptionParser( + usage='\n\t%prog [options] ...', + version='%%prog') + optparser.add_option( + '-r', '--retrace', metavar='PROGRAM', + type='string', dest='retrace', default='d3dretrace', + help='retrace command [default: %default]') + optparser.add_option( + '-v', '--verbose', + action='store_true', dest='verbose', default=False, + help='verbose output') + optparser.add_option( + '-o', '--output', metavar='FILE', + type="string", dest="output", + help="output file [default: stdout]") + + (options, args) = optparser.parse_args(sys.argv[1:]) + if not args: + optparser.error("incorrect number of arguments") + + for arg in args: + if options.output: + output = options.output + else: + name, ext = os.path.splitext(os.path.basename(arg)) + output = name + '.PIXRun' + convert(arg, output) + + +if __name__ == '__main__': + main() diff --git a/specs/cglapi.py b/specs/cglapi.py index 6cea028..89e8917 100644 --- a/specs/cglapi.py +++ b/specs/cglapi.py @@ -221,19 +221,19 @@ cglapi.addFunctions([ Function(CGLError, "CGLFlushDrawable", [(CGLContextObj, "ctx")]), Function(CGLError, "CGLEnable", [(CGLContextObj, "ctx"), (CGLContextEnable, "pname")]), Function(CGLError, "CGLDisable", [(CGLContextObj, "ctx"), (CGLContextEnable, "pname")]), - Function(CGLError, "CGLIsEnabled", [(CGLContextObj, "ctx"), (CGLContextEnable, "pname"), Out(Pointer(GLint), "enable")]), + Function(CGLError, "CGLIsEnabled", [(CGLContextObj, "ctx"), (CGLContextEnable, "pname"), Out(Pointer(GLint), "enable")], sideeffects=False), Function(CGLError, "CGLSetParameter", [(CGLContextObj, "ctx"), (CGLContextParameter, "pname"), (Array(Const(GLint), 1), "params")]), - Function(CGLError, "CGLGetParameter", [(CGLContextObj, "ctx"), (CGLContextParameter, "pname"), Out(Array(GLint, 1), "params")]), + Function(CGLError, "CGLGetParameter", [(CGLContextObj, "ctx"), (CGLContextParameter, "pname"), Out(Array(GLint, 1), "params")], sideeffects=False), Function(CGLError, "CGLSetVirtualScreen", [(CGLContextObj, "ctx"), (GLint, "screen")]), - Function(CGLError, "CGLGetVirtualScreen", [(CGLContextObj, "ctx"), Out(Pointer(GLint), "screen")]), + Function(CGLError, "CGLGetVirtualScreen", [(CGLContextObj, "ctx"), Out(Pointer(GLint), "screen")], sideeffects=False), Function(CGLError, "CGLSetGlobalOption", [(CGLGlobalOption, "pname"), (OpaquePointer(Const(GLint)), "params")]), Function(CGLError, "CGLGetGlobalOption", [(CGLGlobalOption, "pname"), Out(OpaquePointer(GLint), "params")]), Function(CGLError, "CGLSetOption", [(CGLGlobalOption, "pname"), (GLint, "param")]), - Function(CGLError, "CGLGetOption", [(CGLGlobalOption, "pname"), Out(Pointer(GLint), "param")]), + Function(CGLError, "CGLGetOption", [(CGLGlobalOption, "pname"), Out(Pointer(GLint), "param")], sideeffects=False), Function(CGLError, "CGLLockContext", [(CGLContextObj, "ctx")]), Function(CGLError, "CGLUnlockContext", [(CGLContextObj, "ctx")]), - Function(Void, "CGLGetVersion", [Out(Pointer(GLint), "majorvers"), Out(Pointer(GLint), "minorvers")]), - Function(ConstCString, "CGLErrorString", [(CGLError, "error")]), + Function(Void, "CGLGetVersion", [Out(Pointer(GLint), "majorvers"), Out(Pointer(GLint), "minorvers")], sideeffects=False), + Function(ConstCString, "CGLErrorString", [(CGLError, "error")], sideeffects=False), # CGLIOSurface.h, OpenGL framework Function(CGLError, "CGLTexImageIOSurface2D", [(CGLContextObj, "ctx"), (GLenum, "target"), (GLenum, "internal_format"), (GLsizei, "width"), (GLsizei, "height"), (GLenum, "format"), (GLenum, "type"), (IOSurfaceRef, "ioSurface"), (GLuint, "plane")]), diff --git a/specs/d3d9dxva2.py b/specs/d3d9dxva2.py index 36499b7..5c52f98 100644 --- a/specs/d3d9dxva2.py +++ b/specs/d3d9dxva2.py @@ -184,7 +184,7 @@ DXVA2_DecodeExtensionData = Struct("DXVA2_DecodeExtensionData", [ DXVA2_DecodeExecuteParams = Struct("DXVA2_DecodeExecuteParams", [ (UINT, "NumCompBuffers"), - (Pointer(DXVA2_DecodeBufferDesc), "pCompressedBuffers"), + (Array(DXVA2_DecodeBufferDesc, "{self}.NumCompBuffers"), "pCompressedBuffers"), (Pointer(DXVA2_DecodeExtensionData), "pExtensionData"), ]) @@ -263,7 +263,15 @@ DXVA2_VideoProcessorCaps = Struct("DXVA2_VideoProcessorCaps", [ ]) -DXVA2_PVP_SETKEY = Opaque('DXVA2_PVP_SETKEY') +# See also DXVADDI_PVP_KEY128 +DXVA2_PVP_KEY128 = Struct('DXVA2_PVP_KEY128', [ + (Array(BYTE, 16), 'Data'), +]) + +# See also DXVADDI_PVP_SETKEY +DXVA2_PVP_SETKEY = Struct('DXVA2_PVP_SETKEY', [ + (DXVA2_PVP_KEY128, 'ContentKey'), +]) DXVA2_DECODEBUFFERDESC = Struct("DXVA2_DECODEBUFFERDESC", [ (ObjPointer(IDirect3DSurface9), "pRenderTarget"), @@ -321,7 +329,7 @@ DXVA2_DECODEBUFFERINFO = Opaque('DXVA2_DECODEBUFFERINFO') IDirect3DDecodeDevice9 = Interface("IDirect3DDecodeDevice9", IUnknown) IDirect3DDecodeDevice9.methods += [ - StdMethod(HRESULT, "DecodeBeginFrame", [(OpaquePointer(DXVA2_PVP_SETKEY), "pPVPSetKey")]), + StdMethod(HRESULT, "DecodeBeginFrame", [(Pointer(DXVA2_PVP_SETKEY), "pPVPSetKey")]), StdMethod(HRESULT, "DecodeEndFrame", [(Pointer(HANDLE), "pHandleComplete")]), StdMethod(HRESULT, "DecodeSetRenderTarget", [(ObjPointer(IDirect3DSurface9), "pRenderTarget")]), StdMethod(HRESULT, "DecodeExecute", [(Pointer(DXVA2_DECODEEXECUTE), "pExecuteParams")]), diff --git a/specs/d3d9types.py b/specs/d3d9types.py index 8979734..dc9e852 100644 --- a/specs/d3d9types.py +++ b/specs/d3d9types.py @@ -728,6 +728,7 @@ D3DFORMAT = Enum("D3DFORMAT", [ "D3DFMT_INTZ", "D3DFMT_NULL", "D3DFMT_NV12", + "D3DFMT_YV12", "D3DFMT_RAWZ", ]) diff --git a/specs/glparams.py b/specs/glparams.py index 3be99a8..41b5a0f 100644 --- a/specs/glparams.py +++ b/specs/glparams.py @@ -1582,8 +1582,7 @@ parameters = [ ("glGetTexLevelParameter", I, 1, "GL_TEXTURE_COMPRESSED_IMAGE_SIZE"), # 0x86A0 ("glGetTexLevelParameter", B, 1, "GL_TEXTURE_COMPRESSED"), # 0x86A1 ("glGet", I, 1, "GL_NUM_COMPRESSED_TEXTURE_FORMATS"), # 0x86A2 - #XXX: the list is GL_NUM_COMPRESSED_TEXTURES - #("glGet", E, 1, "GL_COMPRESSED_TEXTURE_FORMATS"), # 0x86A3 + ("glGet", E, '_glGetInteger(GL_NUM_COMPRESSED_TEXTURE_FORMATS)', "GL_COMPRESSED_TEXTURE_FORMATS"), # 0x86A3 ("glGet", I, 1, "GL_MAX_VERTEX_UNITS_ARB"), # 0x86A4 ("glGet", I, 1, "GL_ACTIVE_VERTEX_UNITS_ARB"), # 0x86A5 ("glGet", B, 1, "GL_WEIGHT_SUM_UNITY_ARB"), # 0x86A6 @@ -1893,8 +1892,8 @@ parameters = [ ("", X, 1, "GL_VBO_FREE_MEMORY_ATI"), # 0x87FB ("", X, 1, "GL_TEXTURE_FREE_MEMORY_ATI"), # 0x87FC ("", X, 1, "GL_RENDERBUFFER_FREE_MEMORY_ATI"), # 0x87FD - ("", X, 1, "GL_NUM_PROGRAM_BINARY_FORMATS"), # 0x87FE - ("", X, 1, "GL_PROGRAM_BINARY_FORMATS"), # 0x87FF + ("glGet", I, 1, "GL_NUM_PROGRAM_BINARY_FORMATS"), # 0x87FE + ("glGet", E, "_glGetInteger(GL_NUM_PROGRAM_BINARY_FORMATS)", "GL_PROGRAM_BINARY_FORMATS"), # 0x87FF ("glGet", E, 1, "GL_STENCIL_BACK_FUNC"), # 0x8800 ("glGet", E, 1, "GL_STENCIL_BACK_FAIL"), # 0x8801 ("glGet", E, 1, "GL_STENCIL_BACK_PASS_DEPTH_FAIL"), # 0x8802 @@ -2251,12 +2250,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_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 @@ -2371,22 +2370,22 @@ parameters = [ ("", X, 1, "GL_FRAGMENT_SHADER_DERIVATIVE_HINT"), # 0x8B8B ("glGet", S, 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_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 ("glGet", E, 1, "GL_IMPLEMENTATION_COLOR_READ_TYPE"), # 0x8B9A ("glGet", E, 1, "GL_IMPLEMENTATION_COLOR_READ_FORMAT"), # 0x8B9B - #("", X, 1, "GL_POINT_SIZE_ARRAY_OES"), # 0x8B9C + ("", X, 1, "GL_POINT_SIZE_ARRAY_OES"), # 0x8B9C ("glGetTexParameter", I, 4, "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_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 @@ -2504,8 +2503,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 + ("", 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 @@ -2569,18 +2568,18 @@ 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_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 ("", B, 1, "GL_PRIMITIVE_RESTART_FIXED_INDEX"), # 0x8D69 ("", X, 1, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE"), # 0x8D6A ("glGet", I, 1, "GL_MAX_ELEMENT_INDEX"), # 0x8D6B - #("", X, 1, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT"), # 0x8D6C + ("", X, 1, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT"), # 0x8D6C ("", X, 1, "GL_RGBA32UI"), # 0x8D70 ("", X, 1, "GL_RGB32UI"), # 0x8D71 ("", X, 1, "GL_ALPHA32UI_EXT"), # 0x8D72 @@ -2850,7 +2849,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_MALI_SHADER_BINARY_ARM"), # 0x8F60 ("", X, 1, "GL_RED_SNORM"), # 0x8F90 ("", X, 1, "GL_RG_SNORM"), # 0x8F91 ("", X, 1, "GL_RGB_SNORM"), # 0x8F92 @@ -2867,8 +2866,8 @@ parameters = [ ("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_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 @@ -3157,11 +3156,11 @@ parameters = [ ("", 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_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 ("glGet", I, 1, "GL_MAX_DEBUG_MESSAGE_LENGTH"), # 0x9143 ("glGet", I, 1, "GL_MAX_DEBUG_LOGGED_MESSAGES"), # 0x9144 ("glGet", I, 1, "GL_DEBUG_LOGGED_MESSAGES"), # 0x9145 @@ -3325,14 +3324,14 @@ parameters = [ ("", X, 1, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"), # 0x93DB ("", X, 1, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"), # 0x93DC ("", X, 1, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"), # 0x93DD - #("", X, 1, "GL_RESTART_PATH_NV"), # 0xF0 - #("", X, 1, "GL_DUP_FIRST_CUBIC_CURVE_TO_NV"), # 0xF2 - #("", X, 1, "GL_DUP_LAST_CUBIC_CURVE_TO_NV"), # 0xF4 - #("", X, 1, "GL_RECT_NV"), # 0xF6 - #("", X, 1, "GL_CIRCULAR_CCW_ARC_TO_NV"), # 0xF8 - #("", X, 1, "GL_CIRCULAR_CW_ARC_TO_NV"), # 0xFA - #("", X, 1, "GL_CIRCULAR_TANGENT_ARC_TO_NV"), # 0xFC - #("", X, 1, "GL_ARC_TO_NV"), # 0xFE + ("", X, 1, "GL_RESTART_PATH_NV"), # 0xF0 + ("", X, 1, "GL_DUP_FIRST_CUBIC_CURVE_TO_NV"), # 0xF2 + ("", X, 1, "GL_DUP_LAST_CUBIC_CURVE_TO_NV"), # 0xF4 + ("", X, 1, "GL_RECT_NV"), # 0xF6 + ("", X, 1, "GL_CIRCULAR_CCW_ARC_TO_NV"), # 0xF8 + ("", X, 1, "GL_CIRCULAR_CW_ARC_TO_NV"), # 0xFA + ("", X, 1, "GL_CIRCULAR_TANGENT_ARC_TO_NV"), # 0xFC + ("", X, 1, "GL_ARC_TO_NV"), # 0xFE #("", X, 1, "GL_TIMEOUT_IGNORED"), # 0xFFFFFFFFFFFFFFFFull ("", X, 1, "GL_INVALID_INDEX"), # 0xFFFFFFFFu ] diff --git a/specs/stdapi.py b/specs/stdapi.py index b86668b..c652736 100644 --- a/specs/stdapi.py +++ b/specs/stdapi.py @@ -385,6 +385,12 @@ class Function: def argNames(self): return [arg.name for arg in self.args] + def getArgByName(self, name): + for arg in self.args: + if arg.name == name: + return arg + return None + def StdFunction(*args, **kwargs): kwargs.setdefault('call', '__stdcall') diff --git a/specs/winapi.py b/specs/winapi.py index 031c834..4436c6d 100644 --- a/specs/winapi.py +++ b/specs/winapi.py @@ -206,7 +206,7 @@ IUnknown = Interface("IUnknown") IUnknown.methods = ( StdMethod(HRESULT, "QueryInterface", ((REFIID, "riid"), Out(Pointer(ObjPointer(Void)), "ppvObj"))), - StdMethod(ULONG, "AddRef", (), sideeffects=False), + StdMethod(ULONG, "AddRef", ()), StdMethod(ULONG, "Release", ()), ) diff --git a/thirdparty/getopt/CMakeLists.txt b/thirdparty/getopt/CMakeLists.txt index fc46f7d..224fc1e 100644 --- a/thirdparty/getopt/CMakeLists.txt +++ b/thirdparty/getopt/CMakeLists.txt @@ -1,5 +1,11 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}) -add_library (getopt_bundled STATIC +add_library (getopt_bundled STATIC EXCLUDE_FROM_ALL getopt_long.c ) + +install ( + FILES LICENSE + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-getopt.txt +) diff --git a/thirdparty/getopt/LICENSE b/thirdparty/getopt/LICENSE new file mode 100644 index 0000000..1a9141b --- /dev/null +++ b/thirdparty/getopt/LICENSE @@ -0,0 +1,45 @@ +Copyright (c) 2002 Todd C. Miller + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + + +Copyright (c) 2000 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Dieter Baron and Thomas Klausner. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/less/CMakeLists.txt b/thirdparty/less/CMakeLists.txt index 95e7175..ef4eba6 100644 --- a/thirdparty/less/CMakeLists.txt +++ b/thirdparty/less/CMakeLists.txt @@ -31,6 +31,6 @@ install ( install ( FILES LICENSE - DESTINATION doc - RENAME LICENSE.less + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-less.txt ) diff --git a/thirdparty/libpng/CMakeLists.txt b/thirdparty/libpng/CMakeLists.txt index 7775f91..7cf2be9 100644 --- a/thirdparty/libpng/CMakeLists.txt +++ b/thirdparty/libpng/CMakeLists.txt @@ -1,6 +1,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -add_library (png_bundled STATIC +add_library (png_bundled STATIC EXCLUDE_FROM_ALL png.c pngerror.c pngget.c @@ -21,3 +21,9 @@ add_library (png_bundled STATIC set_target_properties (png_bundled PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}" ) + +install ( + FILES LICENSE + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-libpng.txt +) diff --git a/thirdparty/msinttypes/.gitignore b/thirdparty/msinttypes/.gitignore new file mode 100644 index 0000000..2460008 --- /dev/null +++ b/thirdparty/msinttypes/.gitignore @@ -0,0 +1 @@ +!Makefile diff --git a/thirdparty/msinttypes/LICENSE b/thirdparty/msinttypes/LICENSE new file mode 100644 index 0000000..7af067d --- /dev/null +++ b/thirdparty/msinttypes/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2006-2008 Alexander Chemeris + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/msinttypes/Makefile b/thirdparty/msinttypes/Makefile new file mode 100644 index 0000000..ab18b4d --- /dev/null +++ b/thirdparty/msinttypes/Makefile @@ -0,0 +1,10 @@ +update: \ + inttypes.h \ + stdint.h + +%.h: FORCE + wget -N http://msinttypes.googlecode.com/svn/trunk/$@ + +.PHONY: update + +FORCE: diff --git a/thirdparty/msinttypes/inttypes.h b/thirdparty/msinttypes/inttypes.h new file mode 100644 index 0000000..4b3828a --- /dev/null +++ b/thirdparty/msinttypes/inttypes.h @@ -0,0 +1,305 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff --git a/thirdparty/msinttypes/stdbool.h b/thirdparty/msinttypes/stdbool.h new file mode 100644 index 0000000..99a735d --- /dev/null +++ b/thirdparty/msinttypes/stdbool.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2007-2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + +#ifndef _STDBOOL_H_ +#define _STDBOOL_H_ + +#ifndef __cplusplus + +#define false 0 +#define true 1 +#define bool _Bool + +/* For compilers that don't have the builtin _Bool type. */ +#if defined(_MSC_VER) || (__STDC_VERSION__ < 199901L && __GNUC__ < 3) +typedef unsigned char _Bool; +#endif + +#endif /* !__cplusplus */ + +#define __bool_true_false_are_defined 1 + +#endif /* !_STDBOOL_H_ */ diff --git a/thirdparty/msinttypes/stdint.h b/thirdparty/msinttypes/stdint.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/thirdparty/msinttypes/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/thirdparty/msvc/.gitignore b/thirdparty/msvc/.gitignore deleted file mode 100644 index 2460008..0000000 --- a/thirdparty/msvc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!Makefile diff --git a/thirdparty/msvc/Makefile b/thirdparty/msvc/Makefile deleted file mode 100644 index ab18b4d..0000000 --- a/thirdparty/msvc/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -update: \ - inttypes.h \ - stdint.h - -%.h: FORCE - wget -N http://msinttypes.googlecode.com/svn/trunk/$@ - -.PHONY: update - -FORCE: diff --git a/thirdparty/msvc/inttypes.h b/thirdparty/msvc/inttypes.h deleted file mode 100644 index 4b3828a..0000000 --- a/thirdparty/msvc/inttypes.h +++ /dev/null @@ -1,305 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include "stdint.h" - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - - -#endif // _MSC_INTTYPES_H_ ] diff --git a/thirdparty/msvc/stdbool.h b/thirdparty/msvc/stdbool.h deleted file mode 100644 index 99a735d..0000000 --- a/thirdparty/msvc/stdbool.h +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************************************** - * - * Copyright 2007-2010 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - **************************************************************************/ - -#ifndef _STDBOOL_H_ -#define _STDBOOL_H_ - -#ifndef __cplusplus - -#define false 0 -#define true 1 -#define bool _Bool - -/* For compilers that don't have the builtin _Bool type. */ -#if defined(_MSC_VER) || (__STDC_VERSION__ < 199901L && __GNUC__ < 3) -typedef unsigned char _Bool; -#endif - -#endif /* !__cplusplus */ - -#define __bool_true_false_are_defined 1 - -#endif /* !_STDBOOL_H_ */ diff --git a/thirdparty/msvc/stdint.h b/thirdparty/msvc/stdint.h deleted file mode 100644 index d02608a..0000000 --- a/thirdparty/msvc/stdint.h +++ /dev/null @@ -1,247 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus -extern "C" { -#endif -# include -#ifdef __cplusplus -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] diff --git a/thirdparty/qjson/CMakeLists.txt b/thirdparty/qjson/CMakeLists.txt index 512efc8..f142371 100644 --- a/thirdparty/qjson/CMakeLists.txt +++ b/thirdparty/qjson/CMakeLists.txt @@ -27,4 +27,13 @@ set (qjson_SRCS #serializerrunnable.cpp ) -add_library (qjson_bundled STATIC ${qjson_SRCS} ${qjson_MOC_SRCS}) +add_library (qjson_bundled STATIC EXCLUDE_FROM_ALL + ${qjson_SRCS} + ${qjson_MOC_SRCS} +) + +install ( + FILES COPYING.lib + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-qjson.txt +) diff --git a/thirdparty/snappy/CMakeLists.txt b/thirdparty/snappy/CMakeLists.txt index 9bbecdb..25281a6 100644 --- a/thirdparty/snappy/CMakeLists.txt +++ b/thirdparty/snappy/CMakeLists.txt @@ -8,7 +8,7 @@ if (CMAKE_COMPILER_IS_GNUCXX) add_definitions (-Wno-unused-function) endif () -add_library (snappy_bundled STATIC +add_library (snappy_bundled STATIC EXCLUDE_FROM_ALL snappy.cc snappy-sinksource.cc snappy-stubs-internal.cc @@ -18,3 +18,9 @@ add_library (snappy_bundled STATIC set_target_properties (snappy_bundled PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}" ) + +install ( + FILES COPYING + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-snappy.txt +) diff --git a/thirdparty/zlib/CMakeLists.txt b/thirdparty/zlib/CMakeLists.txt index b1e953d..3cf970e 100644 --- a/thirdparty/zlib/CMakeLists.txt +++ b/thirdparty/zlib/CMakeLists.txt @@ -9,7 +9,7 @@ else () add_definitions (-DHAVE_UNISTD_H) endif () -add_library (z_bundled STATIC +add_library (z_bundled STATIC EXCLUDE_FROM_ALL adler32.c compress.c crc32.c @@ -30,3 +30,9 @@ add_library (z_bundled STATIC set_target_properties (z_bundled PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}" ) + +install ( + FILES README + DESTINATION ${DOC_INSTALL_DIR} + RENAME LICENSE-zlib.txt +) diff --git a/wrappers/d3d8trace.py b/wrappers/d3d8trace.py index fd2c8f5..9ce3aad 100644 --- a/wrappers/d3d8trace.py +++ b/wrappers/d3d8trace.py @@ -77,8 +77,7 @@ if __name__ == '__main__': print '#include "trace_writer_local.hpp"' print '#include "os.hpp"' print - print '#include ' - print '#include ' + print '#include "d3d8imports.hpp"' print '#include "d3d8size.hpp"' print '#include "d3d9shader.hpp"' print diff --git a/wrappers/dxgitrace.py b/wrappers/dxgitrace.py index ef4a458..0ecaed2 100644 --- a/wrappers/dxgitrace.py +++ b/wrappers/dxgitrace.py @@ -42,6 +42,36 @@ class D3DCommonTracer(DllTracer): print ' DumpShader(trace::localWriter, %s, %s);' % (arg.name, arg.type.size) return + # Serialize the swapchain dimensions + if function.name == 'CreateSwapChain' and arg.name == 'pDesc' \ + or arg.name == 'pSwapChainDesc': + print r' DXGI_SWAP_CHAIN_DESC *_pSwapChainDesc = NULL;' + print r' DXGI_SWAP_CHAIN_DESC _SwapChainDesc;' + print r' if (%s) {' % arg.name + print r' _SwapChainDesc = *%s;' % arg.name + if function.name != 'CreateSwapChain' or not self.interface.name.endswith('DWM'): + # Obtain size from the window + print r' RECT _rect;' + print r' if (GetClientRect(%s->OutputWindow, &_rect)) {' % arg.name + print r' if (%s->BufferDesc.Width == 0) {' % arg.name + print r' _SwapChainDesc.BufferDesc.Width = _rect.right - _rect.left;' + print r' }' + print r' if (%s->BufferDesc.Height == 0) {' % arg.name + print r' _SwapChainDesc.BufferDesc.Height = _rect.bottom - _rect.top;' + print r' }' + print r' }' + else: + # Obtain size from the output + print r' DXGI_OUTPUT_DESC _OutputDesc;' + print r' if (SUCCEEDED(pOutput->GetDesc(&_OutputDesc))) {' + print r' _SwapChainDesc.BufferDesc.Width = _OutputDesc.DesktopCoordinates.right - _OutputDesc.DesktopCoordinates.left;' + print r' _SwapChainDesc.BufferDesc.Height = _OutputDesc.DesktopCoordinates.bottom - _OutputDesc.DesktopCoordinates.top;' + print r' }' + print r' _pSwapChainDesc = &_SwapChainDesc;' + print r' }' + self.serializeValue(arg.type, '_pSwapChainDesc') + return + DllTracer.serializeArgValue(self, function, arg) def enumWrapperInterfaceVariables(self, interface): diff --git a/wrappers/gltrace.py b/wrappers/gltrace.py index 4ee9373..853a4bc 100644 --- a/wrappers/gltrace.py +++ b/wrappers/gltrace.py @@ -298,12 +298,7 @@ class GlTracer(Tracer): print ' switch (pname) {' for function, type, count, name in glparams.parameters: if type is not None: - print ' case %s: return %u;' % (name, count) - print ' case GL_COMPRESSED_TEXTURE_FORMATS: {' - print ' GLint num_compressed_texture_formats = 0;' - print ' _glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);' - print ' return num_compressed_texture_formats;' - print ' }' + print ' case %s: return %s;' % (name, count) print ' default:' print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);' print ' return 1;' diff --git a/wrappers/gltrace_state.cpp b/wrappers/gltrace_state.cpp index 68bda10..031b5cc 100644 --- a/wrappers/gltrace_state.cpp +++ b/wrappers/gltrace_state.cpp @@ -94,7 +94,7 @@ static bool _releaseContext(context_ptr_t ctx) */ bool releaseContext(uintptr_t context_id) { - bool res; + bool res = false; context_map_mutex.lock(); /* diff --git a/wrappers/trace.py b/wrappers/trace.py index de02086..61a2cb9 100644 --- a/wrappers/trace.py +++ b/wrappers/trace.py @@ -493,6 +493,8 @@ class Tracer: for arg in function.args: if not arg.output: self.unwrapArg(function, arg) + for arg in function.args: + if not arg.output: self.serializeArg(function, arg) print ' trace::localWriter.endEnter();' self.invokeFunction(function) @@ -564,9 +566,6 @@ class Tracer: def wrapRet(self, function, instance): self.wrapValue(function.type, instance) - def unwrapRet(self, function, instance): - self.unwrapValue(function.type, instance) - def needsWrapping(self, type): visitor = WrapDecider() visitor.visit(type) @@ -697,6 +696,8 @@ class Tracer: for arg in method.args: if not arg.output: self.unwrapArg(method, arg) + for arg in method.args: + if not arg.output: self.serializeArg(method, arg) print ' trace::localWriter.endEnter();'