]> git.cworth.org Git - apitrace/commitdiff
Merge branch 'trim-auto'
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Tue, 11 Dec 2012 07:20:26 +0000 (07:20 +0000)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Tue, 11 Dec 2012 07:20:26 +0000 (07:20 +0000)
Conflicts:
cli/CMakeLists.txt

57 files changed:
CMakeLists.txt
README.markdown
cli/CMakeLists.txt
cli/cli_diff.cpp
cli/cli_diff_images.cpp
cli/cli_diff_state.cpp
cli/cli_resources.cpp [new file with mode: 0644]
cli/cli_resources.hpp [new file with mode: 0644]
cli/cli_retrace.cpp
cli/cli_trace.cpp
cli/pickle.hpp [new file with mode: 0644]
common/image.cpp [deleted file]
common/image.hpp [deleted file]
common/image_bmp.cpp [deleted file]
common/image_png.cpp [deleted file]
common/image_pnm.cpp [deleted file]
common/os_time.hpp
common/pickle.hpp [deleted file]
common/trace_api.hpp
common/trace_parser.cpp
common/trace_resource.cpp [deleted file]
common/trace_resource.hpp [deleted file]
common/trace_tools.hpp [deleted file]
common/trace_tools_trace.cpp [deleted file]
gui/CMakeLists.txt
gui/apitrace.cpp
gui/graphing/histogramview.cpp
gui/main.cpp
gui/mainwindow.cpp
gui/mainwindow.h
gui/retracer.cpp
gui/retracer.h
gui/tracedialog.cpp
gui/traceprocess.cpp
gui/trimprocess.cpp
gui/ui/mainwindow.ui
gui/ui/tracedialog.ui
image/CMakeLists.txt [new file with mode: 0644]
image/image.cpp [new file with mode: 0644]
image/image.hpp [new file with mode: 0644]
image/image_bmp.cpp [new file with mode: 0644]
image/image_png.cpp [new file with mode: 0644]
image/image_pnm.cpp [new file with mode: 0644]
inject/CMakeLists.txt [new file with mode: 0644]
inject/inject.h [new file with mode: 0644]
inject/injectee.cpp [new file with mode: 0644]
inject/injector.cpp [new file with mode: 0644]
retrace/CMakeLists.txt
retrace/d3d10state.cpp
retrace/d3d10state.hpp [new file with mode: 0644]
retrace/d3d11state.cpp
retrace/d3d11state_images.cpp
retrace/d3d9state.cpp
retrace/d3d9state_images.cpp
retrace/d3dstate.hpp
retrace/dxgiretrace.py
retrace/glretrace_main.cpp

index 2ace8ac44576231b41cce7ef0017ef62bd6404c7..549d0665c0c3110d22a16f873be39beb62201562 100644 (file)
@@ -206,8 +206,6 @@ set (PNG_DEFINITIONS "")
 set (PNG_LIBRARIES png_bundled)
 
 add_subdirectory (thirdparty/libpng EXCLUDE_FROM_ALL)
-include_directories (${PNG_INCLUDE_DIR})
-add_definitions (${PNG_DEFINITIONS})
 
 if (MSVC)
     add_subdirectory (thirdparty/getopt EXCLUDE_FROM_ALL)
@@ -270,19 +268,6 @@ 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
@@ -320,13 +305,7 @@ add_library (common STATIC
     common/trace_writer_local.cpp
     common/trace_writer_model.cpp
     common/trace_loader.cpp
-    common/trace_resource.cpp
-    common/trace_tools_trace.cpp
     common/trace_profiler.cpp
-    common/image.cpp
-    common/image_bmp.cpp
-    common/image_pnm.cpp
-    common/image_png.cpp
     common/trace_option.cpp
     common/${os}
 )
@@ -350,6 +329,7 @@ endif ()
 add_subdirectory (dispatch)
 add_subdirectory (helpers)
 add_subdirectory (wrappers)
+add_subdirectory (image)
 add_subdirectory (retrace)
 
 
@@ -357,6 +337,9 @@ add_subdirectory (retrace)
 # CLI
 
 if (ENABLE_CLI)
+    if (WIN32)
+        add_subdirectory (inject)
+    endif ()
     add_subdirectory (cli)
 endif ()
 
index c82149545f474e90b5e3135214470da0ab7a0ebd..b1eb08397aa4bf1a64d1db5b2e7cf3dd11248599 100644 (file)
@@ -241,6 +241,13 @@ Then run the application as usual.
 You can specify the written trace filename by setting the `TRACE_FILE`
 environment variable before running.
 
+For D3D10 and higher you really must use `apitrace trace -a DXGI ...`. This is
+because D3D10-11 API span many DLLs which depend on each other, and once a DLL
+with a given name is loaded Windows will reuse it for LoadLibrary calls of the
+same name, causing internal calls to be traced erroneously. `apitrace trace`
+solves this issue by injecting a DLL `dxgitrace.dll` and patching all modules
+to hook only the APIs of interest.
+
 
 Emitting annotations to the trace
 ---------------------------------
index 5df363ab943680dc34a5ee121fa10c40553bc211..5f8e116f5279e385ba1875ed659246bbf2c10d79 100644 (file)
@@ -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
@@ -11,12 +22,12 @@ add_executable (apitrace
     cli_retrace.cpp
     cli_trace.cpp
     cli_trim.cpp
+    cli_resources.cpp
     trace_analyzer.cpp
 )
 
 target_link_libraries (apitrace
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}
index ffc0e303878ba9cc165d019df768b17433d2b806..76cdce1d6f0dc3874366370419070e766668ace9 100644 (file)
 #include "cli.hpp"
 #include "os_string.hpp"
 #include "os_process.hpp"
-#include "trace_resource.hpp"
+#include "cli_resources.hpp"
 
 static const char *synopsis = "Identify differences between two traces.";
 
 static os::String
 find_command(void)
 {
-    return trace::findScript("tracediff.py");
+    return findScript("tracediff.py");
 }
 
 static void
index 3932fa24c51e8afcacb492ed2b0c704bf15196b5..ba8df3e92a440afd5c29f3fafeb967559d281d2c 100644 (file)
 #include "cli.hpp"
 #include "os_string.hpp"
 #include "os_process.hpp"
-#include "trace_resource.hpp"
+#include "cli_resources.hpp"
 
 static const char *synopsis = "Identify differences between two image dumps.";
 
 static os::String
 find_command(void)
 {
-    return trace::findScript("snapdiff.py");
+    return findScript("snapdiff.py");
 }
 
 static void
index 7f75484289fae30e70edbfe593611c0e8cca59ab..341d244ff0d5adc14d9f0e59d6e06056068ed513 100644 (file)
@@ -33,7 +33,7 @@
 #include "cli.hpp"
 #include "os_string.hpp"
 #include "os_process.hpp"
-#include "trace_resource.hpp"
+#include "cli_resources.hpp"
 
 static const char *synopsis = "Identify differences between two state dumps.";
 
@@ -83,7 +83,7 @@ command(int argc, char *argv[])
     file1 = argv[optind];
     file2 = argv[optind + 1];
 
-    os::String command = trace::findScript("jsondiff.py");
+    os::String command = findScript("jsondiff.py");
 
     char *args[5];
 
diff --git a/cli/cli_resources.cpp b/cli/cli_resources.cpp
new file mode 100644 (file)
index 0000000..255a98b
--- /dev/null
@@ -0,0 +1,148 @@
+/*********************************************************************
+ *
+ * Copyright 2011 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 <iostream>
+
+#include "os_string.hpp"
+
+#include "cli_resources.hpp"
+
+
+os::String
+findProgram(const char*programFilename)
+{
+    os::String programPath;
+
+    os::String processDir = os::getProcessName();
+    processDir.trimFilename();
+
+    programPath = processDir;
+    programPath.join(programFilename);
+    if (programPath.exists()) {
+        return programPath;
+    }
+
+#ifndef _WIN32
+    // Try absolute install directory
+    programPath = APITRACE_PROGRAMS_INSTALL_DIR;
+    programPath.join(programFilename);
+    if (programPath.exists()) {
+        return programPath;
+    }
+#endif
+
+    return "";
+}
+
+os::String
+findWrapper(const char *wrapperFilename)
+{
+    os::String wrapperPath;
+
+    os::String processDir = os::getProcessName();
+    processDir.trimFilename();
+
+    // Try relative build directory
+    // XXX: Just make build and install directory layout match
+    wrapperPath = processDir;
+    wrapperPath.join("wrappers");
+    wrapperPath.join(wrapperFilename);
+    if (wrapperPath.exists()) {
+        return wrapperPath;
+    }
+
+    // Try relative install directory
+    wrapperPath = processDir;
+#if defined(_WIN32)
+    wrapperPath.join("..\\lib\\wrappers");
+#elif defined(__APPLE__)
+    wrapperPath.join("../lib/wrappers");
+#else
+    wrapperPath.join("../lib/apitrace/wrappers");
+#endif
+    wrapperPath.join(wrapperFilename);
+    if (wrapperPath.exists()) {
+        return wrapperPath;
+    }
+
+#ifndef _WIN32
+    // Try absolute install directory
+    wrapperPath = APITRACE_WRAPPERS_INSTALL_DIR;
+    wrapperPath.join(wrapperFilename);
+    if (wrapperPath.exists()) {
+        return wrapperPath;
+    }
+#endif
+
+    return "";
+}
+
+os::String
+findScript(const char *scriptFilename)
+{
+    os::String scriptPath;
+
+    os::String processDir = os::getProcessName();
+    processDir.trimFilename();
+
+    // Try relative build directory
+    // XXX: Just make build and install directory layout match
+    scriptPath = processDir;
+    scriptPath.join("scripts");
+    scriptPath.join(scriptFilename);
+    if (scriptPath.exists()) {
+        return scriptPath;
+    }
+
+    // Try relative install directory
+    scriptPath = processDir;
+#if defined(_WIN32)
+    scriptPath.join("..\\lib\\scripts");
+#elif defined(__APPLE__)
+    scriptPath.join("../lib/scripts");
+#else
+    scriptPath.join("../lib/apitrace/scripts");
+#endif
+    scriptPath.join(scriptFilename);
+    if (scriptPath.exists()) {
+        return scriptPath;
+    }
+
+#ifndef _WIN32
+    // Try absolute install directory
+    scriptPath = APITRACE_SCRIPTS_INSTALL_DIR;
+    scriptPath.join(scriptFilename);
+    if (scriptPath.exists()) {
+        return scriptPath;
+    }
+#endif
+
+    std::cerr << "error: cannot find " << scriptFilename << " script\n";
+
+    return "";
+}
diff --git a/cli/cli_resources.hpp b/cli/cli_resources.hpp
new file mode 100644 (file)
index 0000000..dde86dd
--- /dev/null
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * Copyright 2011 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _CLI_RESOURCES_HPP_
+#define _CLI_RESOURCES_HPP_
+
+
+#include <stdlib.h>
+
+#include "os_string.hpp"
+#include "trace_api.hpp"
+
+
+os::String
+findProgram(const char*programFilename);
+
+os::String
+findScript(const char *name);
+
+os::String
+findWrapper(const char *wrapperFilename);
+
+
+#endif /* _CLI_RESOURCES_HPP_ */
index a2dbd09986b86ffc5d31ab5318b02849699f8d4e..d22f719bd65d6a584c416db6010d558a6a55ac9a 100644 (file)
@@ -35,7 +35,7 @@
 #include "os_process.hpp"
 
 #include "trace_parser.hpp"
-#include "trace_resource.hpp"
+#include "cli_resources.hpp"
 
 #include "cli.hpp"
 #include "cli_retrace.hpp"
@@ -46,6 +46,7 @@ guessApi(const char *filename)
 {
     trace::Parser p;
     if (!p.open(filename)) {
+        exit(1);
         return trace::API_UNKNOWN;
     }
     trace::Call *call;
@@ -76,10 +77,8 @@ executeRetrace(const std::vector<const char *> & opts,
     case trace::API_D3D7:
     case trace::API_D3D8:
     case trace::API_D3D9:
-    case trace::API_D3D10:
-    case trace::API_D3D10_1:
-    case trace::API_D3D11:
-        // Can be used with WINE
+    case trace::API_DXGI:
+        // Use prefix so that it can be used with WINE
         retraceName = "d3dretrace.exe";
         break;
     default:
@@ -89,7 +88,7 @@ executeRetrace(const std::vector<const char *> & opts,
     }
 
     std::vector<const char *> command;
-    os::String retracePath = trace::findProgram(retraceName);
+    os::String retracePath = findProgram(retraceName);
     if (retracePath.length()) {
         command.push_back(retracePath);
     } else {
index 80775090c7b1be79cbce6dc9a8e9e6f6b8c521d2..2646ffd8a0190c1bd80b621145c3dd1162efb5e5 100644 (file)
 
 #include <assert.h>
 #include <string.h>
+#include <stdlib.h>
 #include <getopt.h>
 
 #include <iostream>
 
+#include "os_string.hpp"
+#include "os_process.hpp"
+
 #include "cli.hpp"
+#include "cli_resources.hpp"
+
+
+#if defined(__APPLE__)
+#define TRACE_VARIABLE "DYLD_LIBRARY_PATH"
+#define GL_TRACE_WRAPPER  "OpenGL"
+#elif defined(_WIN32)
+#define GL_TRACE_WRAPPER  "opengl32.dll"
+#else
+#define TRACE_VARIABLE "LD_PRELOAD"
+#define GL_TRACE_WRAPPER  "glxtrace.so"
+#define EGL_TRACE_WRAPPER  "egltrace.so"
+#endif
+
+
+static inline bool
+copyWrapper(const os::String & wrapperPath,
+            const char *programPath,
+            bool verbose)
+{
+    os::String wrapperFilename(wrapperPath);
+    wrapperFilename.trimDirectory();
+
+    os::String tmpWrapper(programPath);
+    tmpWrapper.trimFilename();
+    tmpWrapper.join(wrapperFilename);
+
+    if (verbose) {
+        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
+    }
+
+    if (tmpWrapper.exists()) {
+        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
+        return false;
+    }
+
+    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
+        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
+        return false;
+    }
+
+    return true;
+}
+
+
+static int
+traceProgram(trace::API api,
+             char * const *argv,
+             const char *output,
+             bool verbose)
+{
+    const char *wrapperFilename;
+    std::vector<const char *> args;
+    int status = 1;
+
+    /*
+     * TODO: simplify code
+     */
+
+    bool useInject = false;
+    switch (api) {
+    case trace::API_GL:
+        wrapperFilename = GL_TRACE_WRAPPER;
+        break;
+#ifdef EGL_TRACE_WRAPPER
+    case trace::API_EGL:
+        wrapperFilename = EGL_TRACE_WRAPPER;
+        break;
+#endif
+#ifdef _WIN32
+    case trace::API_D3D7:
+        wrapperFilename = "ddraw.dll";
+        break;
+    case trace::API_D3D8:
+        wrapperFilename = "d3d8.dll";
+        break;
+    case trace::API_D3D9:
+        wrapperFilename = "d3d9.dll";
+        break;
+    case trace::API_DXGI:
+        wrapperFilename = "dxgitrace.dll";
+        useInject = true;
+        break;
+#endif
+    default:
+        std::cerr << "error: unsupported API\n";
+        return 1;
+    }
+
+    os::String wrapperPath = findWrapper(wrapperFilename);
+    if (!wrapperPath.length()) {
+        std::cerr << "error: failed to find " << wrapperFilename << "\n";
+        goto exit;
+    }
+
+#if defined(_WIN32)
+    if (useInject) {
+        args.push_back("inject");
+        args.push_back(wrapperPath);
+    } else {
+        /* On Windows copy the wrapper to the program directory.
+         */
+        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
+            goto exit;
+        }
+    }
+#else  /* !_WIN32 */
+    (void)useInject;
+#endif /* !_WIN32 */
+
+#if defined(__APPLE__)
+    /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
+     * directory, not the file. */
+    wrapperPath.trimFilename();
+#endif
+
+#if defined(TRACE_VARIABLE)
+    if (verbose) {
+        std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
+    }
+    /* FIXME: Don't modify the current environment */
+    os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
+#endif /* TRACE_VARIABLE */
+
+    if (output) {
+        os::setEnvironment("TRACE_FILE", output);
+    }
 
-#include "trace_tools.hpp"
+    for (char * const * arg = argv; *arg; ++arg) {
+        args.push_back(*arg);
+    }
+    args.push_back(NULL);
+
+    if (verbose) {
+        const char *sep = "";
+        for (unsigned i = 0; i < args.size(); ++i) {
+            std::cerr << sep << args[i];
+            sep = " ";
+        }
+        std::cerr << "\n";
+    }
+
+    status = os::execute((char * const *)&args[0]);
+
+exit:
+#if defined(TRACE_VARIABLE)
+    os::unsetEnvironment(TRACE_VARIABLE);
+#endif
+#if defined(_WIN32)
+    if (!useInject) {
+        os::String tmpWrapper(argv[0]);
+        tmpWrapper.trimFilename();
+        tmpWrapper.join(wrapperFilename);
+        os::removeFile(tmpWrapper);
+    }
+#endif
+
+    if (output) {
+        os::unsetEnvironment("TRACE_FILE");
+    }
+    
+    return status;
+
+}
 
 
 static const char *synopsis = "Generate a new trace by executing the given program.";
@@ -102,12 +268,12 @@ command(int argc, char *argv[])
                 api = trace::API_D3D8;
             } else if (strcmp(optarg, "d3d9") == 0) {
                 api = trace::API_D3D9;
-            } else if (strcmp(optarg, "d3d10") == 0) {
-                api = trace::API_D3D10;
-            } else if (strcmp(optarg, "d3d10_1") == 0) {
-                api = trace::API_D3D10_1;
-            } else if (strcmp(optarg, "d3d11") == 0) {
-                api = trace::API_D3D11;
+            } else if (strcmp(optarg, "dxgi") == 0 ||
+                       strcmp(optarg, "d3d10") == 0 ||
+                       strcmp(optarg, "d3d10_1") == 0 ||
+                       strcmp(optarg, "d3d11") == 0 ||
+                       strcmp(optarg, "d3d11_1") == 0) {
+                api = trace::API_DXGI;
             } else {
                 std::cerr << "error: unknown API `" << optarg << "`\n";
                 usage();
@@ -131,7 +297,7 @@ command(int argc, char *argv[])
     }
 
     assert(argv[argc] == 0);
-    return trace::traceProgram(api, argv + optind, output, verbose);
+    return traceProgram(api, argv + optind, output, verbose);
 }
 
 const Command trace_command = {
diff --git a/cli/pickle.hpp b/cli/pickle.hpp
new file mode 100644 (file)
index 0000000..84b643a
--- /dev/null
@@ -0,0 +1,331 @@
+/**************************************************************************
+ *
+ * Copyright 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.
+ *
+ **************************************************************************/
+
+/*
+ * Python pickle writer
+ */
+
+#ifndef _PICKLE_HPP_
+#define _PICKLE_HPP_
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ostream>
+#include <string>
+#include <limits>
+
+
+class PickleWriter
+{
+private:
+    std::ostream &os;
+
+    /*
+     * Python pickle opcodes.  See pickle.py and pickletools.py from Python
+     * standard library for details.
+     */
+    enum Opcode {
+        MARK            = '(',
+        STOP            = '.',
+        POP             = '0',
+        POP_MARK        = '1',
+        DUP             = '2',
+        FLOAT           = 'F',
+        INT             = 'I',
+        BININT          = 'J',
+        BININT1         = 'K',
+        LONG            = 'L',
+        BININT2         = 'M',
+        NONE            = 'N',
+        PERSID          = 'P',
+        BINPERSID       = 'Q',
+        REDUCE          = 'R',
+        STRING          = 'S',
+        BINSTRING       = 'T',
+        SHORT_BINSTRING = 'U',
+        UNICODE         = 'V',
+        BINUNICODE      = 'X',
+        APPEND          = 'a',
+        BUILD           = 'b',
+        GLOBAL          = 'c',
+        DICT            = 'd',
+        EMPTY_DICT      = '}',
+        APPENDS         = 'e',
+        GET             = 'g',
+        BINGET          = 'h',
+        INST            = 'i',
+        LONG_BINGET     = 'j',
+        LIST            = 'l',
+        EMPTY_LIST      = ']',
+        OBJ             = 'o',
+        PUT             = 'p',
+        BINPUT          = 'q',
+        LONG_BINPUT     = 'r',
+        SETITEM         = 's',
+        TUPLE           = 't',
+        EMPTY_TUPLE     = ')',
+        SETITEMS        = 'u',
+        BINFLOAT        = 'G',
+
+        PROTO           = '\x80',
+        NEWOBJ          = '\x81',
+        EXT1            = '\x82',
+        EXT2            = '\x83',
+        EXT4            = '\x84',
+        TUPLE1          = '\x85',
+        TUPLE2          = '\x86',
+        TUPLE3          = '\x87',
+        NEWTRUE         = '\x88',
+        NEWFALSE        = '\x89',
+        LONG1           = '\x8a',
+        LONG4           = '\x8b',
+    };
+
+public:
+    PickleWriter(std::ostream &_os) :
+        os(_os) {
+    }
+
+    inline void begin() {
+        os.put(PROTO);
+        os.put(2);
+    }
+
+    inline void end() {
+        os.put(STOP);
+    }
+
+    inline void beginDict() {
+        os.put(EMPTY_DICT);
+        os.put(BINPUT);
+        os.put(1);
+    }
+
+    inline void endDict() {
+    }
+
+    inline void beginItem() {
+    }
+
+    inline void beginItem(const char * name) {
+        writeString(name);
+    }
+
+    inline void beginItem(const std::string &name) {
+        beginItem(name.c_str());
+    }
+
+    inline void endItem(void) {
+        os.put(SETITEM);
+    }
+
+    inline void beginList() {
+        os.put(EMPTY_LIST);
+        os.put(BINPUT);
+        os.put(1);
+        os.put(MARK);
+    }
+
+    inline void endList(void) {
+        os.put(APPENDS);
+    }
+
+    inline void beginTuple() {
+        os.put(MARK);
+    }
+
+    inline void endTuple(void) {
+        os.put(TUPLE);
+    }
+
+    inline void writeString(const char *s, size_t length) {
+        if (!s) {
+            writeNone();
+            return;
+        }
+
+        if (length < 256) {
+            os.put(SHORT_BINSTRING);
+            os.put(length);
+        } else {
+            os.put(BINSTRING);
+            putInt32(length);
+        }
+        os.write(s, length);
+
+        os.put(BINPUT);
+        os.put(1);
+    }
+
+    inline void writeString(const char *s) {
+        if (!s) {
+            writeNone();
+            return;
+        }
+
+        writeString(s, strlen(s));
+    }
+
+    inline void writeString(const std::string &s) {
+        writeString(s.c_str(), s.size());
+    }
+
+    inline void writeNone(void) {
+        os.put(NONE);
+    }
+
+    inline void writeBool(bool b) {
+        os.put(b ? NEWTRUE : NEWFALSE);
+    }
+
+    inline void writeInt(uint8_t i) {
+        os.put(BININT1);
+        os.put(i);
+    }
+
+    inline void writeInt(uint16_t i) {
+        if (i < 0x100) {
+            writeInt((uint8_t)i);
+        } else {
+            os.put(BININT2);
+            putInt16(i);
+        }
+    }
+
+    inline void writeInt(int32_t i) {
+        if (0 <= i && i < 0x10000) {
+            writeInt((uint16_t)i);
+        } else {
+            os.put(BININT);
+            putInt32(i);
+        }
+    }
+
+    inline void writeInt(uint32_t i) {
+        if (i < 0x8000000) {
+            writeInt((int32_t)i);
+        } else {
+            writeLong(i);
+        }
+    }
+
+    inline void writeInt(long long i) {
+        if (-0x8000000 <= i && i < 0x8000000) {
+            writeInt((int32_t)i);
+        } else {
+            writeLong(i);
+        }
+    }
+
+    inline void writeInt(unsigned long long i) {
+        if (i < 0x8000000) {
+            writeInt((int32_t)i);
+        } else {
+            writeLong(i);
+        }
+    }
+
+    inline void writeFloat(double f) {
+        union {
+            double f;
+            char c[8];
+        } u;
+
+        assert(sizeof u.f == sizeof u.c);
+        u.f = f;
+
+        os.put(BINFLOAT);
+        os.put(u.c[7]);
+        os.put(u.c[6]);
+        os.put(u.c[5]);
+        os.put(u.c[4]);
+        os.put(u.c[3]);
+        os.put(u.c[2]);
+        os.put(u.c[1]);
+        os.put(u.c[0]);
+    }
+
+    inline void writeByteArray(const void *buf, size_t length) {
+        os.put(GLOBAL);
+        os << "__builtin__\nbytearray\n";
+        os.put(BINPUT);
+        os.put(1);
+        writeString(static_cast<const char *>(buf), length);
+        os.put(TUPLE1);
+        os.put(REDUCE);
+    }
+
+protected:
+    inline void putInt16(uint16_t i) {
+        os.put( i        & 0xff);
+        os.put( i >>  8        );
+    }
+
+    inline void putInt32(uint32_t i) {
+        os.put( i        & 0xff);
+        os.put((i >>  8) & 0xff);
+        os.put((i >> 16) & 0xff);
+        os.put( i >> 24        );
+    }
+
+    template< class T >
+    inline void writeLong(T l) {
+        os.put(LONG1);
+
+        if (l == 0) {
+            os.put(0);
+            return;
+        }
+
+        // Same as l >> (8 * sizeof l), but without the warnings
+        T sign;
+        if (std::numeric_limits<T>::is_signed) {
+            sign = l < 0 ? ~0 : 0;
+        } else {
+            sign = 0;
+        }
+
+        T sl = l;
+        unsigned c = 0;
+        do {
+            ++c;
+        } while (sl >>= 8 != sign);
+
+        // Add an extra byte if sign bit doesn't match
+        if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
+            ++c;
+        }
+        os.put(c);
+
+        for (unsigned i = 0; i < c; ++ i) {
+            os.put(l & 0xff);
+            l >>= 8;
+        }
+    }
+};
+
+#endif /* _Pickle_HPP_ */
diff --git a/common/image.cpp b/common/image.cpp
deleted file mode 100644 (file)
index e692313..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <math.h>
-
-#include <algorithm>
-
-#include "image.hpp"
-
-
-namespace image {
-
-
-double Image::compare(Image &ref)
-{
-    if (width != ref.width ||
-        height != ref.height ||
-        channels < 3 ||
-        ref.channels < 3) {
-        return 0.0;
-    }
-
-    // Ignore missing alpha when comparing RGB w/ RGBA, but enforce an equal
-    // number of channels otherwise.
-    unsigned minChannels = std::min(channels, ref.channels);
-    if (channels != ref.channels && minChannels < 3) {
-        return 0.0;
-    }
-
-    const unsigned char *pSrc = start();
-    const unsigned char *pRef = ref.start();
-
-    unsigned long long error = 0;
-    for (unsigned y = 0; y < height; ++y) {
-        for (unsigned  x = 0; x < width; ++x) {
-            // FIXME: Ignore alpha channel until we are able to pick a visual
-            // that matches the traces
-            for (unsigned  c = 0; c < minChannels; ++c) {
-                int delta = pSrc[x*channels + c] - pRef[x*ref.channels + c];
-                error += delta*delta;
-            }
-        }
-
-        pSrc += stride();
-        pRef += ref.stride();
-    }
-
-    double numerator = error*2 + 1;
-    double denominator = height*width*minChannels*255ULL*255ULL*2;
-    double quotient = numerator/denominator;
-
-    // Precision in bits
-    double precision = -log(quotient)/log(2.0);
-
-    return precision;
-}
-
-
-} /* namespace image */
diff --git a/common/image.hpp b/common/image.hpp
deleted file mode 100644 (file)
index 7dd18c1..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-/*
- * Image I/O.
- */
-
-#ifndef _IMAGE_HPP_
-#define _IMAGE_HPP_
-
-
-#include <fstream>
-
-
-namespace image {
-
-
-class Image {
-public:
-    unsigned width;
-    unsigned height;
-    unsigned channels;
-
-    // Flipped vertically or not
-    bool flipped;
-
-    // Pixels in RGBA format
-    unsigned char *pixels;
-
-    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
-        width(w),
-        height(h),
-        channels(c),
-        flipped(f),
-        pixels(new unsigned char[h*w*c])
-    {}
-
-    inline ~Image() {
-        delete [] pixels;
-    }
-
-    inline unsigned char *start(void) {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline const unsigned char *start(void) const {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline unsigned char *end(void) {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline const unsigned char *end(void) const {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline signed stride(void) const {
-        return flipped ? -(signed)(width*channels) : width*channels;
-    }
-
-    bool writeBMP(const char *filename) const;
-
-    void writePNM(std::ostream &os, const char *comment = NULL) const;
-
-    inline bool writePNM(const char *filename, const char *comment = NULL) const {
-        std::ofstream os(filename, std::ofstream::binary);
-        if (!os) {
-            return false;
-        }
-        writePNM(os, comment);
-        return true;
-    }
-
-    bool
-    writePNG(std::ostream &os) const;
-
-    inline bool
-    writePNG(const char *filename) const {
-        std::ofstream os(filename, std::ofstream::binary);
-        if (!os) {
-            return false;
-        }
-        return writePNG(os);
-    }
-
-    double compare(Image &ref);
-};
-
-
-Image *
-readPNG(const char *filename);
-
-const char *
-readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height);
-
-
-} /* namespace image */
-
-
-#endif /* _IMAGE_HPP_ */
diff --git a/common/image_bmp.cpp b/common/image_bmp.cpp
deleted file mode 100644 (file)
index e0c6428..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace image {
-
-
-#pragma pack(push,2)
-struct FileHeader {
-    uint16_t bfType;
-    uint32_t bfSize;
-    uint16_t bfReserved1;
-    uint16_t bfReserved2;
-    uint32_t bfOffBits;
-};
-#pragma pack(pop)
-
-struct InfoHeader {
-    uint32_t biSize;
-    int32_t biWidth;
-    int32_t biHeight;
-    uint16_t biPlanes;
-    uint16_t biBitCount;
-    uint32_t biCompression;
-    uint32_t biSizeImage;
-    int32_t biXPelsPerMeter;
-    int32_t biYPelsPerMeter;
-    uint32_t biClrUsed;
-    uint32_t biClrImportant;
-};
-
-struct Pixel {
-    uint8_t rgbBlue;
-    uint8_t rgbGreen;
-    uint8_t rgbRed;
-    uint8_t rgbAlpha;
-};
-
-
-bool
-Image::writeBMP(const char *filename) const {
-    assert(channels == 4);
-
-    struct FileHeader bmfh;
-    struct InfoHeader bmih;
-    unsigned x, y;
-
-    bmfh.bfType = 0x4d42;
-    bmfh.bfSize = 14 + 40 + height*width*4;
-    bmfh.bfReserved1 = 0;
-    bmfh.bfReserved2 = 0;
-    bmfh.bfOffBits = 14 + 40;
-
-    bmih.biSize = 40;
-    bmih.biWidth = width;
-    bmih.biHeight = height;
-    bmih.biPlanes = 1;
-    bmih.biBitCount = 32;
-    bmih.biCompression = 0;
-    bmih.biSizeImage = height*width*4;
-    bmih.biXPelsPerMeter = 0;
-    bmih.biYPelsPerMeter = 0;
-    bmih.biClrUsed = 0;
-    bmih.biClrImportant = 0;
-
-    std::ofstream stream(filename, std::ofstream::binary);
-
-    if (!stream) {
-        return false;
-    }
-
-    stream.write((const char *)&bmfh, 14);
-    stream.write((const char *)&bmih, 40);
-
-    unsigned stride = width*4;
-
-    if (flipped) {
-        for (y = 0; y < height; ++y) {
-            const unsigned char *ptr = pixels + y * stride;
-            for (x = 0; x < width; ++x) {
-                struct Pixel pixel;
-                pixel.rgbRed   = ptr[x*4 + 0];
-                pixel.rgbGreen = ptr[x*4 + 1];
-                pixel.rgbBlue  = ptr[x*4 + 2];
-                pixel.rgbAlpha = ptr[x*4 + 3];
-                stream.write((const char *)&pixel, 4);
-            }
-        }
-    } else {
-        y = height;
-        while (y--) {
-            const unsigned char *ptr = pixels + y * stride;
-            for (x = 0; x < width; ++x) {
-                struct Pixel pixel;
-                pixel.rgbRed   = ptr[x*4 + 0];
-                pixel.rgbGreen = ptr[x*4 + 1];
-                pixel.rgbBlue  = ptr[x*4 + 2];
-                pixel.rgbAlpha = ptr[x*4 + 3];
-                stream.write((const char *)&pixel, 4);
-            }
-        }
-    }
-
-    stream.close();
-
-    return true;
-}
-
-
-} /* namespace image */
diff --git a/common/image_png.cpp b/common/image_png.cpp
deleted file mode 100644 (file)
index dba07d4..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <zlib.h>
-#include <png.h>
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <fstream>
-
-#include "image.hpp"
-
-
-namespace image {
-
-
-static const int png_compression_level = Z_BEST_SPEED;
-
-
-static void
-pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
-{
-    std::ostream *os = (std::ostream *) png_get_io_ptr(png_ptr);
-    os->write((const char *)data, length);
-}
-
-bool
-Image::writePNG(std::ostream &os) const
-{
-    png_structp png_ptr;
-    png_infop info_ptr;
-    int color_type;
-
-    switch (channels) {
-    case 4:
-        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-        break;
-    case 3:
-        color_type = PNG_COLOR_TYPE_RGB;
-        break;
-    case 2:
-        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
-        break;
-    case 1:
-        color_type = PNG_COLOR_TYPE_GRAY;
-        break;
-    default:
-        assert(0);
-        goto no_png;
-    }
-
-    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_ptr)
-        goto no_png;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr) {
-        png_destroy_write_struct(&png_ptr,  NULL);
-        goto no_png;
-    }
-
-    if (setjmp(png_jmpbuf(png_ptr))) {
-        png_destroy_write_struct(&png_ptr, &info_ptr);
-        goto no_png;
-    }
-
-    png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL);
-
-    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
-                 color_type, PNG_INTERLACE_NONE,
-                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-    png_set_compression_level(png_ptr, png_compression_level);
-
-    png_write_info(png_ptr, info_ptr);
-
-    if (!flipped) {
-        for (unsigned y = 0; y < height; ++y) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    } else {
-        unsigned y = height;
-        while (y--) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    }
-
-    png_write_end(png_ptr, info_ptr);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    return true;
-
-no_png:
-    return false;
-}
-
-
-Image *
-readPNG(const char *filename)
-{
-    FILE *fp;
-    png_structp png_ptr;
-    png_infop info_ptr;
-    png_infop end_info;
-    Image *image;
-
-    fp = fopen(filename, "rb");
-    if (!fp)
-        goto no_fp;
-
-    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_ptr)
-        goto no_png;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr) {
-        png_destroy_read_struct(&png_ptr, NULL, NULL);
-        goto no_png;
-    }
-
-    end_info = png_create_info_struct(png_ptr);
-    if (!end_info) {
-        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-        goto no_png;
-    }
-
-    if (setjmp(png_jmpbuf(png_ptr))) {
-        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-        goto no_png;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    png_read_info(png_ptr, info_ptr);
-
-    png_uint_32 width, height;
-    int bit_depth, color_type, interlace_type, compression_type, filter_method;
-
-    png_get_IHDR(png_ptr, info_ptr,
-                 &width, &height,
-                 &bit_depth, &color_type, &interlace_type,
-                 &compression_type, &filter_method);
-
-    image = new Image(width, height);
-    if (!image)
-        goto no_image;
-
-    /* Convert to RGBA8 */
-    if (color_type == PNG_COLOR_TYPE_PALETTE)
-        png_set_palette_to_rgb(png_ptr);
-    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
-        png_set_expand_gray_1_2_4_to_8(png_ptr);
-    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
-        png_set_tRNS_to_alpha(png_ptr);
-    if (bit_depth == 16)
-        png_set_strip_16(png_ptr);
-
-    for (unsigned y = 0; y < height; ++y) {
-        png_bytep row = (png_bytep)(image->pixels + y*width*4);
-        png_read_row(png_ptr, row, NULL);
-    }
-
-    png_read_end(png_ptr, info_ptr);
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-    fclose(fp);
-    return image;
-
-no_image:
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-no_png:
-    fclose(fp);
-no_fp:
-    return NULL;
-}
-
-
-
-} /* namespace image */
diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp
deleted file mode 100644 (file)
index f9cd05d..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "image.hpp"
-
-
-namespace image {
-
-/**
- * http://en.wikipedia.org/wiki/Netpbm_format
- * http://netpbm.sourceforge.net/doc/ppm.html
- */
-void
-Image::writePNM(std::ostream &os, const char *comment) const {
-    assert(channels == 1 || channels >= 3);
-
-    os << (channels == 1 ? "P5" : "P6") << "\n";
-    if (comment) {
-        os << "#" << comment << "\n";
-    }
-    os << width << " " << height << "\n";
-    os << "255" << "\n";
-
-    const unsigned char *row;
-
-    if (channels == 1 || channels == 3) {
-        for (row = start(); row != end(); row += stride()) {
-            os.write((const char *)row, width*channels);
-        }
-    } else {
-        unsigned char *tmp = new unsigned char[width*3];
-        if (channels == 4) {
-            for (row = start(); row != end(); row += stride()) {
-                const uint32_t *src = (const uint32_t *)row;
-                uint32_t *dst = (uint32_t *)tmp;
-                unsigned x;
-                for (x = 0; x + 4 <= width; x += 4) {
-                    /*
-                     * It's much faster to access dwords than bytes.
-                     *
-                     * FIXME: Big-endian version.
-                     */
-
-                    uint32_t rgba0 = *src++ & 0xffffff;
-                    uint32_t rgba1 = *src++ & 0xffffff;
-                    uint32_t rgba2 = *src++ & 0xffffff;
-                    uint32_t rgba3 = *src++ & 0xffffff;
-                    uint32_t rgb0 = rgba0
-                                  | (rgba1 << 24);
-                    uint32_t rgb1 = (rgba1 >> 8)
-                                  | (rgba2 << 16);
-                    uint32_t rgb2 = (rgba2 >> 16)
-                                  | (rgba3 << 8);
-                    *dst++ = rgb0;
-                    *dst++ = rgb1;
-                    *dst++ = rgb2;
-                }
-                for (; x < width; ++x) {
-                    tmp[x*3 + 0] = row[x*4 + 0];
-                    tmp[x*3 + 1] = row[x*4 + 1];
-                    tmp[x*3 + 2] = row[x*4 + 2];
-                }
-                os.write((const char *)tmp, width*3);
-            }
-        } else if (channels == 2) {
-            for (row = start(); row != end(); row += stride()) {
-                const unsigned char *src = row;
-                unsigned char *dst = tmp;
-                for (unsigned x = 0; x < width; ++x) {
-                    *dst++ = *src++;
-                    *dst++ = *src++;
-                    *dst++ = 0;
-                }
-                os.write((const char *)tmp, width*3);
-            }
-        } else {
-            assert(0);
-        }
-        delete [] tmp;
-    }
-}
-
-const char *
-readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
-{
-    *channels = 0;
-    *width = 0;
-    *height = 0;
-
-    const char *currentBuffer = buffer;
-    const char *nextBuffer;
-
-    // parse number of channels
-    int scannedChannels = sscanf(currentBuffer, "P%d\n", channels);
-    if (scannedChannels != 1) { // validate scanning of channels
-        // invalid channel line
-        return buffer;
-    }
-    // convert channel token to number of channels
-    *channels = (*channels == 5) ? 1 : 3;
-
-    // advance past channel line
-    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
-    bufferSize -= nextBuffer - currentBuffer;
-    currentBuffer = nextBuffer;
-
-    // skip over optional comment
-    if (*currentBuffer == '#') {
-        // advance past comment line
-        nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
-        bufferSize -= nextBuffer - currentBuffer;
-        currentBuffer = nextBuffer;
-    }
-
-    // parse dimensions of image
-    int scannedDimensions = sscanf(currentBuffer, "%d %d\n", width, height);
-    if (scannedDimensions != 2) { // validate scanning of dimensions
-        // invalid dimension line
-        return buffer;
-    }
-
-    // advance past dimension line
-    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
-    bufferSize -= nextBuffer - currentBuffer;
-    currentBuffer = nextBuffer;
-
-    // skip over "255\n" at end of header
-    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
-
-    // return start of image data
-    return nextBuffer;
-}
-
-} /* namespace image */
index 13cc733ae05488312b4fb5554d08fcb8fd49bc2d..3e4960e74554d0179c96b4582202d52390c61378 100644 (file)
@@ -73,7 +73,7 @@ namespace os {
         return counter.QuadPart;
 #elif defined(__linux__)
         struct timespec tp;
-        if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
+        if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
             return 0;
         }
         return tp.tv_sec * 1000000000LL + tp.tv_nsec;
diff --git a/common/pickle.hpp b/common/pickle.hpp
deleted file mode 100644 (file)
index 84b643a..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/**************************************************************************
- *
- * Copyright 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.
- *
- **************************************************************************/
-
-/*
- * Python pickle writer
- */
-
-#ifndef _PICKLE_HPP_
-#define _PICKLE_HPP_
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <ostream>
-#include <string>
-#include <limits>
-
-
-class PickleWriter
-{
-private:
-    std::ostream &os;
-
-    /*
-     * Python pickle opcodes.  See pickle.py and pickletools.py from Python
-     * standard library for details.
-     */
-    enum Opcode {
-        MARK            = '(',
-        STOP            = '.',
-        POP             = '0',
-        POP_MARK        = '1',
-        DUP             = '2',
-        FLOAT           = 'F',
-        INT             = 'I',
-        BININT          = 'J',
-        BININT1         = 'K',
-        LONG            = 'L',
-        BININT2         = 'M',
-        NONE            = 'N',
-        PERSID          = 'P',
-        BINPERSID       = 'Q',
-        REDUCE          = 'R',
-        STRING          = 'S',
-        BINSTRING       = 'T',
-        SHORT_BINSTRING = 'U',
-        UNICODE         = 'V',
-        BINUNICODE      = 'X',
-        APPEND          = 'a',
-        BUILD           = 'b',
-        GLOBAL          = 'c',
-        DICT            = 'd',
-        EMPTY_DICT      = '}',
-        APPENDS         = 'e',
-        GET             = 'g',
-        BINGET          = 'h',
-        INST            = 'i',
-        LONG_BINGET     = 'j',
-        LIST            = 'l',
-        EMPTY_LIST      = ']',
-        OBJ             = 'o',
-        PUT             = 'p',
-        BINPUT          = 'q',
-        LONG_BINPUT     = 'r',
-        SETITEM         = 's',
-        TUPLE           = 't',
-        EMPTY_TUPLE     = ')',
-        SETITEMS        = 'u',
-        BINFLOAT        = 'G',
-
-        PROTO           = '\x80',
-        NEWOBJ          = '\x81',
-        EXT1            = '\x82',
-        EXT2            = '\x83',
-        EXT4            = '\x84',
-        TUPLE1          = '\x85',
-        TUPLE2          = '\x86',
-        TUPLE3          = '\x87',
-        NEWTRUE         = '\x88',
-        NEWFALSE        = '\x89',
-        LONG1           = '\x8a',
-        LONG4           = '\x8b',
-    };
-
-public:
-    PickleWriter(std::ostream &_os) :
-        os(_os) {
-    }
-
-    inline void begin() {
-        os.put(PROTO);
-        os.put(2);
-    }
-
-    inline void end() {
-        os.put(STOP);
-    }
-
-    inline void beginDict() {
-        os.put(EMPTY_DICT);
-        os.put(BINPUT);
-        os.put(1);
-    }
-
-    inline void endDict() {
-    }
-
-    inline void beginItem() {
-    }
-
-    inline void beginItem(const char * name) {
-        writeString(name);
-    }
-
-    inline void beginItem(const std::string &name) {
-        beginItem(name.c_str());
-    }
-
-    inline void endItem(void) {
-        os.put(SETITEM);
-    }
-
-    inline void beginList() {
-        os.put(EMPTY_LIST);
-        os.put(BINPUT);
-        os.put(1);
-        os.put(MARK);
-    }
-
-    inline void endList(void) {
-        os.put(APPENDS);
-    }
-
-    inline void beginTuple() {
-        os.put(MARK);
-    }
-
-    inline void endTuple(void) {
-        os.put(TUPLE);
-    }
-
-    inline void writeString(const char *s, size_t length) {
-        if (!s) {
-            writeNone();
-            return;
-        }
-
-        if (length < 256) {
-            os.put(SHORT_BINSTRING);
-            os.put(length);
-        } else {
-            os.put(BINSTRING);
-            putInt32(length);
-        }
-        os.write(s, length);
-
-        os.put(BINPUT);
-        os.put(1);
-    }
-
-    inline void writeString(const char *s) {
-        if (!s) {
-            writeNone();
-            return;
-        }
-
-        writeString(s, strlen(s));
-    }
-
-    inline void writeString(const std::string &s) {
-        writeString(s.c_str(), s.size());
-    }
-
-    inline void writeNone(void) {
-        os.put(NONE);
-    }
-
-    inline void writeBool(bool b) {
-        os.put(b ? NEWTRUE : NEWFALSE);
-    }
-
-    inline void writeInt(uint8_t i) {
-        os.put(BININT1);
-        os.put(i);
-    }
-
-    inline void writeInt(uint16_t i) {
-        if (i < 0x100) {
-            writeInt((uint8_t)i);
-        } else {
-            os.put(BININT2);
-            putInt16(i);
-        }
-    }
-
-    inline void writeInt(int32_t i) {
-        if (0 <= i && i < 0x10000) {
-            writeInt((uint16_t)i);
-        } else {
-            os.put(BININT);
-            putInt32(i);
-        }
-    }
-
-    inline void writeInt(uint32_t i) {
-        if (i < 0x8000000) {
-            writeInt((int32_t)i);
-        } else {
-            writeLong(i);
-        }
-    }
-
-    inline void writeInt(long long i) {
-        if (-0x8000000 <= i && i < 0x8000000) {
-            writeInt((int32_t)i);
-        } else {
-            writeLong(i);
-        }
-    }
-
-    inline void writeInt(unsigned long long i) {
-        if (i < 0x8000000) {
-            writeInt((int32_t)i);
-        } else {
-            writeLong(i);
-        }
-    }
-
-    inline void writeFloat(double f) {
-        union {
-            double f;
-            char c[8];
-        } u;
-
-        assert(sizeof u.f == sizeof u.c);
-        u.f = f;
-
-        os.put(BINFLOAT);
-        os.put(u.c[7]);
-        os.put(u.c[6]);
-        os.put(u.c[5]);
-        os.put(u.c[4]);
-        os.put(u.c[3]);
-        os.put(u.c[2]);
-        os.put(u.c[1]);
-        os.put(u.c[0]);
-    }
-
-    inline void writeByteArray(const void *buf, size_t length) {
-        os.put(GLOBAL);
-        os << "__builtin__\nbytearray\n";
-        os.put(BINPUT);
-        os.put(1);
-        writeString(static_cast<const char *>(buf), length);
-        os.put(TUPLE1);
-        os.put(REDUCE);
-    }
-
-protected:
-    inline void putInt16(uint16_t i) {
-        os.put( i        & 0xff);
-        os.put( i >>  8        );
-    }
-
-    inline void putInt32(uint32_t i) {
-        os.put( i        & 0xff);
-        os.put((i >>  8) & 0xff);
-        os.put((i >> 16) & 0xff);
-        os.put( i >> 24        );
-    }
-
-    template< class T >
-    inline void writeLong(T l) {
-        os.put(LONG1);
-
-        if (l == 0) {
-            os.put(0);
-            return;
-        }
-
-        // Same as l >> (8 * sizeof l), but without the warnings
-        T sign;
-        if (std::numeric_limits<T>::is_signed) {
-            sign = l < 0 ? ~0 : 0;
-        } else {
-            sign = 0;
-        }
-
-        T sl = l;
-        unsigned c = 0;
-        do {
-            ++c;
-        } while (sl >>= 8 != sign);
-
-        // Add an extra byte if sign bit doesn't match
-        if (((l >> (8 * c - 1)) & 1) != ((l >> (8 * sizeof l - 1)) & 1)) {
-            ++c;
-        }
-        os.put(c);
-
-        for (unsigned i = 0; i < c; ++ i) {
-            os.put(l & 0xff);
-            l >>= 8;
-        }
-    }
-};
-
-#endif /* _Pickle_HPP_ */
index 4c896dbfaed52cf57f28a1f66cd2ae08545221a2..3d491fe1054eb66f61e96aced45676ac8a129923 100644 (file)
@@ -48,9 +48,7 @@ enum API {
     API_D3D7,
     API_D3D8,
     API_D3D9,
-    API_D3D10,
-    API_D3D10_1,
-    API_D3D11,
+    API_DXGI, // D3D10.x, D3D11.x
 };
 
 
index 7a8c4f96e551802cfca9d8a85ae5f597e19629d5..f3aea7e7cf482f26f69e74432691bcefbb75ab1c 100644 (file)
@@ -248,9 +248,10 @@ Parser::parse_function_sig(void) {
                 api = trace::API_GL;
             } else if (n[0] == 'e' && n[1] == 'g' && n[2] == 'l' && n[3] >= 'A' && n[3] <= 'Z') { // egl[A-Z]*
                 api = trace::API_EGL;
-            } else if (n[0] == 'D' &&
-                       ((n[1] == 'i' && n[2] == 'r' && n[3] == 'e' && n[4] == 'c' && n[5] == 't') || // Direct*
-                        (n[1] == '3' && n[2] == 'D'))) { // D3D*
+            } else if ((n[0] == 'D' &&
+                        ((n[1] == 'i' && n[2] == 'r' && n[3] == 'e' && n[4] == 'c' && n[5] == 't') || // Direct*
+                         (n[1] == '3' && n[2] == 'D'))) || // D3D*
+                       (n[0] == 'C' && n[1] == 'r' && n[2] == 'e' && n[3] == 'a' && n[4] == 't' && n[5] == 'e')) { // Create*
                 api = trace::API_DX;
             } else {
                 /* TODO */
diff --git a/common/trace_resource.cpp b/common/trace_resource.cpp
deleted file mode 100644 (file)
index 04ac327..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*********************************************************************
- *
- * Copyright 2011 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 <iostream>
-
-#include "os_string.hpp"
-#include "trace_tools.hpp"
-
-
-
-namespace trace {
-
-os::String
-findProgram(const char*programFilename)
-{
-    os::String programPath;
-
-    os::String processDir = os::getProcessName();
-    processDir.trimFilename();
-
-    programPath = processDir;
-    programPath.join(programFilename);
-    if (programPath.exists()) {
-        return programPath;
-    }
-
-#ifndef _WIN32
-    // Try absolute install directory
-    programPath = APITRACE_PROGRAMS_INSTALL_DIR;
-    programPath.join(programFilename);
-    if (programPath.exists()) {
-        return programPath;
-    }
-#endif
-
-    return "";
-}
-
-os::String
-findWrapper(const char *wrapperFilename)
-{
-    os::String wrapperPath;
-
-    os::String processDir = os::getProcessName();
-    processDir.trimFilename();
-
-    // Try relative build directory
-    // XXX: Just make build and install directory layout match
-    wrapperPath = processDir;
-    wrapperPath.join("wrappers");
-    wrapperPath.join(wrapperFilename);
-    if (wrapperPath.exists()) {
-        return wrapperPath;
-    }
-
-    // Try relative install directory
-    wrapperPath = processDir;
-#if defined(_WIN32)
-    wrapperPath.join("..\\lib\\wrappers");
-#elif defined(__APPLE__)
-    wrapperPath.join("../lib/wrappers");
-#else
-    wrapperPath.join("../lib/apitrace/wrappers");
-#endif
-    wrapperPath.join(wrapperFilename);
-    if (wrapperPath.exists()) {
-        return wrapperPath;
-    }
-
-#ifndef _WIN32
-    // Try absolute install directory
-    wrapperPath = APITRACE_WRAPPERS_INSTALL_DIR;
-    wrapperPath.join(wrapperFilename);
-    if (wrapperPath.exists()) {
-        return wrapperPath;
-    }
-#endif
-
-    return "";
-}
-
-os::String
-findScript(const char *scriptFilename)
-{
-    os::String scriptPath;
-
-    os::String processDir = os::getProcessName();
-    processDir.trimFilename();
-
-    // Try relative build directory
-    // XXX: Just make build and install directory layout match
-    scriptPath = processDir;
-    scriptPath.join("scripts");
-    scriptPath.join(scriptFilename);
-    if (scriptPath.exists()) {
-        return scriptPath;
-    }
-
-    // Try relative install directory
-    scriptPath = processDir;
-#if defined(_WIN32)
-    scriptPath.join("..\\lib\\scripts");
-#elif defined(__APPLE__)
-    scriptPath.join("../lib/scripts");
-#else
-    scriptPath.join("../lib/apitrace/scripts");
-#endif
-    scriptPath.join(scriptFilename);
-    if (scriptPath.exists()) {
-        return scriptPath;
-    }
-
-#ifndef _WIN32
-    // Try absolute install directory
-    scriptPath = APITRACE_SCRIPTS_INSTALL_DIR;
-    scriptPath.join(scriptFilename);
-    if (scriptPath.exists()) {
-        return scriptPath;
-    }
-#endif
-
-    std::cerr << "error: cannot find " << scriptFilename << " script\n";
-
-    return "";
-}
-
-
-} /* namespace trace */
diff --git a/common/trace_resource.hpp b/common/trace_resource.hpp
deleted file mode 100644 (file)
index 28c5727..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _TRACE_RESOURCE_HPP_
-#define _TRACE_RESOURCE_HPP_
-
-
-#include <stdlib.h>
-
-#include "os_string.hpp"
-#include "trace_api.hpp"
-
-
-namespace trace {
-
-
-os::String
-findProgram(const char*programFilename);
-
-os::String
-findScript(const char *name);
-
-os::String
-findWrapper(const char *wrapperFilename);
-
-} /* namespace trace */
-
-#endif /* _TRACE_RESOURCE_HPP_ */
diff --git a/common/trace_tools.hpp b/common/trace_tools.hpp
deleted file mode 100644 (file)
index ddfe888..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _TRACE_TOOLS_HPP_
-#define _TRACE_TOOLS_HPP_
-
-
-#include <stdlib.h>
-
-#include "trace_api.hpp"
-
-
-namespace trace {
-
-
-int
-traceProgram(API api,
-             char * const *argv,
-             const char *output = NULL,
-             bool verbose = false);
-
-
-
-} /* namespace trace */
-
-#endif /* _TRACE_TOOLS_HPP_ */
diff --git a/common/trace_tools_trace.cpp b/common/trace_tools_trace.cpp
deleted file mode 100644 (file)
index 4c0082d..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*********************************************************************
- *
- * Copyright 2011 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 <stdlib.h>
-
-#include <iostream>
-
-#include "os_string.hpp"
-#include "os_process.hpp"
-#include "trace_tools.hpp"
-#include "trace_resource.hpp"
-
-
-
-namespace trace {
-
-
-#if defined(__APPLE__)
-#define TRACE_VARIABLE "DYLD_LIBRARY_PATH"
-#define GL_TRACE_WRAPPER  "OpenGL"
-#elif defined(_WIN32)
-#define GL_TRACE_WRAPPER  "opengl32.dll"
-#else
-#define TRACE_VARIABLE "LD_PRELOAD"
-#define GL_TRACE_WRAPPER  "glxtrace.so"
-#define EGL_TRACE_WRAPPER  "egltrace.so"
-#endif
-
-
-static inline bool
-copyWrapper(const os::String & wrapperPath,
-            const char *programPath,
-            bool verbose)
-{
-    os::String wrapperFilename(wrapperPath);
-    wrapperFilename.trimDirectory();
-
-    os::String tmpWrapper(programPath);
-    tmpWrapper.trimFilename();
-    tmpWrapper.join(wrapperFilename);
-
-    if (verbose) {
-        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
-    }
-
-    if (tmpWrapper.exists()) {
-        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
-        return false;
-    }
-
-    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
-        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
-        return false;
-    }
-
-    return true;
-}
-
-
-static const char *glWrappers[] = {
-    GL_TRACE_WRAPPER,
-    NULL
-};
-
-#ifdef EGL_TRACE_WRAPPER
-static const char *eglWrappers[] = {
-    EGL_TRACE_WRAPPER,
-    NULL
-};
-#endif
-
-#ifdef _WIN32
-static const char *d3d7Wrappers[] = {
-    "ddraw.dll",
-    NULL
-};
-
-static const char *d3d8Wrappers[] = {
-    "d3d8.dll",
-    NULL
-};
-
-static const char *d3d9Wrappers[] = {
-    "d3d9.dll",
-    NULL
-};
-
-static const char *dxgiWrappers[] = {
-    "dxgitrace.dll",
-    //"dxgi.dll",
-    "d3d10.dll",
-    "d3d10_1.dll",
-    "d3d11.dll",
-    NULL
-};
-#endif
-
-int
-traceProgram(API api,
-             char * const *argv,
-             const char *output,
-             bool verbose)
-{
-    const char **wrapperFilenames;
-    unsigned numWrappers;
-    int status = 1;
-
-    /*
-     * TODO: simplify code
-     */
-
-    switch (api) {
-    case API_GL:
-        wrapperFilenames = glWrappers;
-        break;
-#ifdef EGL_TRACE_WRAPPER
-    case API_EGL:
-        wrapperFilenames = eglWrappers;
-        break;
-#endif
-#ifdef _WIN32
-    case API_D3D7:
-        wrapperFilenames = d3d7Wrappers;
-        break;
-    case API_D3D8:
-        wrapperFilenames = d3d8Wrappers;
-        break;
-    case API_D3D9:
-        wrapperFilenames = d3d9Wrappers;
-        break;
-    case API_D3D10:
-    case API_D3D10_1:
-    case API_D3D11:
-        wrapperFilenames = dxgiWrappers;
-        break;
-#endif
-    default:
-        std::cerr << "error: unsupported API\n";
-        return 1;
-    }
-
-    numWrappers = 0;
-    while (wrapperFilenames[numWrappers]) {
-        ++numWrappers;
-    }
-
-    unsigned i;
-    for (i = 0; i < numWrappers; ++i) {
-        const char *wrapperFilename = wrapperFilenames[i];
-
-        os::String wrapperPath = findWrapper(wrapperFilename);
-
-        if (!wrapperPath.length()) {
-            std::cerr << "error: failed to find " << wrapperFilename << "\n";
-            goto exit;
-        }
-
-#if defined(_WIN32)
-        /* On Windows copy the wrapper to the program directory.
-         */
-        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
-            goto exit;
-        }
-#endif /* _WIN32 */
-
-#if defined(__APPLE__)
-        /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
-         * directory, not the file. */
-        wrapperPath.trimFilename();
-#endif
-
-#if defined(TRACE_VARIABLE)
-        assert(numWrappers == 1);
-        if (verbose) {
-            std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
-        }
-        /* FIXME: Don't modify the current environment */
-        os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
-#endif /* TRACE_VARIABLE */
-    }
-
-    if (output) {
-        os::setEnvironment("TRACE_FILE", output);
-    }
-
-    if (verbose) {
-        const char *sep = "";
-        for (char * const * arg = argv; *arg; ++arg) {
-            std::cerr << *arg << sep;
-            sep = " ";
-        }
-        std::cerr << "\n";
-    }
-
-    status = os::execute(argv);
-
-exit:
-#if defined(TRACE_VARIABLE)
-    os::unsetEnvironment(TRACE_VARIABLE);
-#endif
-#if defined(_WIN32)
-    for (unsigned j = 0; j < i; ++j) {
-        const char *wrapperFilename = wrapperFilenames[j];
-        os::String tmpWrapper(argv[0]);
-        tmpWrapper.trimFilename();
-        tmpWrapper.join(wrapperFilename);
-        os::removeFile(tmpWrapper);
-    }
-#endif
-
-    if (output) {
-        os::unsetEnvironment("TRACE_FILE");
-    }
-    
-    return status;
-
-}
-
-
-} /* namespace trace */
index 8968cb4852f2c52eff7e328f7f822b59941864fa..773d344549462fba25f4d403121ba42942b52ecc 100644 (file)
@@ -58,23 +58,40 @@ QT4_WRAP_UI(qapitrace_UIS_H ${qapitrace_UIS})
 
 #add_app_icon(qapitrace_SRCS ../icons/hi*-qapitrace.png)
 link_directories(${LINK_DIRECTORIES} ${QJSON_LIBRARY_DIRS})
-include_directories(${QT_INCLUDES} ${QJSON_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
+include_directories(
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_SOURCE_DIR}
+    ${QJSON_INCLUDE_DIR}
+    ${QT_INCLUDES}
+)
+
+if (WIN32)
+    # Use Windows subsystem (i.e., no console).
+    set (qapitrace_SUBSYSTEM "WIN32")
+endif ()
 
-add_executable(qapitrace ${qapitrace_SRCS} ${qapitrace_UIS_H})
+add_executable(qapitrace ${qapitrace_SUBSYSTEM} ${qapitrace_SRCS} ${qapitrace_UIS_H})
 
 target_link_libraries (qapitrace
+    image
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${QJSON_LIBRARIES}
     ${QT_LIBRARIES}
 )
 
-# Recent builds of Qt no longer support i386 architecture
 if (APPLE)
+    # Recent builds of Qt no longer support i386 architecture
     set_target_properties (qapitrace PROPERTIES OSX_ARCHITECTURES x86_64)
 endif ()
+if (MSVC)
+    # When the Windows subsystem is chosen by default MSVC expects WinMain()
+    # entry point, but we rather use plain old main() everywhere.
+    set_target_properties (qapitrace PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup")
+endif ()
+
 
 ########### install files ###############
 
index 6a8ebe2cd043a4608191db584f2b78274ba09143..a69ce2fff0ef25a2f0293e392e273f9b4ecc1b4d 100644 (file)
@@ -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 {
index 0b945772b96916bbe470289865eedcfba9e96b33..2dd3d8e94263b3cf95d5bff59b5381282ac8f0ab 100644 (file)
@@ -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;
index 0ed50ed8f2b33506f931f570d9662430d59712ec..471dec7939c7eccd88c4d1c882a121ea2a587b08 100644 (file)
@@ -3,6 +3,9 @@
 #include "apitrace.h"
 #include "apitracecall.h"
 
+#include "os_string.hpp"
+#include "os_process.hpp"
+
 #include <QApplication>
 #include <QMetaType>
 #include <QVariant>
@@ -32,6 +35,15 @@ int main(int argc, char **argv)
     qRegisterMetaType<ApiTrace::SearchResult>();
     qRegisterMetaType<ApiTrace::SearchRequest>();
     qRegisterMetaType<QList<QImage> >();
+
+#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;
index caf9e370236ebed41d8aa29409cc3e253b1457a4..d6ebd2f9e1ecbe3a107222b684cda6c1e826c7e3 100644 (file)
@@ -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();
index 2248127f76aae57b8acd4728c7b090ad628564da..78267efca4c9f5cd98bb4eb0b48a5bc980ae3ceb 100644 (file)
@@ -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();
index 213704b8e61ef0a4f6a200c8da5d48cb37818d83..2928ed63f321f31e34667e2448e1b8f765f2fdbf 100644 (file)
@@ -3,7 +3,7 @@
 #include "apitracecall.h"
 #include "thumbnail.h"
 
-#include "image.hpp"
+#include "image/image.hpp"
 
 #include "trace_profiler.hpp"
 
@@ -137,19 +137,6 @@ Retracer::Retracer(QObject *parent)
       m_profilePixels(false)
 {
     qRegisterMetaType<QList<ApiTraceError> >();
-
-#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
@@ -271,9 +258,7 @@ void Retracer::run()
     case trace::API_D3D7:
     case trace::API_D3D8:
     case trace::API_D3D9:
-    case trace::API_D3D10:
-    case trace::API_D3D10_1:
-    case trace::API_D3D11:
+    case trace::API_DXGI:
 #ifdef Q_OS_WIN
         prog = QLatin1String("d3dretrace");
 #else
index e889d8887cf3753ce609d86daefa6233d7134ddf..af1a3d9f7b727b70f1173dcc058980bba590f6a6 100644 (file)
@@ -65,8 +65,6 @@ private:
     bool m_profileGpu;
     bool m_profileCpu;
     bool m_profilePixels;
-
-    QProcessEnvironment m_processEnvironment;
 };
 
 #endif
index fcfdf4661241ff30858f0f5332d83fbd30bcc126..b8e438d9ddddc3c7fe49307f2b41de6778b47854 100644 (file)
@@ -50,7 +50,7 @@ void TraceDialog::browse()
             tr("Find the application"),
             QDir::currentPath());
 
-    if (isFileOk(fileName)) {
+    if (!fileName.isEmpty() && isFileOk(fileName)) {
         applicationEdit->setText(fileName);
     }
 }
index 6f4d0b9350da147249bbf1e522fd8c51d6de4384..8d57e525f0617b901a124369f1deb07da2c995a4 100644 (file)
@@ -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()
index c23475d50d86a62e078594f6786073628f4ebd9a..34639c634d4893ad55d38617ebc0a7307c9f53c7 100644 (file)
@@ -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()
index 7cbb3d1e3bea979532b80bd7bdbf620b80822d9a..06f4503af50d92cf3015ce7baaecb3aaed588252 100644 (file)
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
-       <property name="url" stdset="0">
+       <property name="url">
         <url>
          <string>about:blank</string>
         </url>
    </property>
   </action>
   <action name="actionReplay">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="icon">
     <iconset resource="../qapitrace.qrc">
      <normaloff>:/resources/media-playback-start.png</normaloff>:/resources/media-playback-start.png</iconset>
    </property>
   </action>
   <action name="actionStop">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="icon">
     <iconset resource="../qapitrace.qrc">
      <normaloff>:/resources/media-playback-stop.png</normaloff>:/resources/media-playback-stop.png</iconset>
    </property>
   </action>
   <action name="actionLookupState">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="icon">
     <iconset resource="../qapitrace.qrc">
      <normaloff>:/resources/media-record.png</normaloff>:/resources/media-record.png</iconset>
    </property>
   </action>
   <action name="actionShowThumbnails">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="text">
     <string>Show &amp;Thumbnails</string>
    </property>
    </property>
   </action>
   <action name="actionTrim">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="text">
     <string>Tr&amp;im</string>
    </property>
      <normaloff>:/resources/document-new.png</normaloff>:/resources/document-new.png</iconset>
    </property>
    <property name="text">
-    <string>New</string>
+    <string>&amp;New...</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+N</string>
    </property>
   </action>
   <action name="actionFind">
      <normaloff>:/resources/edit-find.png</normaloff>:/resources/edit-find.png</iconset>
    </property>
    <property name="text">
-    <string>Find</string>
+    <string>&amp;Find</string>
    </property>
    <property name="shortcut">
     <string>Ctrl+F</string>
    </property>
   </action>
   <action name="actionProfile">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="text">
     <string>&amp;Profile</string>
    </property>
index a3e5240a540b2ec44a2751557b9652650bb567f5..f6eccf445372471608fca231948b7c8540c20b12 100644 (file)
@@ -47,7 +47,7 @@
      <item>
       <widget class="QPushButton" name="browseButton">
        <property name="text">
-        <string>Browse</string>
+        <string>Browse...</string>
        </property>
        <property name="flat">
         <bool>false</bool>
diff --git a/image/CMakeLists.txt b/image/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ee4d98f
--- /dev/null
@@ -0,0 +1,14 @@
+include_directories (
+    ${PNG_INCLUDE_DIR}
+)
+
+add_library (image STATIC
+    image.cpp
+    image_bmp.cpp
+    image_png.cpp
+    image_pnm.cpp
+)
+
+target_link_libraries (image
+    ${PNG_LIBRARIES}
+)
diff --git a/image/image.cpp b/image/image.cpp
new file mode 100644 (file)
index 0000000..e692313
--- /dev/null
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <math.h>
+
+#include <algorithm>
+
+#include "image.hpp"
+
+
+namespace image {
+
+
+double Image::compare(Image &ref)
+{
+    if (width != ref.width ||
+        height != ref.height ||
+        channels < 3 ||
+        ref.channels < 3) {
+        return 0.0;
+    }
+
+    // Ignore missing alpha when comparing RGB w/ RGBA, but enforce an equal
+    // number of channels otherwise.
+    unsigned minChannels = std::min(channels, ref.channels);
+    if (channels != ref.channels && minChannels < 3) {
+        return 0.0;
+    }
+
+    const unsigned char *pSrc = start();
+    const unsigned char *pRef = ref.start();
+
+    unsigned long long error = 0;
+    for (unsigned y = 0; y < height; ++y) {
+        for (unsigned  x = 0; x < width; ++x) {
+            // FIXME: Ignore alpha channel until we are able to pick a visual
+            // that matches the traces
+            for (unsigned  c = 0; c < minChannels; ++c) {
+                int delta = pSrc[x*channels + c] - pRef[x*ref.channels + c];
+                error += delta*delta;
+            }
+        }
+
+        pSrc += stride();
+        pRef += ref.stride();
+    }
+
+    double numerator = error*2 + 1;
+    double denominator = height*width*minChannels*255ULL*255ULL*2;
+    double quotient = numerator/denominator;
+
+    // Precision in bits
+    double precision = -log(quotient)/log(2.0);
+
+    return precision;
+}
+
+
+} /* namespace image */
diff --git a/image/image.hpp b/image/image.hpp
new file mode 100644 (file)
index 0000000..7dd18c1
--- /dev/null
@@ -0,0 +1,123 @@
+/**************************************************************************
+ *
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Image I/O.
+ */
+
+#ifndef _IMAGE_HPP_
+#define _IMAGE_HPP_
+
+
+#include <fstream>
+
+
+namespace image {
+
+
+class Image {
+public:
+    unsigned width;
+    unsigned height;
+    unsigned channels;
+
+    // Flipped vertically or not
+    bool flipped;
+
+    // Pixels in RGBA format
+    unsigned char *pixels;
+
+    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
+        width(w),
+        height(h),
+        channels(c),
+        flipped(f),
+        pixels(new unsigned char[h*w*c])
+    {}
+
+    inline ~Image() {
+        delete [] pixels;
+    }
+
+    inline unsigned char *start(void) {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline const unsigned char *start(void) const {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline unsigned char *end(void) {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline const unsigned char *end(void) const {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline signed stride(void) const {
+        return flipped ? -(signed)(width*channels) : width*channels;
+    }
+
+    bool writeBMP(const char *filename) const;
+
+    void writePNM(std::ostream &os, const char *comment = NULL) const;
+
+    inline bool writePNM(const char *filename, const char *comment = NULL) const {
+        std::ofstream os(filename, std::ofstream::binary);
+        if (!os) {
+            return false;
+        }
+        writePNM(os, comment);
+        return true;
+    }
+
+    bool
+    writePNG(std::ostream &os) const;
+
+    inline bool
+    writePNG(const char *filename) const {
+        std::ofstream os(filename, std::ofstream::binary);
+        if (!os) {
+            return false;
+        }
+        return writePNG(os);
+    }
+
+    double compare(Image &ref);
+};
+
+
+Image *
+readPNG(const char *filename);
+
+const char *
+readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height);
+
+
+} /* namespace image */
+
+
+#endif /* _IMAGE_HPP_ */
diff --git a/image/image_bmp.cpp b/image/image_bmp.cpp
new file mode 100644 (file)
index 0000000..e0c6428
--- /dev/null
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace image {
+
+
+#pragma pack(push,2)
+struct FileHeader {
+    uint16_t bfType;
+    uint32_t bfSize;
+    uint16_t bfReserved1;
+    uint16_t bfReserved2;
+    uint32_t bfOffBits;
+};
+#pragma pack(pop)
+
+struct InfoHeader {
+    uint32_t biSize;
+    int32_t biWidth;
+    int32_t biHeight;
+    uint16_t biPlanes;
+    uint16_t biBitCount;
+    uint32_t biCompression;
+    uint32_t biSizeImage;
+    int32_t biXPelsPerMeter;
+    int32_t biYPelsPerMeter;
+    uint32_t biClrUsed;
+    uint32_t biClrImportant;
+};
+
+struct Pixel {
+    uint8_t rgbBlue;
+    uint8_t rgbGreen;
+    uint8_t rgbRed;
+    uint8_t rgbAlpha;
+};
+
+
+bool
+Image::writeBMP(const char *filename) const {
+    assert(channels == 4);
+
+    struct FileHeader bmfh;
+    struct InfoHeader bmih;
+    unsigned x, y;
+
+    bmfh.bfType = 0x4d42;
+    bmfh.bfSize = 14 + 40 + height*width*4;
+    bmfh.bfReserved1 = 0;
+    bmfh.bfReserved2 = 0;
+    bmfh.bfOffBits = 14 + 40;
+
+    bmih.biSize = 40;
+    bmih.biWidth = width;
+    bmih.biHeight = height;
+    bmih.biPlanes = 1;
+    bmih.biBitCount = 32;
+    bmih.biCompression = 0;
+    bmih.biSizeImage = height*width*4;
+    bmih.biXPelsPerMeter = 0;
+    bmih.biYPelsPerMeter = 0;
+    bmih.biClrUsed = 0;
+    bmih.biClrImportant = 0;
+
+    std::ofstream stream(filename, std::ofstream::binary);
+
+    if (!stream) {
+        return false;
+    }
+
+    stream.write((const char *)&bmfh, 14);
+    stream.write((const char *)&bmih, 40);
+
+    unsigned stride = width*4;
+
+    if (flipped) {
+        for (y = 0; y < height; ++y) {
+            const unsigned char *ptr = pixels + y * stride;
+            for (x = 0; x < width; ++x) {
+                struct Pixel pixel;
+                pixel.rgbRed   = ptr[x*4 + 0];
+                pixel.rgbGreen = ptr[x*4 + 1];
+                pixel.rgbBlue  = ptr[x*4 + 2];
+                pixel.rgbAlpha = ptr[x*4 + 3];
+                stream.write((const char *)&pixel, 4);
+            }
+        }
+    } else {
+        y = height;
+        while (y--) {
+            const unsigned char *ptr = pixels + y * stride;
+            for (x = 0; x < width; ++x) {
+                struct Pixel pixel;
+                pixel.rgbRed   = ptr[x*4 + 0];
+                pixel.rgbGreen = ptr[x*4 + 1];
+                pixel.rgbBlue  = ptr[x*4 + 2];
+                pixel.rgbAlpha = ptr[x*4 + 3];
+                stream.write((const char *)&pixel, 4);
+            }
+        }
+    }
+
+    stream.close();
+
+    return true;
+}
+
+
+} /* namespace image */
diff --git a/image/image_png.cpp b/image/image_png.cpp
new file mode 100644 (file)
index 0000000..dba07d4
--- /dev/null
@@ -0,0 +1,206 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <zlib.h>
+#include <png.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <fstream>
+
+#include "image.hpp"
+
+
+namespace image {
+
+
+static const int png_compression_level = Z_BEST_SPEED;
+
+
+static void
+pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    std::ostream *os = (std::ostream *) png_get_io_ptr(png_ptr);
+    os->write((const char *)data, length);
+}
+
+bool
+Image::writePNG(std::ostream &os) const
+{
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int color_type;
+
+    switch (channels) {
+    case 4:
+        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+        break;
+    case 3:
+        color_type = PNG_COLOR_TYPE_RGB;
+        break;
+    case 2:
+        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+        break;
+    case 1:
+        color_type = PNG_COLOR_TYPE_GRAY;
+        break;
+    default:
+        assert(0);
+        goto no_png;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_write_struct(&png_ptr,  NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        goto no_png;
+    }
+
+    png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+                 color_type, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_set_compression_level(png_ptr, png_compression_level);
+
+    png_write_info(png_ptr, info_ptr);
+
+    if (!flipped) {
+        for (unsigned y = 0; y < height; ++y) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    } else {
+        unsigned y = height;
+        while (y--) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    }
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    return true;
+
+no_png:
+    return false;
+}
+
+
+Image *
+readPNG(const char *filename)
+{
+    FILE *fp;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_infop end_info;
+    Image *image;
+
+    fp = fopen(filename, "rb");
+    if (!fp)
+        goto no_fp;
+
+    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        goto no_png;
+    }
+
+    end_info = png_create_info_struct(png_ptr);
+    if (!end_info) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+        goto no_png;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    png_read_info(png_ptr, info_ptr);
+
+    png_uint_32 width, height;
+    int bit_depth, color_type, interlace_type, compression_type, filter_method;
+
+    png_get_IHDR(png_ptr, info_ptr,
+                 &width, &height,
+                 &bit_depth, &color_type, &interlace_type,
+                 &compression_type, &filter_method);
+
+    image = new Image(width, height);
+    if (!image)
+        goto no_image;
+
+    /* Convert to RGBA8 */
+    if (color_type == PNG_COLOR_TYPE_PALETTE)
+        png_set_palette_to_rgb(png_ptr);
+    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+        png_set_expand_gray_1_2_4_to_8(png_ptr);
+    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+        png_set_tRNS_to_alpha(png_ptr);
+    if (bit_depth == 16)
+        png_set_strip_16(png_ptr);
+
+    for (unsigned y = 0; y < height; ++y) {
+        png_bytep row = (png_bytep)(image->pixels + y*width*4);
+        png_read_row(png_ptr, row, NULL);
+    }
+
+    png_read_end(png_ptr, info_ptr);
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+    fclose(fp);
+    return image;
+
+no_image:
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+no_png:
+    fclose(fp);
+no_fp:
+    return NULL;
+}
+
+
+
+} /* namespace image */
diff --git a/image/image_pnm.cpp b/image/image_pnm.cpp
new file mode 100644 (file)
index 0000000..f9cd05d
--- /dev/null
@@ -0,0 +1,163 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "image.hpp"
+
+
+namespace image {
+
+/**
+ * http://en.wikipedia.org/wiki/Netpbm_format
+ * http://netpbm.sourceforge.net/doc/ppm.html
+ */
+void
+Image::writePNM(std::ostream &os, const char *comment) const {
+    assert(channels == 1 || channels >= 3);
+
+    os << (channels == 1 ? "P5" : "P6") << "\n";
+    if (comment) {
+        os << "#" << comment << "\n";
+    }
+    os << width << " " << height << "\n";
+    os << "255" << "\n";
+
+    const unsigned char *row;
+
+    if (channels == 1 || channels == 3) {
+        for (row = start(); row != end(); row += stride()) {
+            os.write((const char *)row, width*channels);
+        }
+    } else {
+        unsigned char *tmp = new unsigned char[width*3];
+        if (channels == 4) {
+            for (row = start(); row != end(); row += stride()) {
+                const uint32_t *src = (const uint32_t *)row;
+                uint32_t *dst = (uint32_t *)tmp;
+                unsigned x;
+                for (x = 0; x + 4 <= width; x += 4) {
+                    /*
+                     * It's much faster to access dwords than bytes.
+                     *
+                     * FIXME: Big-endian version.
+                     */
+
+                    uint32_t rgba0 = *src++ & 0xffffff;
+                    uint32_t rgba1 = *src++ & 0xffffff;
+                    uint32_t rgba2 = *src++ & 0xffffff;
+                    uint32_t rgba3 = *src++ & 0xffffff;
+                    uint32_t rgb0 = rgba0
+                                  | (rgba1 << 24);
+                    uint32_t rgb1 = (rgba1 >> 8)
+                                  | (rgba2 << 16);
+                    uint32_t rgb2 = (rgba2 >> 16)
+                                  | (rgba3 << 8);
+                    *dst++ = rgb0;
+                    *dst++ = rgb1;
+                    *dst++ = rgb2;
+                }
+                for (; x < width; ++x) {
+                    tmp[x*3 + 0] = row[x*4 + 0];
+                    tmp[x*3 + 1] = row[x*4 + 1];
+                    tmp[x*3 + 2] = row[x*4 + 2];
+                }
+                os.write((const char *)tmp, width*3);
+            }
+        } else if (channels == 2) {
+            for (row = start(); row != end(); row += stride()) {
+                const unsigned char *src = row;
+                unsigned char *dst = tmp;
+                for (unsigned x = 0; x < width; ++x) {
+                    *dst++ = *src++;
+                    *dst++ = *src++;
+                    *dst++ = 0;
+                }
+                os.write((const char *)tmp, width*3);
+            }
+        } else {
+            assert(0);
+        }
+        delete [] tmp;
+    }
+}
+
+const char *
+readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
+{
+    *channels = 0;
+    *width = 0;
+    *height = 0;
+
+    const char *currentBuffer = buffer;
+    const char *nextBuffer;
+
+    // parse number of channels
+    int scannedChannels = sscanf(currentBuffer, "P%d\n", channels);
+    if (scannedChannels != 1) { // validate scanning of channels
+        // invalid channel line
+        return buffer;
+    }
+    // convert channel token to number of channels
+    *channels = (*channels == 5) ? 1 : 3;
+
+    // advance past channel line
+    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
+    bufferSize -= nextBuffer - currentBuffer;
+    currentBuffer = nextBuffer;
+
+    // skip over optional comment
+    if (*currentBuffer == '#') {
+        // advance past comment line
+        nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
+        bufferSize -= nextBuffer - currentBuffer;
+        currentBuffer = nextBuffer;
+    }
+
+    // parse dimensions of image
+    int scannedDimensions = sscanf(currentBuffer, "%d %d\n", width, height);
+    if (scannedDimensions != 2) { // validate scanning of dimensions
+        // invalid dimension line
+        return buffer;
+    }
+
+    // advance past dimension line
+    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
+    bufferSize -= nextBuffer - currentBuffer;
+    currentBuffer = nextBuffer;
+
+    // skip over "255\n" at end of header
+    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
+
+    // return start of image data
+    return nextBuffer;
+}
+
+} /* namespace image */
diff --git a/inject/CMakeLists.txt b/inject/CMakeLists.txt
new file mode 100644 (file)
index 0000000..489b819
--- /dev/null
@@ -0,0 +1,19 @@
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+
+add_library (injectee MODULE
+    injectee.cpp
+)
+set_target_properties (injectee PROPERTIES
+    PREFIX ""
+    OUTPUT_NAME inject
+)
+install (TARGETS injectee LIBRARY DESTINATION bin)
+
+add_executable (injector
+    injector.cpp
+)
+set_target_properties (injector PROPERTIES
+    PREFIX ""
+    OUTPUT_NAME inject
+)
+install (TARGETS injector RUNTIME DESTINATION bin)
diff --git a/inject/inject.h b/inject/inject.h
new file mode 100644 (file)
index 0000000..058ada6
--- /dev/null
@@ -0,0 +1,181 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/*
+ * Code for the DLL that will be injected in the target process.
+ *
+ * The injected DLL will manipulate the import tables to hook the
+ * modules/functions of interest.
+ *
+ * See also:
+ * - http://www.codeproject.com/KB/system/api_spying_hack.aspx
+ * - http://www.codeproject.com/KB/threads/APIHooking.aspx
+ * - http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
+ */
+
+
+#include <windows.h>
+
+
+static inline const char *
+getSeparator(const char *szFilename) {
+    const char *p, *q;
+    p = NULL;
+    q = szFilename;
+    char c;
+    do  {
+        c = *q++;
+        if (c == '\\' || c == '/' || c == ':') {
+            p = q;
+        }
+    } while (c);
+    return p;
+}
+
+
+static inline const char *
+getBaseName(const char *szFilename) {
+    const char *pSeparator = getSeparator(szFilename);
+    if (!pSeparator) {
+        return szFilename;
+    }
+    return pSeparator;
+}
+
+
+static inline void
+getDirName(char *szFilename) {
+    char *pSeparator = const_cast<char *>(getSeparator(szFilename));
+    if (pSeparator) {
+        *pSeparator = '\0';
+    }
+}
+
+
+static inline void
+getModuleName(char *szModuleName, size_t n, const char *szFilename) {
+    char *p = szModuleName;
+    const char *q = getBaseName(szFilename);
+    char c;
+    while (--n) {
+        c = *q++;
+        if (c == '.' || c == '\0') {
+            break;
+        }
+        *p++ = c;
+    };
+    *p++ = '\0';
+}
+
+
+#define SHARED_MEM_SIZE 4096
+
+static LPVOID pSharedMem = NULL;
+static HANDLE hFileMapping = NULL;
+
+
+static LPSTR
+OpenSharedMemory(void) {
+    if (pSharedMem) {
+        return (LPSTR)pSharedMem;
+    }
+
+    hFileMapping = CreateFileMapping(
+        INVALID_HANDLE_VALUE,   // system paging file
+        NULL,                   // lpAttributes
+        PAGE_READWRITE,         // read/write access
+        0,                      // dwMaximumSizeHigh
+        SHARED_MEM_SIZE,              // dwMaximumSizeLow
+        TEXT("injectfilemap")); // name of map object
+    if (hFileMapping == NULL) {
+        fprintf(stderr, "Failed to create file mapping\n");
+        return NULL;
+    }
+
+    BOOL bAlreadyExists = (GetLastError() == ERROR_ALREADY_EXISTS);
+
+    pSharedMem = MapViewOfFile(
+        hFileMapping,
+        FILE_MAP_WRITE, // read/write access
+        0,              // dwFileOffsetHigh
+        0,              // dwFileOffsetLow
+        0);             // dwNumberOfBytesToMap (entire file)
+    if (pSharedMem == NULL) {
+        fprintf(stderr, "Failed to map view \n");
+        return NULL;
+    }
+
+    if (!bAlreadyExists) {
+        memset(pSharedMem, 0, SHARED_MEM_SIZE);
+    }
+
+    return (LPSTR)pSharedMem;
+}
+
+
+static inline VOID
+CloseSharedMem(void) {
+    if (!pSharedMem) {
+        return;
+    }
+
+    UnmapViewOfFile(pSharedMem);
+    pSharedMem = NULL;
+
+    CloseHandle(hFileMapping);
+    hFileMapping = NULL;
+}
+
+
+static inline VOID
+SetSharedMem(LPCSTR lpszSrc) {
+    LPSTR lpszDst = OpenSharedMemory();
+    if (!lpszDst) {
+        return;
+    }
+
+    size_t n = 1;
+    while (*lpszSrc && n < SHARED_MEM_SIZE) {
+        *lpszDst++ = *lpszSrc++;
+        n++;
+    }
+    *lpszDst = '\0';
+}
+
+
+static inline VOID
+GetSharedMem(LPSTR lpszDst, size_t n) {
+    LPCSTR lpszSrc = OpenSharedMemory();
+    if (!lpszSrc) {
+        return;
+    }
+
+    while (*lpszSrc && --n) {
+        *lpszDst++ = *lpszSrc++;
+    }
+    *lpszDst = '\0';
+}
+
diff --git a/inject/injectee.cpp b/inject/injectee.cpp
new file mode 100644 (file)
index 0000000..86992b8
--- /dev/null
@@ -0,0 +1,572 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/*
+ * Code for the DLL that will be injected in the target process.
+ *
+ * The injected DLL will manipulate the import tables to hook the
+ * modules/functions of interest.
+ *
+ * See also:
+ * - http://www.codeproject.com/KB/system/api_spying_hack.aspx
+ * - http://www.codeproject.com/KB/threads/APIHooking.aspx
+ * - http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <windows.h>
+#include <tlhelp32.h>
+
+#include "inject.h"
+
+
+#define VERBOSITY 0
+#define NOOP 0
+
+
+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);
+
+    va_list ap;
+    va_start(ap, format);
+    _vsnprintf(buf, sizeof buf, format, ap);
+    va_end(ap);
+
+    OutputDebugStringA(buf);
+
+    LeaveCriticalSection(&Mutex);
+#endif
+}
+
+
+static HMODULE WINAPI
+MyLoadLibraryA(LPCSTR lpLibFileName);
+
+static HMODULE WINAPI
+MyLoadLibraryW(LPCWSTR lpLibFileName);
+
+static HMODULE WINAPI
+MyLoadLibraryExA(LPCSTR lpFileName, HANDLE hFile, DWORD dwFlags);
+
+static HMODULE WINAPI
+MyLoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);
+
+static FARPROC WINAPI
+MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName);
+
+
+static const char *
+getImportDescriptionName(HMODULE hModule, const PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor) {
+    const char* szName = (const char*)((PBYTE)hModule + pImportDescriptor->Name);
+    return szName;
+}
+
+
+static PIMAGE_IMPORT_DESCRIPTOR
+getImportDescriptor(HMODULE hModule,
+                    const char *szModule,
+                    const char *pszDllName)
+{
+    MEMORY_BASIC_INFORMATION MemoryInfo;
+    if (VirtualQuery(hModule, &MemoryInfo, sizeof MemoryInfo) != sizeof MemoryInfo) {
+        debugPrintf("%s: %s: VirtualQuery failed\n", __FUNCTION__, szModule);
+        return NULL;
+    }
+    if (MemoryInfo.Protect & (PAGE_NOACCESS | PAGE_EXECUTE)) {
+        debugPrintf("%s: %s: no read access (Protect = 0x%08x)\n", __FUNCTION__, szModule, MemoryInfo.Protect);
+        return NULL;
+    }
+
+    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
+    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)hModule + pDosHeader->e_lfanew);
+
+    PIMAGE_OPTIONAL_HEADER pOptionalHeader = &pNtHeaders->OptionalHeader;
+
+    UINT_PTR ImportAddress = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+
+    if (!ImportAddress) {
+        return NULL;
+    }
+
+    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)hModule + ImportAddress);
+
+    while (pImportDescriptor->FirstThunk) {
+        const char* szName = getImportDescriptionName(hModule, pImportDescriptor);
+        if (stricmp(pszDllName, szName) == 0) {
+            return pImportDescriptor;
+        }
+        ++pImportDescriptor;
+    }
+
+    return NULL;
+}
+
+
+static BOOL
+replaceAddress(LPVOID *lpOldAddress, LPVOID lpNewAddress)
+{
+    DWORD flOldProtect;
+
+    if (*lpOldAddress == lpNewAddress) {
+        return TRUE;
+    }
+
+    EnterCriticalSection(&Mutex);
+
+    if (!(VirtualProtect(lpOldAddress, sizeof *lpOldAddress, PAGE_READWRITE, &flOldProtect))) {
+        LeaveCriticalSection(&Mutex);
+        return FALSE;
+    }
+
+    *lpOldAddress = lpNewAddress;
+
+    if (!(VirtualProtect(lpOldAddress, sizeof *lpOldAddress, flOldProtect, &flOldProtect))) {
+        LeaveCriticalSection(&Mutex);
+        return FALSE;
+    }
+
+    LeaveCriticalSection(&Mutex);
+    return TRUE;
+}
+
+
+static LPVOID *
+getOldFunctionAddress(HMODULE hModule,
+                    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor,
+                    const char* pszFunctionName)
+{
+    PIMAGE_THUNK_DATA pOriginalFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDescriptor->OriginalFirstThunk);
+    PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDescriptor->FirstThunk);
+
+    //debugPrintf("  %s\n", __FUNCTION__);
+
+    while (pOriginalFirstThunk->u1.Function) {
+        PIMAGE_IMPORT_BY_NAME pImport = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hModule + pOriginalFirstThunk->u1.AddressOfData);
+        const char* szName = (const char* )pImport->Name;
+        //debugPrintf("    %s\n", szName);
+        if (strcmp(pszFunctionName, szName) == 0) {
+            //debugPrintf("  %s succeeded\n", __FUNCTION__);
+            return (LPVOID *)(&pFirstThunk->u1.Function);
+        }
+        ++pOriginalFirstThunk;
+        ++pFirstThunk;
+    }
+
+    //debugPrintf("  %s failed\n", __FUNCTION__);
+
+    return NULL;
+}
+
+
+static void
+replaceModule(HMODULE hModule,
+              const char *szModule,
+              PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor,
+              HMODULE hNewModule)
+{
+    PIMAGE_THUNK_DATA pOriginalFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDescriptor->OriginalFirstThunk);
+    PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDescriptor->FirstThunk);
+
+    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);
+
+        PROC pNewProc = GetProcAddress(hNewModule, szFunctionName);
+        if (!pNewProc) {
+            debugPrintf("  warning: no replacement for %s\n", szFunctionName);
+        } else {
+            LPVOID *lpOldAddress = (LPVOID *)(&pFirstThunk->u1.Function);
+            replaceAddress(lpOldAddress, (LPVOID)pNewProc);
+        }
+
+        ++pOriginalFirstThunk;
+        ++pFirstThunk;
+    }
+}
+
+
+static BOOL
+hookFunction(HMODULE hModule,
+             const char *szModule,
+             const char *pszDllName,
+             const char *pszFunctionName,
+             LPVOID lpNewAddress)
+{
+    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = getImportDescriptor(hModule, szModule, pszDllName);
+    if (pImportDescriptor == NULL) {
+        return FALSE;
+    }
+    LPVOID* lpOldFunctionAddress = getOldFunctionAddress(hModule, pImportDescriptor, pszFunctionName);
+    if (lpOldFunctionAddress == NULL) {
+        return FALSE;
+    }
+
+    if (*lpOldFunctionAddress == lpNewAddress) {
+        return TRUE;
+    }
+
+    if (VERBOSITY >= 3) {
+        debugPrintf("      hooking %s->%s!%s\n", szModule, pszDllName, pszFunctionName);
+    }
+
+    return replaceAddress(lpOldFunctionAddress, lpNewAddress);
+}
+
+
+static BOOL
+replaceImport(HMODULE hModule,
+              const char *szModule,
+              const char *pszDllName,
+              HMODULE hNewModule)
+{
+#if NOOP
+    return TRUE;
+#endif
+
+    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = getImportDescriptor(hModule, szModule, pszDllName);
+    if (pImportDescriptor == NULL) {
+        return TRUE;
+    }
+
+    replaceModule(hModule, szModule, pImportDescriptor, hNewModule);
+
+    return TRUE;
+}
+
+static HMODULE g_hThisModule = NULL;
+
+
+struct Replacement {
+    const char *szMatchModule;
+    HMODULE hReplaceModule;
+};
+
+static unsigned numReplacements = 0;
+static Replacement replacements[32];
+
+
+
+static void
+hookModule(HMODULE hModule,
+           const char *szModule)
+{
+    if (hModule == g_hThisModule) {
+        return;
+    }
+
+    for (unsigned i = 0; i < numReplacements; ++i) {
+        if (hModule == replacements[i].hReplaceModule) {
+            return;
+        }
+    }
+
+    hookFunction(hModule, szModule, "kernel32.dll", "LoadLibraryA", (LPVOID)MyLoadLibraryA);
+    hookFunction(hModule, szModule, "kernel32.dll", "LoadLibraryW", (LPVOID)MyLoadLibraryW);
+    hookFunction(hModule, szModule, "kernel32.dll", "LoadLibraryExA", (LPVOID)MyLoadLibraryExA);
+    hookFunction(hModule, szModule, "kernel32.dll", "LoadLibraryExW", (LPVOID)MyLoadLibraryExW);
+    hookFunction(hModule, szModule, "kernel32.dll", "GetProcAddress", (LPVOID)MyGetProcAddress);
+
+    const char *szBaseName = getBaseName(szModule);
+    for (unsigned i = 0; i < numReplacements; ++i) {
+        if (stricmp(szBaseName, replacements[i].szMatchModule) == 0) {
+            return;
+        }
+    }
+
+    /* Don't hook internal dependencies */
+    if (stricmp(szBaseName, "d3d10core.dll") == 0 ||
+        stricmp(szBaseName, "d3d10level9.dll") == 0 ||
+        stricmp(szBaseName, "d3d10sdklayers.dll") == 0 ||
+        stricmp(szBaseName, "d3d10_1core.dll") == 0 ||
+        stricmp(szBaseName, "d3d11sdklayers.dll") == 0 ||
+        stricmp(szBaseName, "d3d11_1sdklayers.dll") == 0) {
+        return;
+    }
+
+    for (unsigned i = 0; i < numReplacements; ++i) {
+        replaceImport(hModule, szModule, replacements[i].szMatchModule, replacements[i].hReplaceModule);
+        replaceImport(hModule, szModule, replacements[i].szMatchModule, replacements[i].hReplaceModule);
+        replaceImport(hModule, szModule, replacements[i].szMatchModule, replacements[i].hReplaceModule);
+    }
+}
+
+static void
+hookAllModules(void)
+{
+    HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
+    if (hModuleSnap == INVALID_HANDLE_VALUE) {
+        return;
+    }
+
+    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));
+        }
+        first = false;
+    }
+
+    if (Module32First(hModuleSnap, &me32)) {
+        do  {
+            hookModule(me32.hModule, me32.szExePath);
+        } while (Module32Next(hModuleSnap, &me32));
+    }
+
+    CloseHandle(hModuleSnap);
+}
+
+
+
+
+static HMODULE WINAPI
+MyLoadLibrary(LPCSTR lpLibFileName, HANDLE hFile = NULL, DWORD dwFlags = 0)
+{
+    // To Send the information to the server informing that,
+    // LoadLibrary is invoked.
+    HMODULE hModule = LoadLibraryExA(lpLibFileName, hFile, dwFlags);
+
+    //hookModule(hModule, lpLibFileName);
+    hookAllModules();
+
+    return hModule;
+}
+
+static HMODULE WINAPI
+MyLoadLibraryA(LPCSTR lpLibFileName)
+{
+    if (VERBOSITY >= 2) {
+        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);
+#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);
+#endif
+            break;
+        }
+    }
+
+    return MyLoadLibrary(lpLibFileName);
+}
+
+static HMODULE WINAPI
+MyLoadLibraryW(LPCWSTR lpLibFileName)
+{
+    if (VERBOSITY >= 2) {
+        debugPrintf("%s(L\"%S\")\n", __FUNCTION__, lpLibFileName);
+    }
+
+    char szFileName[256];
+    wcstombs(szFileName, lpLibFileName, sizeof szFileName);
+
+    return MyLoadLibrary(szFileName);
+}
+
+static HMODULE WINAPI
+MyLoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+    if (VERBOSITY >= 2) {
+        debugPrintf("%s(\"%s\")\n", __FUNCTION__, lpLibFileName);
+    }
+    return MyLoadLibrary(lpLibFileName, hFile, dwFlags);
+}
+
+static HMODULE WINAPI
+MyLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+    if (VERBOSITY >= 2) {
+        debugPrintf("%s(L\"%S\")\n", __FUNCTION__, lpLibFileName);
+    }
+
+    char szFileName[256];
+    wcstombs(szFileName, lpLibFileName, sizeof szFileName);
+
+    return MyLoadLibrary(szFileName, hFile, dwFlags);
+}
+
+static FARPROC WINAPI
+MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
+
+    if (VERBOSITY >= 99) {
+        /* XXX this can cause segmentation faults */
+        debugPrintf("%s(\"%s\")\n", __FUNCTION__, lpProcName);
+    }
+
+    assert(hModule != g_hThisModule);
+    for (unsigned i = 0; i < numReplacements; ++i) {
+        if (hModule == replacements[i].hReplaceModule) {
+            return GetProcAddress(hModule, lpProcName);
+        }
+    }
+
+#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) {
+
+        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);
+                }
+                return pProcAddress;
+            } else {
+                debugPrintf("      ignoring %s!%s\n", szBaseName, lpProcName);
+                break;
+            }
+        }
+    }
+#endif
+
+    return GetProcAddress(hModule, lpProcName);
+}
+
+
+EXTERN_C BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
+{
+    const char *szNewDllName = NULL;
+    HMODULE hNewModule = NULL;
+    const char *szNewDllBaseName;
+
+    switch (fdwReason) {
+    case DLL_PROCESS_ATTACH:
+        debugPrintf("DLL_PROCESS_ATTACH\n");
+
+        g_hThisModule = hinstDLL;
+
+        {
+            char szProcess[MAX_PATH];
+            GetModuleFileNameA(NULL, szProcess, sizeof szProcess);
+            debugPrintf("  attached to %s\n", szProcess);
+        }
+
+        /*
+         * Calling LoadLibrary inside DllMain is strongly discouraged.  But it
+         * works quite well, provided that the loaded DLL does not require or do
+         * anything special in its DllMain, which seems to be the general case.
+         *
+         * See also:
+         * - http://stackoverflow.com/questions/4370812/calling-loadlibrary-from-dllmain
+         * - http://msdn.microsoft.com/en-us/library/ms682583
+         */
+
+#if 0
+        szNewDllName = getenv("INJECT_DLL");
+        if (!szNewDllName) {
+            debugPrintf("warning: INJECT_DLL not set\n");
+            return FALSE;
+        }
+#else
+        static char szSharedMemCopy[MAX_PATH];
+        GetSharedMem(szSharedMemCopy, sizeof szSharedMemCopy);
+        szNewDllName = szSharedMemCopy;
+#endif
+        debugPrintf("  injecting %s\n", szNewDllName);
+
+        hNewModule = LoadLibraryA(szNewDllName);
+        if (!hNewModule) {
+            debugPrintf("warning: failed to load %s\n", szNewDllName);
+            return FALSE;
+        }
+
+        szNewDllBaseName = getBaseName(szNewDllName);
+        if (stricmp(szNewDllBaseName, "dxgitrace.dll") == 0) {
+            replacements[numReplacements].szMatchModule = "dxgi.dll";
+            replacements[numReplacements].hReplaceModule = hNewModule;
+            ++numReplacements;
+
+            replacements[numReplacements].szMatchModule = "d3d10.dll";
+            replacements[numReplacements].hReplaceModule = hNewModule;
+            ++numReplacements;
+
+            replacements[numReplacements].szMatchModule = "d3d10_1.dll";
+            replacements[numReplacements].hReplaceModule = hNewModule;
+            ++numReplacements;
+
+            replacements[numReplacements].szMatchModule = "d3d11.dll";
+            replacements[numReplacements].hReplaceModule = hNewModule;
+            ++numReplacements;
+        } else {
+            replacements[numReplacements].szMatchModule = szNewDllBaseName;
+            replacements[numReplacements].hReplaceModule = hNewModule;
+            ++numReplacements;
+        }
+
+        hookAllModules();
+        break;
+
+    case DLL_THREAD_ATTACH:
+        break;
+
+    case DLL_THREAD_DETACH:
+        break;
+
+    case DLL_PROCESS_DETACH:
+        debugPrintf("DLL_PROCESS_DETACH\n");
+        break;
+    }
+    return TRUE;
+}
diff --git a/inject/injector.cpp b/inject/injector.cpp
new file mode 100644 (file)
index 0000000..04e0959
--- /dev/null
@@ -0,0 +1,289 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/*
+ * Main program to start and inject a DLL into a process via a remote thread.
+ *
+ * For background see:
+ * - http://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows
+ * - http://www.codeproject.com/KB/threads/completeinject.aspx
+ * - http://www.codeproject.com/KB/threads/winspy.aspx
+ * - http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
+ * - http://www.codeproject.com/KB/threads/APIHooking.aspx
+ *
+ * Other slightly different techniques:
+ * - http://www.fr33project.org/pages/projects/phook.htm
+ * - http://www.hbgary.com/loading-a-dll-without-calling-loadlibrary
+ * - http://securityxploded.com/ntcreatethreadex.php
+ */
+
+#include <string>
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "inject.h"
+
+
+/**
+ * Determine whether an argument should be quoted.
+ */
+static bool
+needsQuote(const char *arg)
+{
+    char c;
+    while (true) {
+        c = *arg++;
+        if (c == '\0') {
+            break;
+        }
+        if (c == ' ' || c == '\t' || c == '\"') {
+            return true;
+        }
+        if (c == '\\') {
+            c = *arg++;
+            if (c == '\0') {
+                break;
+            }
+            if (c == '"') {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+static void
+quoteArg(std::string &s, const char *arg)
+{
+    char c;
+    unsigned backslashes = 0;
+
+    s.push_back('"');
+    while (true) {
+        c = *arg++;
+        if (c == '\0') {
+            break;
+        } else if (c == '"') {
+            while (backslashes) {
+                s.push_back('\\');
+                --backslashes;
+            }
+            s.push_back('\\');
+        } else {
+            if (c == '\\') {
+                ++backslashes;
+            } else {
+                backslashes = 0;
+            }
+        }
+        s.push_back(c);
+    }
+    s.push_back('"');
+}
+
+
+int
+main(int argc, char *argv[])
+{
+
+    if (argc < 3) {
+        fprintf(stderr, "inject dllname.dll command [args] ...\n");
+        return 1;
+    }
+
+    const char *szDll = argv[1];
+#if 0
+    SetEnvironmentVariableA("INJECT_DLL", szDll);
+#else
+    SetSharedMem(szDll);
+#endif
+
+    PROCESS_INFORMATION processInfo;
+    HANDLE hProcess;
+    BOOL bAttach;
+    if (isdigit(argv[2][0])) {
+        bAttach = TRUE;
+
+        BOOL bRet;
+        HANDLE hToken   = NULL;
+        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
+        if (!bRet) {
+            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
+            return 1;
+        }
+
+        LUID Luid;
+        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
+        if (!bRet) {
+            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
+            return 1;
+        }
+
+        TOKEN_PRIVILEGES tp;
+        tp.PrivilegeCount = 1;
+        tp.Privileges[0].Luid = Luid;
+        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
+        if (!bRet) {
+            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
+            return 1;
+        }
+
+        DWORD dwDesiredAccess =
+            PROCESS_CREATE_THREAD |
+            PROCESS_QUERY_INFORMATION |
+            PROCESS_QUERY_LIMITED_INFORMATION |
+            PROCESS_VM_OPERATION |
+            PROCESS_VM_WRITE |
+            PROCESS_VM_READ;
+        DWORD dwProcessId = atol(argv[2]);
+        hProcess = OpenProcess(
+            dwDesiredAccess,
+            FALSE /* bInheritHandle */,
+            dwProcessId);
+        if (!hProcess) {
+            DWORD dwLastError = GetLastError();
+            fprintf(stderr, "error: failed to open process %lu (%lu)\n", dwProcessId, dwLastError);
+            return 1;
+        }
+    } else {
+        bAttach = FALSE;
+        std::string commandLine;
+        char sep = 0;
+        for (int i = 2; i < argc; ++i) {
+            const char *arg = argv[i];
+
+            if (sep) {
+                commandLine.push_back(sep);
+            }
+
+            if (needsQuote(arg)) {
+                quoteArg(commandLine, arg);
+            } else {
+                commandLine.append(arg);
+            }
+
+            sep = ' ';
+        }
+
+        STARTUPINFO startupInfo;
+        memset(&startupInfo, 0, sizeof startupInfo);
+        startupInfo.cb = sizeof startupInfo;
+
+        // Create the process in suspended state
+        if (!CreateProcessA(
+               NULL,
+               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
+               0, // process attributes
+               0, // thread attributes
+               TRUE, // inherit handles
+               CREATE_SUSPENDED,
+               NULL, // environment
+               NULL, // current directory
+               &startupInfo,
+               &processInfo)) {
+            fprintf(stderr, "error: failed to execute %s\n", commandLine.c_str());
+            return 1;
+        }
+
+        hProcess = processInfo.hProcess;
+    }
+
+    /*
+     * XXX: Mixed architecture don't quite work.  See also
+     * http://www.corsix.org/content/dll-injection-and-wow64
+     */
+    const char *szDllName;
+    szDllName = "inject.dll";
+
+    char szDllPath[MAX_PATH];
+    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
+    getDirName(szDllPath);
+    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);
+
+    size_t szDllPathLength = strlen(szDllPath) + 1;
+
+    // Allocate memory in the target process to hold the DLL name
+    void *lpMemory = VirtualAllocEx(hProcess, NULL, szDllPathLength, MEM_COMMIT, PAGE_READWRITE);
+    if (!lpMemory) {
+        fprintf(stderr, "error: failed to allocate memory in the process\n");
+        TerminateProcess(hProcess, 1);
+        return 1;
+    }
+
+    // Copy DLL name into the target process
+    if (!WriteProcessMemory(hProcess, lpMemory, szDllPath, szDllPathLength, NULL)) {
+        fprintf(stderr, "error: failed to write into process memory\n");
+        TerminateProcess(hProcess, 1);
+        return 1;
+    }
+
+    /*
+     * Get LoadLibraryA address from kernel32.dll.  It's the same for all the
+     * process (XXX: but only within the same architecture).
+     */
+    PTHREAD_START_ROUTINE lpStartAddress =
+        (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("KERNEL32"), "LoadLibraryA");
+
+    // Create remote thread in another process
+    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, lpMemory, 0, NULL);
+    if (!hThread) {
+        fprintf(stderr, "error: failed to create remote thread\n");
+        TerminateProcess(hProcess, 1);
+        return 1;
+    }
+
+    // Wait for it to finish
+    WaitForSingleObject(hThread, INFINITE);
+
+    DWORD hModule = 0;
+    GetExitCodeThread(hThread, &hModule);
+    if (!hModule) {
+        fprintf(stderr, "error: failed to inject %s\n", szDllPath);
+        TerminateProcess(hProcess, 1);
+        return 1;
+    }
+
+    if (bAttach) {
+        return 0;
+    }
+
+    // Start main process thread
+    ResumeThread(processInfo.hThread);
+
+    // Wait for it to finish
+    WaitForSingleObject(hProcess, INFINITE);
+
+    DWORD exitCode = ~0;
+    GetExitCodeProcess(hProcess, &exitCode);
+
+    CloseHandle(hProcess);
+    CloseHandle(processInfo.hThread);
+
+    return (int)exitCode;
+
+}
index 5a2a6088d5da9decd77c81af7182b1c3031c81ed..c6a364f30f42f66a6fdb92f7eda432dff52fef65 100644 (file)
@@ -6,6 +6,7 @@ include_directories (
     ${CMAKE_SOURCE_DIR}/helpers
     ${CMAKE_BINARY_DIR}/dispatch
     ${CMAKE_SOURCE_DIR}/dispatch
+    ${CMAKE_SOURCE_DIR}/image
 )
 
 add_definitions (-DRETRACE)
@@ -39,8 +40,8 @@ add_library (retrace_common STATIC
     json.cpp
 )
 target_link_libraries (retrace_common
+    image
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}
index 15be6c48ceb930bac3f122bb48ea59075fd80c5d..d5e41da04146d3597264ed8f1dbea2e74c0f46c6 100644 (file)
 
 #include <iostream>
 
-#include "d3d11imports.hpp"
-#include "json.hpp"
-#include "d3dshader.hpp"
-#include "d3dstate.hpp"
+#include "d3d10imports.hpp"
+#include "d3d10state.hpp"
 
 
 namespace d3dstate {
@@ -41,46 +39,6 @@ const GUID
 GUID_D3DSTATE = {0x7D71CAC9,0x7F58,0x432C,{0xA9,0x75,0xA1,0x9F,0xCF,0xCE,0xFD,0x14}};
 
 
-template< class T >
-inline void
-dumpShader(JSONWriter &json, const char *name, T *pShader) {
-    if (!pShader) {
-        return;
-    }
-
-    HRESULT hr;
-
-    /*
-     * There is no method to get the shader byte code, so the creator is supposed to
-     * attach it via the SetPrivateData method.
-     */
-    UINT BytecodeLength = 0;
-    char dummy;
-    hr = pShader->GetPrivateData(GUID_D3DSTATE, &BytecodeLength, &dummy);
-    if (hr != DXGI_ERROR_MORE_DATA) {
-        return;
-    }
-
-    void *pShaderBytecode = malloc(BytecodeLength);
-    if (!pShaderBytecode) {
-        return;
-    }
-
-    hr = pShader->GetPrivateData(GUID_D3DSTATE, &BytecodeLength, pShaderBytecode);
-    if (SUCCEEDED(hr)) {
-        IDisassemblyBuffer *pDisassembly = NULL;
-        hr = DisassembleShader(pShaderBytecode, BytecodeLength, &pDisassembly);
-        if (SUCCEEDED(hr)) {
-            json.beginMember(name);
-            json.writeString((const char *)pDisassembly->GetBufferPointer() /*, pDisassembly->GetBufferSize() */);
-            json.endMember();
-            pDisassembly->Release();
-        }
-    }
-
-    free(pShaderBytecode);
-}
-
 static void
 dumpShaders(JSONWriter &json, ID3D10Device *pDevice)
 {
diff --git a/retrace/d3d10state.hpp b/retrace/d3d10state.hpp
new file mode 100644 (file)
index 0000000..b480bd6
--- /dev/null
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _DXGISTATE_HPP_
+#define _DXGISTATE_HPP_
+
+
+#include <windows.h>
+
+
+#include "json.hpp"
+#include "d3dshader.hpp"
+#include "d3dstate.hpp"
+
+
+namespace d3dstate {
+
+
+template< class T >
+inline void
+dumpShader(JSONWriter &json, const char *name, T *pShader) {
+    if (!pShader) {
+        return;
+    }
+
+    HRESULT hr;
+
+    /*
+     * There is no method to get the shader byte code, so the creator is supposed to
+     * attach it via the SetPrivateData method.
+     */
+    UINT BytecodeLength = 0;
+    char dummy;
+    hr = pShader->GetPrivateData(GUID_D3DSTATE, &BytecodeLength, &dummy);
+    if (hr != DXGI_ERROR_MORE_DATA) {
+        return;
+    }
+
+    void *pShaderBytecode = malloc(BytecodeLength);
+    if (!pShaderBytecode) {
+        return;
+    }
+
+    hr = pShader->GetPrivateData(GUID_D3DSTATE, &BytecodeLength, pShaderBytecode);
+    if (SUCCEEDED(hr)) {
+        IDisassemblyBuffer *pDisassembly = NULL;
+        hr = DisassembleShader(pShaderBytecode, BytecodeLength, &pDisassembly);
+        if (SUCCEEDED(hr)) {
+            json.beginMember(name);
+            json.writeString((const char *)pDisassembly->GetBufferPointer() /*, pDisassembly->GetBufferSize() */);
+            json.endMember();
+            pDisassembly->Release();
+        }
+    }
+
+    free(pShaderBytecode);
+}
+
+
+} /* namespace d3dstate */
+
+#endif // _DXGISTATE_HPP_
index 05885f4cd2cde494760cd8e8627aaacd15f82371..bc8f7c44b2618f366585322c1deb8f14385ba6c5 100644 (file)
 #include <iostream>
 
 #include "d3d11imports.hpp"
-#include "json.hpp"
+#include "d3d10state.hpp"
 
 
 namespace d3dstate {
 
 
+static void
+dumpShaders(JSONWriter &json, ID3D11DeviceContext *pDeviceContext)
+{
+    json.beginMember("shaders");
+    json.beginObject();
+
+    ID3D11VertexShader *pVertexShader = NULL;
+    pDeviceContext->VSGetShader(&pVertexShader, NULL, NULL);
+    if (pVertexShader) {
+        dumpShader<ID3D11DeviceChild>(json, "VS", pVertexShader);
+        pVertexShader->Release();
+    }
+
+    ID3D11GeometryShader *pGeometryShader = NULL;
+    pDeviceContext->GSGetShader(&pGeometryShader, NULL, NULL);
+    if (pGeometryShader) {
+        dumpShader<ID3D11DeviceChild>(json, "GS", pGeometryShader);
+        pGeometryShader->Release();
+    }
+
+    ID3D11PixelShader *pPixelShader = NULL;
+    pDeviceContext->PSGetShader(&pPixelShader, NULL, NULL);
+    if (pPixelShader) {
+        dumpShader<ID3D11DeviceChild>(json, "PS", pPixelShader);
+    }
+
+    json.endObject();
+    json.endMember(); // shaders
+}
+
+
 void
 dumpDevice(std::ostream &os, ID3D11DeviceContext *pDeviceContext)
 {
     JSONWriter json(os);
 
     /* TODO */
+    json.beginMember("parameters");
+    json.beginObject();
+    json.endObject();
+    json.endMember(); // parameters
+
+    dumpShaders(json, pDeviceContext);
+
+    json.beginMember("textures");
+    json.beginObject();
+    json.endObject();
+    json.endMember(); // textures
+
+    dumpFramebuffer(json, pDeviceContext);
 }
 
 
index 9c6ff87d1835b45640b7b6d2adbc96f10b927484..fda85b15f05d8973b76450caed1b9295ed0f8f9c 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "image.hpp"
 #include "d3d11imports.hpp"
+#include "d3d10state.hpp"
 
 
 namespace d3dstate {
@@ -140,9 +141,10 @@ stageResource(ID3D11DeviceContext *pDeviceContext,
 }
 
 image::Image *
-getRenderTargetImage(ID3D11DeviceContext *pDevice) {
+getRenderTargetViewImage(ID3D11DeviceContext *pDevice,
+                         ID3D11RenderTargetView *pRenderTargetView) {
     image::Image *image = NULL;
-    ID3D11RenderTargetView *pRenderTargetView = NULL;
+    ;
     D3D11_RENDER_TARGET_VIEW_DESC Desc;
     ID3D11Resource *pResource = NULL;
     ID3D11Resource *pStagingResource = NULL;
@@ -154,9 +156,8 @@ getRenderTargetImage(ID3D11DeviceContext *pDevice) {
     const unsigned char *src;
     unsigned char *dst;
 
-    pDevice->OMGetRenderTargets(1, &pRenderTargetView, NULL);
     if (!pRenderTargetView) {
-        goto no_rendertarget;
+        return NULL;
     }
 
     pRenderTargetView->GetResource(&pResource);
@@ -164,7 +165,8 @@ getRenderTargetImage(ID3D11DeviceContext *pDevice) {
 
     pRenderTargetView->GetDesc(&Desc);
     if (Desc.Format != DXGI_FORMAT_R8G8B8A8_UNORM &&
-        Desc.Format != DXGI_FORMAT_R32G32B32A32_FLOAT) {
+        Desc.Format != DXGI_FORMAT_R32G32B32A32_FLOAT &&
+        Desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) {
         std::cerr << "warning: unsupported DXGI format " << Desc.Format << "\n";
         goto no_staging;
     }
@@ -235,6 +237,13 @@ getRenderTargetImage(ID3D11DeviceContext *pDevice) {
                 dst[4*x + 2] = ((float *)src)[4*x + 2] * scale;
                 dst[4*x + 3] = ((float *)src)[4*x + 3] * scale;
             }
+        } else if (Desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM) {
+            for (unsigned x = 0; x < Width; ++x) {
+                dst[4*x + 0] = src[4*x + 2];
+                dst[4*x + 1] = src[4*x + 1];
+                dst[4*x + 2] = src[4*x + 0];
+                dst[4*x + 3] = src[4*x + 3];
+            }
         } else {
             assert(0);
         }
@@ -252,12 +261,57 @@ no_staging:
     if (pResource) {
         pResource->Release();
     }
+    return image;
+}
+
+
+
+
+image::Image *
+getRenderTargetImage(ID3D11DeviceContext *pDevice) {
+    ID3D11RenderTargetView *pRenderTargetView = NULL;
+    pDevice->OMGetRenderTargets(1, &pRenderTargetView, NULL);
+
+    image::Image *image = NULL;
     if (pRenderTargetView) {
+        image = getRenderTargetViewImage(pDevice, pRenderTargetView);
         pRenderTargetView->Release();
     }
-no_rendertarget:
+
     return image;
 }
 
 
+void
+dumpFramebuffer(JSONWriter &json, ID3D11DeviceContext *pDevice)
+{
+    json.beginMember("framebuffer");
+    json.beginObject();
+
+    ID3D11RenderTargetView *pRenderTargetViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
+    pDevice->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, pRenderTargetViews, NULL);
+
+    for (UINT i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
+        if (!pRenderTargetViews[i]) {
+            continue;
+        }
+
+        image::Image *image;
+        image = getRenderTargetViewImage(pDevice, pRenderTargetViews[i]);
+        if (image) {
+            char label[64];
+            _snprintf(label, sizeof label, "RENDER_TARGET_%u", i);
+            json.beginMember(label);
+            json.writeImage(image, "UNKNOWN");
+            json.endMember(); // RENDER_TARGET_*
+        }
+
+        pRenderTargetViews[i]->Release();
+    }
+
+    json.endObject();
+    json.endMember(); // framebuffer
+}
+
+
 } /* namespace d3dstate */
index 99cb6037655247d9825fb009a0cec9946bb8431d..a90ee6da037de7e12f3dcbb104bb3659acf88e61 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "d3d9imports.hpp"
 #include "d3dshader.hpp"
+#include "d3dstate.hpp"
 #include "json.hpp"
 
 
@@ -100,9 +101,20 @@ dumpDevice(std::ostream &os, IDirect3DDevice9 *pDevice)
 {
     JSONWriter json(os);
 
+    /* TODO */
+    json.beginMember("parameters");
+    json.beginObject();
+    json.endObject();
+    json.endMember(); // parameters
+
     dumpShaders(json, pDevice);
 
-    /* TODO */
+    json.beginMember("textures");
+    json.beginObject();
+    json.endObject();
+    json.endMember(); // textures
+
+    dumpFramebuffer(json, pDevice);
 }
 
 
index 855dede27801251ac4c935c8f425ce3095129f8f..81f7f7f08fc6ab4f760d4795f29a7feb9b286fe2 100644 (file)
 #include <assert.h>
 
 #include "image.hpp"
+#include "json.hpp"
 #include "d3d9imports.hpp"
+#include "d3dstate.hpp"
 
 
 namespace d3dstate {
 
 
-image::Image *
-getRenderTargetImage(IDirect3DDevice9 *pDevice) {
+static image::Image *
+getRenderTargetImage(IDirect3DDevice9 *pDevice,
+                     IDirect3DSurface9 *pRenderTarget) {
     image::Image *image = NULL;
-    IDirect3DSurface9 *pRenderTarget = NULL;
     D3DSURFACE_DESC Desc;
     IDirect3DSurface9 *pStagingSurface = NULL;
     D3DLOCKED_RECT LockedRect;
@@ -44,15 +46,17 @@ getRenderTargetImage(IDirect3DDevice9 *pDevice) {
     unsigned char *dst;
     HRESULT hr;
 
-    hr = pDevice->GetRenderTarget(0, &pRenderTarget);
-    if (FAILED(hr)) {
-        goto no_rendertarget;
+    if (!pRenderTarget) {
+        return NULL;
     }
-    assert(pRenderTarget);
 
     hr = pRenderTarget->GetDesc(&Desc);
     assert(SUCCEEDED(hr));
-    assert(Desc.Format == D3DFMT_X8R8G8B8 || Desc.Format == D3DFMT_A8R8G8B8);
+
+    if (Desc.Format != D3DFMT_X8R8G8B8 && Desc.Format != D3DFMT_A8R8G8B8) {
+        std::cerr << "warning: unsupported D3DFORMAT " << Desc.Format << "\n";
+        goto no_staging;
+    }
 
     hr = pDevice->CreateOffscreenPlainSurface(Desc.Width, Desc.Height, Desc.Format, D3DPOOL_SYSTEMMEM, &pStagingSurface, NULL);
     if (FAILED(hr)) {
@@ -91,10 +95,69 @@ no_image:
 no_rendertargetdata:
     pStagingSurface->Release();
 no_staging:
-    pRenderTarget->Release();
-no_rendertarget:
     return image;
 }
 
 
+image::Image *
+getRenderTargetImage(IDirect3DDevice9 *pDevice) {
+    HRESULT hr;
+
+    IDirect3DSurface9 *pRenderTarget = NULL;
+    hr = pDevice->GetRenderTarget(0, &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, IDirect3DDevice9 *pDevice)
+{
+    HRESULT hr;
+
+    json.beginMember("framebuffer");
+    json.beginObject();
+
+    D3DCAPS9 Caps;
+    pDevice->GetDeviceCaps(&Caps);
+
+    for (UINT i = 0; i < Caps.NumSimultaneousRTs; ++i) {
+        IDirect3DSurface9 *pRenderTarget = NULL;
+        hr = pDevice->GetRenderTarget(i, &pRenderTarget);
+        if (FAILED(hr)) {
+            continue;
+        }
+
+        if (!pRenderTarget) {
+            continue;
+        }
+
+        image::Image *image;
+        image = getRenderTargetImage(pDevice, pRenderTarget);
+        if (image) {
+            char label[64];
+            _snprintf(label, sizeof label, "RENDER_TARGET_%u", i);
+            json.beginMember(label);
+            json.writeImage(image, "UNKNOWN");
+            json.endMember(); // RENDER_TARGET_*
+        }
+
+        pRenderTarget->Release();
+    }
+
+    json.endObject();
+    json.endMember(); // framebuffer
+}
+
+
 } /* namespace d3dstate */
index 09e82a2805a96ae711cd647b4f94f8b584fa6b81..3766a91353e6710396d8801f0ffa75bdef10aa0e 100644 (file)
@@ -53,6 +53,9 @@ extern const GUID GUID_D3DSTATE;
 image::Image *
 getRenderTargetImage(IDirect3DDevice9 *pDevice);
 
+void
+dumpFramebuffer(JSONWriter &json, IDirect3DDevice9 *pDevice);
+
 void
 dumpDevice(std::ostream &os, IDirect3DDevice9 *pDevice);
 
@@ -70,6 +73,9 @@ dumpDevice(std::ostream &os, ID3D10Device *pDevice);
 image::Image *
 getRenderTargetImage(ID3D11DeviceContext *pDeviceContext);
 
+void
+dumpFramebuffer(JSONWriter &json, ID3D11DeviceContext *pDeviceContext);
+
 void
 dumpDevice(std::ostream &os, ID3D11DeviceContext *pDeviceContext);
 
index a412c3aeb8b86a6b53a61d56740bcc978a78b126..8de3c989efa5f46057c6b04c19cbee22665af4f0 100644 (file)
@@ -74,14 +74,6 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
             if 'pSwapChainDesc' in function.argNames():
                 print r'    createWindow(pSwapChainDesc);'
 
-            # Compensate for the fact we don't trace the software renderer
-            # module LoadLibrary call
-            if 'Software' in function.argNames():
-                print r'    if (Software) {'
-                print r'        retrace::warning(call) << "using WARP for software device\n";'
-                print r'        Software = LoadLibraryA("d3d10warp");'
-                print r'    }'
-
             # Compensate for the fact we don't trace DXGI object creation
             if function.name.startswith('D3D11CreateDevice'):
                 print r'    if (DriverType == D3D_DRIVER_TYPE_UNKNOWN && !pAdapter) {'
@@ -89,52 +81,73 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
                 print r'    }'
 
             if function.name.startswith('D3D10CreateDevice'):
+                # Toggle debugging
+                print r'    Flags &= ~D3D10_CREATE_DEVICE_DEBUG;'
+                print r'    if (retrace::debug) {'
+                print r'        if (LoadLibraryA("d3d10sdklayers")) {'
+                print r'            Flags |= D3D10_CREATE_DEVICE_DEBUG;'
+                print r'        }'
+                print r'    }'
+
+                # Force driver
                 self.forceDriver('D3D10_DRIVER_TYPE')
+
             if function.name.startswith('D3D11CreateDevice'):
+                # Toggle debugging
+                print r'    Flags &= ~D3D11_CREATE_DEVICE_DEBUG;'
+                print r'    if (retrace::debug) {'
+                print r'        if (LoadLibraryA("d3d11sdklayers")) {'
+                print r'            Flags |= D3D11_CREATE_DEVICE_DEBUG;'
+                print r'        }'
+                print r'    }'
+
+                # Force driver
                 self.forceDriver('D3D_DRIVER_TYPE')
 
         Retracer.invokeFunction(self, function)
 
     def forceDriver(self, enum):
-        print r'    switch (retrace::driver) {'
-        print r'    case retrace::DRIVER_HARDWARE:'
-        print r'        DriverType = %s_HARDWARE;' % enum
-        print r'        Software = NULL;'
-        print r'        break;'
-        print r'    case retrace::DRIVER_SOFTWARE:'
-        print r'        pAdapter = NULL;'
-        print r'        DriverType = %s_WARP;' % enum
-        print r'        Software = NULL;'
-        print r'        break;'
-        print r'    case retrace::DRIVER_REFERENCE:'
-        print r'        pAdapter = NULL;'
-        print r'        DriverType = %s_REFERENCE;' % enum
-        print r'        Software = NULL;'
-        print r'        break;'
-        print r'    case retrace::DRIVER_NULL:'
-        print r'        pAdapter = NULL;'
-        print r'        DriverType = %s_NULL;' % enum
-        print r'        Software = NULL;'
-        print r'        break;'
-        print r'    case retrace::DRIVER_MODULE:'
-        print r'        pAdapter = NULL;'
-        print r'        DriverType = %s_SOFTWARE;' % enum
-        print r'        Software = LoadLibraryA(retrace::driverModule);'
-        print r'        if (!Software) {'
-        print r'            retrace::warning(call) << "failed to load " << retrace::driverModule << "\n";'
-        print r'        }'
-        print r'        break;'
-        print r'    default:'
-        print r'        assert(0);'
-        print r'        /* fall-through */'
-        print r'    case retrace::DRIVER_DEFAULT:'
-        print r'        if (DriverType == %s_SOFTWARE) {' % enum
-        print r'            Software = LoadLibraryA("d3d10warp");'
+        # This can only work when pAdapter is NULL. For non-NULL pAdapter we
+        # need to override inside the EnumAdapters call below
+        print r'    if (pAdapter == NULL) {'
+        print r'        switch (retrace::driver) {'
+        print r'        case retrace::DRIVER_HARDWARE:'
+        print r'            DriverType = %s_HARDWARE;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_SOFTWARE:'
+        print r'            DriverType = %s_WARP;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_REFERENCE:'
+        print r'            DriverType = %s_REFERENCE;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_NULL:'
+        print r'            DriverType = %s_NULL;' % enum
+        print r'            Software = NULL;'
+        print r'            break;'
+        print r'        case retrace::DRIVER_MODULE:'
+        print r'            DriverType = %s_SOFTWARE;' % enum
+        print r'            Software = LoadLibraryA(retrace::driverModule);'
         print r'            if (!Software) {'
-        print r'                retrace::warning(call) << "failed to load d3d10warp.dll\n";'
+        print r'                retrace::warning(call) << "failed to load " << retrace::driverModule << "\n";'
         print r'            }'
+        print r'            break;'
+        print r'        default:'
+        print r'            assert(0);'
+        print r'            /* fall-through */'
+        print r'        case retrace::DRIVER_DEFAULT:'
+        print r'            if (DriverType == %s_SOFTWARE) {' % enum
+        print r'                Software = LoadLibraryA("d3d10warp");'
+        print r'                if (!Software) {'
+        print r'                    retrace::warning(call) << "failed to load d3d10warp.dll\n";'
+        print r'                }'
+        print r'            }'
+        print r'            break;'
         print r'        }'
-        print r'        break;'
+        print r'    } else {'
+        print r'        Software = NULL;'
         print r'    }'
 
     def invokeInterfaceMethod(self, interface, method):
@@ -164,6 +177,34 @@ createWindow(DXGI_SWAP_CHAIN_DESC *pSwapChainDesc) {
             print r'        pSharedResource = NULL;'
             print r'    }'
 
+        # Force driver
+        if interface.name.startswith('IDXGIFactory') and method.name == 'EnumAdapters':
+            print r'    const char *szSoftware = NULL;'
+            print r'    switch (retrace::driver) {'
+            print r'    case retrace::DRIVER_REFERENCE:'
+            print r'    case retrace::DRIVER_SOFTWARE:'
+            print r'        szSoftware = "d3d10warp.dll";'
+            print r'        break;'
+            print r'    case retrace::DRIVER_MODULE:'
+            print r'        szSoftware = retrace::driverModule;'
+            print r'        break;'
+            print r'    default:'
+            print r'        break;'
+            print r'    }'
+            print r'    HMODULE hSoftware = NULL;'
+            print r'    if (szSoftware) {'
+            print r'        hSoftware = LoadLibraryA(szSoftware);'
+            print r'        if (!hSoftware) {'
+            print r'            retrace::warning(call) << "failed to load " << szSoftware << "\n";'
+            print r'        }'
+            print r'    }'
+            print r'    if (hSoftware) {'
+            print r'        _result = _this->CreateSoftwareAdapter(hSoftware, ppAdapter);'
+            print r'    } else {'
+            Retracer.invokeInterfaceMethod(self, interface, method)
+            print r'    }'
+            return
+
         Retracer.invokeInterfaceMethod(self, interface, method)
 
         # process events after presents
index 1418ca3d0fcc9bd54326263af35763136dd656c8..d0298fcb74e76e4dc8f99d6ab103ab8f65e5b0e5 100755 (executable)
@@ -43,9 +43,16 @@ namespace glretrace {
 bool insideList = false;
 bool insideGlBeginEnd = 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;
@@ -109,26 +116,24 @@ 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, &timestamp);
+        return timestamp;
     } else {
-        gpuTime = 0;
-    }
-
-    if (retrace::profilingCpuTimes) {
-        cpuTime = os::getTime();
-    } else {
-        cpuTime = 0;
+        return os::getTime();
     }
+}
 
+static inline int64_t
+getTimeFrequency(void) {
     if (retrace::profilingGpuTimes && supportsTimestamp) {
-        glDeleteQueries(1, &query);
+        return 1000000000;
+    } else {
+        return os::timeFrequency;
     }
 }
 
@@ -140,17 +145,16 @@ completeCallQuery(CallQuery& query) {
     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,6 +163,8 @@ completeCallQuery(CallQuery& query) {
         cpuDuration = query.cpuEnd - query.cpuStart;
     }
 
+    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);
 }
@@ -183,20 +189,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 +210,18 @@ 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();
     }
 }
 
 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 */
@@ -276,11 +282,9 @@ 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);
         }
     }
 }
@@ -291,23 +295,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();
     }