summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xCMakeLists.txt17
-rw-r--r--cgltrace.py62
-rw-r--r--cli/cli_dump.cpp11
-rw-r--r--common/formatter.hpp34
-rw-r--r--common/trace_loader.cpp4
-rw-r--r--common/trace_lookup.hpp111
-rw-r--r--common/trace_model.cpp25
-rw-r--r--common/trace_model.hpp87
-rw-r--r--common/trace_parser.cpp48
-rw-r--r--common/trace_parser.hpp15
-rw-r--r--common/trace_parser_flags.cpp128
-rw-r--r--dispatch.py11
-rw-r--r--egltrace.py20
-rw-r--r--glimports.hpp12
-rw-r--r--glproc.py42
-rw-r--r--glproc_egl.cpp100
-rw-r--r--glproc_gl.cpp230
-rw-r--r--glstate.cpp4
-rw-r--r--glws_egl_xlib.cpp25
-rw-r--r--glws_glx.cpp3
-rw-r--r--glws_wgl.cpp6
-rw-r--r--glxtrace.py54
-rw-r--r--gui/apitrace.cpp4
-rw-r--r--gui/apitracecall.cpp6
-rw-r--r--gui/apitracecall.h2
-rw-r--r--wgltrace.py25
26 files changed, 851 insertions, 235 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93ab8d1..710c626 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,15 +40,14 @@ if (ENABLE_GUI)
find_package (QJSON ${REQUIRE_GUI})
endif ()
+include_directories (${OPENGL_INCLUDE_DIR})
+
if (WIN32)
find_package (DirectX)
elseif (APPLE)
else ()
find_package (X11 REQUIRED)
- set (X11_INCLUDE_DIR ${X11_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR})
- set (X11_GL_LIB ${OPENGL_gl_LIBRARY})
-
include_directories (${X11_INCLUDE_DIR})
if (ENABLE_EGL)
@@ -269,6 +268,7 @@ add_library (common STATIC
common/trace_file_snappy.cpp
common/trace_model.cpp
common/trace_parser.cpp
+ common/trace_parser_flags.cpp
common/trace_writer.cpp
common/trace_writer_local.cpp
common/trace_writer_model.cpp
@@ -377,6 +377,7 @@ if (WIN32)
add_library (wgltrace MODULE specs/opengl32.def
wgltrace.cpp
glcaps.cpp
+ glproc_gl.cpp
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
)
set_target_properties (wgltrace PROPERTIES
@@ -398,6 +399,7 @@ elseif (APPLE)
add_library (cgltrace SHARED
cgltrace.cpp
glcaps.cpp
+ glproc_gl.cpp
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
)
@@ -425,6 +427,7 @@ else ()
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
glxtrace.cpp
glcaps.cpp
+ glproc_gl.cpp
)
set_target_properties (glxtrace PROPERTIES
@@ -455,6 +458,7 @@ if (EGL_FOUND)
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
egltrace.cpp
glcaps.cpp
+ glproc_egl.cpp
)
set_property (
@@ -516,6 +520,7 @@ set (retrace_sources
add_executable (glretrace
${retrace_sources}
${glws_os}
+ glproc_gl.cpp
)
set_property (
@@ -529,7 +534,6 @@ target_link_libraries (glretrace
)
if (WIN32)
- target_link_libraries (glretrace ${OPENGL_gl_LIBRARY})
elseif (APPLE)
target_link_libraries (glretrace
"-framework Cocoa"
@@ -537,7 +541,7 @@ elseif (APPLE)
${OPENGL_gl_LIBRARY} # CGL*
)
else ()
- target_link_libraries (glretrace ${OPENGL_gl_LIBRARY} ${X11_X11_LIB})
+ target_link_libraries (glretrace ${X11_X11_LIB})
endif ()
install (TARGETS glretrace RUNTIME DESTINATION bin)
@@ -546,6 +550,7 @@ if (EGL_FOUND AND NOT WIN32 AND NOT APPLE)
add_executable (eglretrace
${retrace_sources}
glws_egl_xlib.cpp
+ glproc_egl.cpp
)
set_property (
@@ -560,8 +565,6 @@ if (EGL_FOUND AND NOT WIN32 AND NOT APPLE)
)
target_link_libraries (eglretrace
- ${EGL_LIBRARIES}
- ${OPENGL_gl_LIBRARY}
${X11_X11_LIB}
)
diff --git a/cgltrace.py b/cgltrace.py
index b6a6fd0..2100723 100644
--- a/cgltrace.py
+++ b/cgltrace.py
@@ -44,12 +44,6 @@ if __name__ == '__main__':
print
print '#include <stdlib.h>'
print '#include <string.h>'
- print '#include <unistd.h>'
- print
- print '#ifndef _GNU_SOURCE'
- print '#define _GNU_SOURCE // for dladdr'
- print '#endif'
- print '#include <dlfcn.h>'
print
print '#include "trace_writer.hpp"'
print
@@ -68,62 +62,6 @@ if __name__ == '__main__':
print r'''
-
-/*
- * Path to the true OpenGL framework
- */
-static const char *libgl_filename = "/System/Library/Frameworks/OpenGL.framework/OpenGL";
-
-
-/*
- * Handle to the true OpenGL framework.
- */
-static void *libgl_handle = NULL;
-
-
-/*
- * Lookup a libGL symbol
- */
-void * __libgl_sym(const char *symbol)
-{
- void *result;
-
- if (!libgl_handle) {
- /*
- * Unfortunately we can't just dlopen the true dynamic library because
- * DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATH take precedence, even for
- * absolute paths. So we create a temporary symlink, and dlopen that
- * instead.
- */
-
- char temp_filename[] = "/tmp/tmp.XXXXXX";
-
- if (mktemp(temp_filename) != NULL) {
- if (symlink(libgl_filename, temp_filename) == 0) {
- libgl_handle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
- remove(temp_filename);
- }
- }
-
- if (!libgl_handle) {
- os::log("apitrace: error: couldn't load %s\n", libgl_filename);
- os::abort();
- return NULL;
- }
- }
-
- result = dlsym(libgl_handle, symbol);
-
- if (result == dlsym(RTLD_SELF, symbol)) {
- os::log("apitrace: error: symbol lookup recursion\n");
- os::abort();
- return NULL;
- }
-
- return result;
-}
-
-
PUBLIC
void * gll_noop = 0;
diff --git a/cli/cli_dump.cpp b/cli/cli_dump.cpp
index 5baa5ae..4a73382 100644
--- a/cli/cli_dump.cpp
+++ b/cli/cli_dump.cpp
@@ -37,6 +37,8 @@ enum ColorOption {
static ColorOption color = COLOR_OPTION_AUTO;
+static bool verbose = false;
+
static const char *synopsis = "Dump given trace(s) to standard output.";
static void
@@ -46,6 +48,7 @@ usage(void)
<< "usage: apitrace dump [OPTIONS] <trace-file>...\n"
<< synopsis << "\n"
"\n"
+ " -v, --verbose verbose output\n"
" --color=<WHEN>\n"
" --colour=<WHEN> Colored syntax highlighting\n"
" WHEN is 'auto', 'always', or 'never'\n";
@@ -68,6 +71,9 @@ command(int argc, char *argv[])
} else if (!strcmp(arg, "--help")) {
usage();
return 0;
+ } else if (strcmp(arg, "-v") == 0 ||
+ strcmp(arg, "--verbose") == 0) {
+ verbose = true;
} else if (!strcmp(arg, "--color=auto") ||
!strcmp(arg, "--colour=auto")) {
color = COLOR_OPTION_AUTO;
@@ -106,7 +112,10 @@ command(int argc, char *argv[])
trace::Call *call;
while ((call = p.parse_call())) {
- call->dump(std::cout, color);
+ if (verbose ||
+ !(call->flags & trace::CALL_FLAG_VERBOSE)) {
+ call->dump(std::cout, color);
+ }
delete call;
}
}
diff --git a/common/formatter.hpp b/common/formatter.hpp
index 61bafde..59f0fea 100644
--- a/common/formatter.hpp
+++ b/common/formatter.hpp
@@ -62,6 +62,7 @@ public:
virtual Attribute *normal(void) const { return new Attribute; }
virtual Attribute *bold(void) const { return new Attribute; }
virtual Attribute *italic(void) const { return new Attribute; }
+ virtual Attribute *strike(void) const { return new Attribute; }
virtual Attribute *color(Color) const { return new Attribute; }
};
@@ -88,6 +89,7 @@ public:
virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); }
virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); }
virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); }
+ virtual Attribute *strike(void) const { return new AnsiAttribute("9m"); }
virtual Attribute *color(Color c) const {
static const char *color_escapes[] = {
"31m", /* red */
@@ -107,8 +109,39 @@ inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) {
#ifdef _WIN32
+
#include <windows.h>
+
+#ifndef COMMON_LVB_LEADING_BYTE
+#define COMMON_LVB_LEADING_BYTE 0x0100
+#endif
+
+#ifndef COMMON_LVB_TRAILING_BYTE
+#define COMMON_LVB_TRAILING_BYTE 0x0200
+#endif
+
+#ifndef COMMON_LVB_GRID_HORIZONTAL
+#define COMMON_LVB_GRID_HORIZONTAL 0x0400
+#endif
+
+#ifndef COMMON_LVB_GRID_LVERTICAL
+#define COMMON_LVB_GRID_LVERTICAL 0x0800
+#endif
+
+#ifndef COMMON_LVB_GRID_RVERTICAL
+#define COMMON_LVB_GRID_RVERTICAL 0x1000
+#endif
+
+#ifndef COMMON_LVB_REVERSE_VIDEO
+#define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
+#ifndef COMMON_LVB_UNDERSCORE
+#define COMMON_LVB_UNDERSCORE 0x8000
+#endif
+
+
class WindowsAttribute : public Attribute {
protected:
WORD wAttributes;
@@ -142,6 +175,7 @@ public:
virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); }
virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
+ virtual Attribute *strike(void) const { return new WindowsAttribute(COMMON_LVB_REVERSE_VIDEO | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
virtual Attribute *color(Color c) const {
static const WORD color_escapes[] = {
FOREGROUND_RED | FOREGROUND_INTENSITY,
diff --git a/common/trace_loader.cpp b/common/trace_loader.cpp
index a4d23d2..e091dce 100644
--- a/common/trace_loader.cpp
+++ b/common/trace_loader.cpp
@@ -95,9 +95,7 @@ bool Loader::isCallAFrameMarker(const trace::Call *call) const
switch (m_frameMarker) {
case FrameMarker_SwapBuffers:
- return name.find("SwapBuffers") != std::string::npos ||
- name == "CGLFlushDrawable" ||
- name == "glFrameTerminatorGREMEDY";
+ return call->flags & trace::CALL_FLAG_END_FRAME;
break;
case FrameMarker_Flush:
return name == "glFlush";
diff --git a/common/trace_lookup.hpp b/common/trace_lookup.hpp
new file mode 100644
index 0000000..7134778
--- /dev/null
+++ b/common/trace_lookup.hpp
@@ -0,0 +1,111 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Helper code for function name indexed lookup tables.
+ */
+
+#ifndef _TRACE_LOOKUP_HPP_
+#define _TRACE_LOOKUP_HPP_
+
+
+#include <assert.h>
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+
+
+namespace trace {
+
+
+/**
+ * Generic type for (name, value) pairs.
+ */
+template< class T >
+struct Entry
+{
+ const char *name;
+ T value;
+};
+
+
+/**
+ * Function object which compare entries by name.
+ */
+template< class T >
+struct EntryCompare {
+ inline bool
+ operator() (const Entry<T> & a, const Entry<T> & b) const {
+ return strcmp(a.name, b.name) < 0;
+ }
+};
+
+
+/**
+ * Lookup the entry with the given name, .
+ *
+ * The entry table must be sorted alphabetically (the same rules used by
+ * strcmp).
+ */
+template< class T, std::size_t n >
+inline const T &
+entryLookup(const char *name, const Entry<T> (& entries)[n], const T & default_)
+{
+ typedef const Entry<T> * ConstIterator;
+
+ ConstIterator first = &entries[0];
+ ConstIterator last = &entries[n];
+
+ assert(first != last);
+
+ Entry<T> reference;
+ reference.name = name;
+
+ EntryCompare<T> compare;
+
+#ifndef NDEBUG
+ for (ConstIterator it = first; it != last; ++it) {
+ ConstIterator next = it + 1;
+ if (next != last && !compare(*it, *next)) {
+ std::cerr << "error: " << it->name << " and " << next->name << " not properly sorted\n";
+ assert(0);
+ }
+ }
+#endif
+
+ first = std::lower_bound(first, last, reference, compare);
+
+ if (first == last || compare(reference, *first)) {
+ return default_;
+ }
+
+ return first->value;
+}
+
+
+} /* namespace trace */
+
+#endif /* _TRACE_LOOKUP_HPP_ */
diff --git a/common/trace_model.cpp b/common/trace_model.cpp
index 2a381ed..5c6b145 100644
--- a/common/trace_model.cpp
+++ b/common/trace_model.cpp
@@ -196,6 +196,7 @@ protected:
formatter::Attribute *normal;
formatter::Attribute *bold;
formatter::Attribute *italic;
+ formatter::Attribute *strike;
formatter::Attribute *red;
formatter::Attribute *pointer;
formatter::Attribute *literal;
@@ -206,6 +207,7 @@ public:
normal = formatter->normal();
bold = formatter->bold();
italic = formatter->italic();
+ strike = formatter->strike();
red = formatter->color(formatter::RED);
pointer = formatter->color(formatter::GREEN);
literal = formatter->color(formatter::BLUE);
@@ -341,8 +343,19 @@ public:
}
void visit(Call *call) {
+ CallFlags flags = call->flags;
+
+ if (flags & CALL_FLAG_NON_REPRODUCIBLE) {
+ os << strike;
+ } else if (flags & (CALL_FLAG_FAKE | CALL_FLAG_NO_SIDE_EFFECTS)) {
+ os << normal;
+ } else {
+ os << bold;
+ }
+ os << call->sig->name << normal;
+
+ os << "(";
const char *sep = "";
- os << bold << call->sig->name << normal << "(";
for (unsigned i = 0; i < call->args.size(); ++i) {
os << sep << italic << call->sig->arg_names[i] << normal << " = ";
if (call->args[i]) {
@@ -353,11 +366,21 @@ public:
sep = ", ";
}
os << ")";
+
if (call->ret) {
os << " = ";
_visit(call->ret);
}
+
+ if (flags & CALL_FLAG_INCOMPLETE) {
+ os << " // " << red << "incomplete" << normal;
+ }
+
os << "\n";
+
+ if (flags & CALL_FLAG_END_FRAME) {
+ os << "\n";
+ }
}
};
diff --git a/common/trace_model.hpp b/common/trace_model.hpp
index 61ff4a6..f208032 100644
--- a/common/trace_model.hpp
+++ b/common/trace_model.hpp
@@ -339,6 +339,83 @@ inline std::ostream & operator <<(std::ostream &os, Value *value) {
}
+typedef unsigned CallFlags;
+
+/**
+ * Call flags.
+ *
+ * TODO: It might be better to to record some of these (but not all) into the
+ * trace file.
+ */
+enum {
+
+ /**
+ * Whether a call was really done by the application or not.
+ *
+ * This flag is set for fake calls -- calls not truly done by the application
+ * but emitted and recorded for completeness, to provide contextual information
+ * necessary for retracing, that would not be available through other ways.
+ *
+ * XXX: This one definetely needs to go into the trace file.
+ */
+ CALL_FLAG_FAKE = (1 << 0),
+
+ /**
+ * Whether this call should be retraced or ignored.
+ *
+ * This flag is set for calls which can't be safely replayed (due to incomplete
+ * information) or that have no sideffects.
+ *
+ * Some incomplete calls are unreproduceable, but not all.
+ */
+ CALL_FLAG_NON_REPRODUCIBLE = (1 << 1),
+
+ /**
+ * Whether this call has no side-effects, therefore don't need to be
+ * retraced.
+ *
+ * This flag is set for calls that merely query information which is not
+ * needed for posterior calls.
+ */
+ CALL_FLAG_NO_SIDE_EFFECTS = (1 << 2),
+
+ /**
+ * Whether this call renders into the bound rendertargets.
+ */
+ CALL_FLAG_RENDER = (1 << 3),
+
+ /**
+ * Whether this call causes render target to be swapped.
+ *
+ * This does not mark frame termination by itself -- that's solely the
+ * responsibility of `endOfFrame` bit.
+ *
+ * This mean that snapshots should be take prior to the call, and not
+ * after.
+ */
+ CALL_FLAG_SWAP_RENDERTARGET = (1 << 4),
+
+ /**
+ * Whether this call terminates a frame.
+ *
+ * XXX: This can't always be determined by the function name, so it should also
+ * go into the trace file eventually.
+ */
+ CALL_FLAG_END_FRAME = (1 << 5),
+
+ /**
+ * Whether this call is incomplete, i.e., it never returned.
+ */
+ CALL_FLAG_INCOMPLETE = (1 << 6),
+
+ /**
+ * Whether this call is verbose (i.e., not usually interesting).
+ */
+ CALL_FLAG_VERBOSE = (1 << 7),
+};
+
+
+
class Call
{
public:
@@ -347,7 +424,15 @@ public:
std::vector<Value *> args;
Value *ret;
- Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
+ CallFlags flags;
+
+ Call(FunctionSig *_sig, const CallFlags &_flags) :
+ sig(_sig),
+ args(_sig->num_args),
+ ret(0),
+ flags(_flags) {
+ }
+
~Call();
inline const char * name(void) const {
diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp
index aabf388..1a1139d 100644
--- a/common/trace_parser.cpp
+++ b/common/trace_parser.cpp
@@ -27,6 +27,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "trace_file.hpp"
#include "trace_parser.hpp"
@@ -42,6 +43,8 @@ Parser::Parser() {
file = NULL;
next_call_no = 0;
version = 0;
+
+ glGetErrorSig = NULL;
}
@@ -164,21 +167,25 @@ void Parser::setBookmark(const ParseBookmark &bookmark) {
Call *Parser::parse_call(Mode mode) {
do {
+ Call *call;
int c = read_byte();
switch (c) {
case trace::EVENT_ENTER:
parse_enter(mode);
break;
case trace::EVENT_LEAVE:
- return parse_leave(mode);
+ call = parse_leave(mode);
+ adjust_call_flags(call);
+ return call;
default:
std::cerr << "error: unknown event " << c << "\n";
exit(1);
case -1:
if (!calls.empty()) {
- Call *call = calls.front();
- std::cerr << call->no << ": warning: incomplete call " << call->name() << "\n";
+ call = calls.front();
+ call->flags |= CALL_FLAG_INCOMPLETE;
calls.pop_front();
+ adjust_call_flags(call);
return call;
}
return NULL;
@@ -201,7 +208,8 @@ T *lookup(std::vector<T *> &map, size_t index) {
}
-FunctionSig *Parser::parse_function_sig(void) {
+Parser::FunctionSigFlags *
+Parser::parse_function_sig(void) {
size_t id = read_uint();
FunctionSigState *sig = lookup(functions, id);
@@ -217,8 +225,21 @@ FunctionSig *Parser::parse_function_sig(void) {
arg_names[i] = read_string();
}
sig->arg_names = arg_names;
+ sig->flags = lookupCallFlags(sig->name);
sig->offset = file->currentOffset();
functions[id] = sig;
+
+ /**
+ * Note down the signature of special functions for future reference.
+ *
+ * NOTE: If the number of comparisons increases we should move this to a
+ * separate function and use bisection.
+ */
+ if (sig->num_args == 0 &&
+ strcmp(sig->name, "glGetError") == 0) {
+ glGetErrorSig = sig;
+ }
+
} else if (file->currentOffset() < sig->offset) {
/* skip over the signature */
skip_string(); /* name */
@@ -327,9 +348,9 @@ BitmaskSig *Parser::parse_bitmask_sig() {
void Parser::parse_enter(Mode mode) {
- FunctionSig *sig = parse_function_sig();
+ FunctionSigFlags *sig = parse_function_sig();
- Call *call = new Call(sig);
+ Call *call = new Call(sig, sig->flags);
call->no = next_call_no++;
@@ -387,6 +408,21 @@ bool Parser::parse_call_details(Call *call, Mode mode) {
}
+/**
+ * Make adjustments to this particular call flags.
+ *
+ * NOTE: This is called per-call so no string comparisons should be done here.
+ * All name comparisons should be done when the signature is parsed instead.
+ */
+void Parser::adjust_call_flags(Call *call) {
+ // Mark glGetError() = GL_NO_ERROR as verbose
+ if (call->sig == glGetErrorSig &&
+ call->ret &&
+ call->ret->toSInt() == 0) {
+ call->flags |= CALL_FLAG_VERBOSE;
+ }
+}
+
void Parser::parse_arg(Call *call, Mode mode) {
unsigned index = read_uint();
Value *value = parse_value(mode);
diff --git a/common/trace_parser.hpp b/common/trace_parser.hpp
index 8b071f5..73bb776 100644
--- a/common/trace_parser.hpp
+++ b/common/trace_parser.hpp
@@ -59,6 +59,10 @@ protected:
typedef std::list<Call *> CallList;
CallList calls;
+ struct FunctionSigFlags : public FunctionSig {
+ CallFlags flags;
+ };
+
// Helper template that extends a base signature structure, with additional
// parsing information.
template< class T >
@@ -69,7 +73,7 @@ protected:
File::Offset offset;
};
- typedef SigState<FunctionSig> FunctionSigState;
+ typedef SigState<FunctionSigFlags> FunctionSigState;
typedef SigState<StructSig> StructSigState;
typedef SigState<EnumSig> EnumSigState;
typedef SigState<BitmaskSig> BitmaskSigState;
@@ -84,6 +88,8 @@ protected:
EnumMap enums;
BitmaskMap bitmasks;
+ FunctionSig *glGetErrorSig;
+
unsigned next_call_no;
public:
@@ -122,11 +128,14 @@ public:
protected:
Call *parse_call(Mode mode);
- FunctionSig *parse_function_sig(void);
+ FunctionSigFlags *parse_function_sig(void);
StructSig *parse_struct_sig();
EnumSig *parse_enum_sig();
BitmaskSig *parse_bitmask_sig();
+ static CallFlags
+ lookupCallFlags(const char *name);
+
Call *parse_Call(Mode mode);
void parse_enter(Mode mode);
@@ -135,6 +144,8 @@ protected:
bool parse_call_details(Call *call, Mode mode);
+ void adjust_call_flags(Call *call);
+
void parse_arg(Call *call, Mode mode);
Value *parse_value(void);
diff --git a/common/trace_parser_flags.cpp b/common/trace_parser_flags.cpp
new file mode 100644
index 0000000..3e0286f
--- /dev/null
+++ b/common/trace_parser_flags.cpp
@@ -0,0 +1,128 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+/**
+ * Label functions based on their name.
+ */
+
+
+#include "trace_lookup.hpp"
+#include "trace_parser.hpp"
+
+
+using namespace trace;
+
+
+/**
+ * Shortcut for SwapBuffers, which terminate and swap bound render buffer.
+ */
+#define CALL_FLAG_SWAPBUFFERS (CALL_FLAG_END_FRAME | CALL_FLAG_SWAP_RENDERTARGET)
+
+
+
+/**
+ * Default call flags.
+ */
+const CallFlags
+defaultCallFlags = 0;
+
+
+/**
+ * Call flags lookup table.
+ */
+const Entry<CallFlags>
+callFlagTable[] = {
+ { "CGLFlushDrawable", CALL_FLAG_END_FRAME },
+ { "eglGetProcAddress", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "eglQueryString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "eglSwapBuffers", CALL_FLAG_SWAPBUFFERS },
+ { "glFrameTerminatorGREMEDY", CALL_FLAG_END_FRAME },
+ { "glGetError", CALL_FLAG_NO_SIDE_EFFECTS }, // verbose will be set later for GL_NO_ERROR
+ { "glGetString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glGetStringi", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsAsyncMarkerSGIX", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsBuffer", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsBufferARB", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsBufferResidentNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsEnabled", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsEnabledIndexedEXT", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsEnabledi", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsFenceAPPLE", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsFenceNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsFramebuffer", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsFramebufferEXT", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsList", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsNameAMD", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsNamedBufferResidentNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsNamedStringARB", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsObjectBufferATI", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsOcclusionQueryNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsProgram", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsProgramARB", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsProgramNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsProgramPipeline", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsQuery", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsQueryARB", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsRenderbuffer", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsRenderbufferEXT", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsSampler", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsShader", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsSync", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsTexture", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsTextureEXT", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsTransformFeedback", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsTransformFeedbackNV", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsVariantEnabledEXT", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsVertexArray", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsVertexArrayAPPLE", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glIsVertexAttribEnabledAPPLE", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetClientString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetCurrentContext", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetCurrentDisplay", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetCurrentDrawable", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetProcAddress", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXGetProcAddressARB", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXIsDirect", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXQueryExtension", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXQueryExtensionsString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXQueryVersion", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "glXSwapBuffers", CALL_FLAG_SWAPBUFFERS },
+ { "wglGetDefaultProcAddress", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "wglGetProcAddress", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE },
+ { "wglSwapBuffers", CALL_FLAG_SWAPBUFFERS },
+ { "wglSwapLayerBuffers", CALL_FLAG_SWAPBUFFERS },
+ { "wglSwapMultipleBuffers", CALL_FLAG_SWAPBUFFERS },
+ // NOTE: New entries must be sorted alphabetically
+};
+
+
+/**
+ * Lookup call flags by name.
+ */
+CallFlags
+Parser::lookupCallFlags(const char *name) {
+ return entryLookup(name, callFlagTable, defaultCallFlags);
+}
diff --git a/dispatch.py b/dispatch.py
index a2f23e9..adb16b7 100644
--- a/dispatch.py
+++ b/dispatch.py
@@ -61,17 +61,11 @@ class Dispatcher:
# functions
print '#ifdef RETRACE'
for function in api.functions:
- if self.is_public_function(function):
- print '#define __%s %s' % (function.name, function.name)
- else:
- print '#define %s __%s' % (function.name, function.name)
+ print '#define %s __%s' % (function.name, function.name)
print '#endif /* RETRACE */'
print
def dispatch_function(self, function):
- if self.is_public_function(function):
- print '#ifndef RETRACE'
- print
ptype = function_pointer_type(function)
pvalue = function_pointer_value(function)
print 'typedef ' + function.prototype('* %s' % ptype) + ';'
@@ -87,9 +81,6 @@ class Dispatcher:
print ' %s%s(%s);' % (ret, pvalue, ', '.join([str(arg.name) for arg in function.args]))
print '}'
print
- if self.is_public_function(function):
- print '#endif /* !RETRACE */'
- print
def is_public_function(self, function):
return True
diff --git a/egltrace.py b/egltrace.py
index 1148924..de90799 100644
--- a/egltrace.py
+++ b/egltrace.py
@@ -110,23 +110,3 @@ if __name__ == '__main__':
print ' return procPtr;'
print '}'
print
- print r'''
-
-/*
- * Lookup a EGL or GLES symbol
- */
-void * __libegl_sym(const char *symbol)
-{
- void *proc;
-
- /* Always try dlsym before eglGetProcAddress as spec 3.10 says
- * implementation may choose to also export extension functions
- * publicly.
- */
- proc = dlsym(RTLD_NEXT, symbol);
- if (!proc && symbol[0] == 'g' && symbol[1] == 'l')
- proc = (void *) __eglGetProcAddress(symbol);
-
- return proc;
-}
-'''
diff --git a/glimports.hpp b/glimports.hpp
index d0dc0da..65b0aca 100644
--- a/glimports.hpp
+++ b/glimports.hpp
@@ -34,13 +34,19 @@
// Prevent including system's glext.h
#define __glext_h_
+
// Some functions take GLenum disguised as GLint. Apple noticed and fixed it
// in the Mac OS X 10.6.x gl.h headers. Regardless, C++ typechecking rules
// force the wrappers to match the prototype precisely.
-#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_7)
-#define GLenum_int GLenum
+#if defined(__APPLE__)
+# include <AvailabilityMacros.h> // for MAC_OS_X_VERSION_10_7
+# if defined(MAC_OS_X_VERSION_10_7)
+# define GLenum_int GLint
+# else
+# define GLenum_int GLenum
+# endif
#else
-#define GLenum_int GLint
+# define GLenum_int GLint
#endif
diff --git a/glproc.py b/glproc.py
index 67079e4..26df9df 100644
--- a/glproc.py
+++ b/glproc.py
@@ -492,38 +492,16 @@ public_symbols.update([
class GlDispatcher(Dispatcher):
def header(self):
- print '#ifdef RETRACE'
- print '# if defined(TRACE_EGL)'
- print '# define __getPrivateProcAddress(name) eglGetProcAddress(name)'
- print '# elif defined(_WIN32)'
- print '# define __getPrivateProcAddress(name) wglGetProcAddress(name)'
- print '# elif defined(__APPLE__)'
- print '# include <dlfcn.h>'
- print '# define __getPrivateProcAddress(name) dlsym(RTLD_DEFAULT, name)'
- print '# else'
- print '# define __getPrivateProcAddress(name) glXGetProcAddressARB((const GLubyte *)(name))'
- print '# endif'
- print '#else /* !RETRACE */'
- print '# if defined(TRACE_EGL)'
- print '# define __getPublicProcAddress(name) __libegl_sym(name)'
- print '# define __getPrivateProcAddress(name) __libegl_sym(name)'
- print ' void * __libegl_sym(const char *symbol);'
- print '# elif defined(_WIN32)'
- print ' PROC __getPublicProcAddress(LPCSTR lpProcName);'
- print '# define __getPrivateProcAddress(name) __wglGetProcAddress(name)'
- print ' static inline PROC __stdcall __wglGetProcAddress(const char * lpszProc);'
- print '# else'
- print '# define __getPublicProcAddress(name) __libgl_sym(name)'
- print ' void * __libgl_sym(const char *symbol);'
- print '# ifdef __APPLE__'
- print '# define __getPrivateProcAddress(name) __getPublicProcAddress(name)'
- print '# else'
- print '# define __getPrivateProcAddress(name) __glXGetProcAddressARB((const GLubyte *)(name))'
- print ' static inline __GLXextFuncPtr __glXGetProcAddressARB(const GLubyte * procName);'
- print '# endif'
- print '# endif'
- print '#endif /* !RETRACE */'
- print
+ print '''
+#if defined(_WIN32)
+extern HINSTANCE __libGlHandle;
+#else
+extern void * __libGlHandle;
+#endif
+
+void * __getPublicProcAddress(const char *procName);
+void * __getPrivateProcAddress(const char *procName);
+'''
def is_public_function(self, function):
return function.name in public_symbols or function.name.startswith('CGL')
diff --git a/glproc_egl.cpp b/glproc_egl.cpp
new file mode 100644
index 0000000..4ceb2ff
--- /dev/null
+++ b/glproc_egl.cpp
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glproc.hpp"
+
+
+#if !defined(_WIN32)
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE // for dladdr
+#endif
+#include <dlfcn.h>
+#endif
+
+
+/*
+ * Handle to the true OpenGL library.
+ */
+#if defined(_WIN32)
+HINSTANCE __libGlHandle = NULL;
+#else
+void *__libGlHandle = NULL;
+#endif
+
+
+
+#if defined(_WIN32)
+
+#error Unsupported
+
+#elif defined(__APPLE__)
+
+#error Unsupported
+
+#else
+
+/*
+ * Lookup a public EGL/GL/GLES symbol
+ *
+ * The spec states that eglGetProcAddress should only be used for non-core
+ * (extensions) entry-points. Core entry-points should be taken directly from
+ * the API specific libraries.
+ *
+ * We cannot tell here which API a symbol is meant for here (as some are
+ * exported by many). So this code assumes that the appropriate shared
+ * libraries have been loaded previously (either dlopened with RTLD_GLOBAL, or
+ * as part of the executable dependencies), and that their symbols available
+ * for quering via dlsym(RTLD_NEXT, ...).
+ */
+void *
+__getPublicProcAddress(const char *procName)
+{
+ return dlsym(RTLD_NEXT, procName);
+}
+
+/*
+ * Lookup a private EGL/GL/GLES symbol
+ *
+ * Private symbols should always be available through eglGetProcAddress, and
+ * they are guaranteed to work with any context bound (regardless of the API).
+ *
+ * However, per issue#57, eglGetProcAddress returns garbage on some
+ * implementations, and the spec states that implementations may choose to also
+ * export extension functions publicly, so we always attempt dlsym before
+ * eglGetProcAddress to mitigate that.
+ */
+void *
+__getPrivateProcAddress(const char *procName)
+{
+ void *proc;
+ proc = dlsym(RTLD_NEXT, procName);
+ if (!proc && procName[0] == 'g' && procName[1] == 'l')
+ proc = (void *) __eglGetProcAddress(procName);
+
+ return proc;
+}
+
+#endif
diff --git a/glproc_gl.cpp b/glproc_gl.cpp
new file mode 100644
index 0000000..d032e8b
--- /dev/null
+++ b/glproc_gl.cpp
@@ -0,0 +1,230 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glproc.hpp"
+
+
+#if !defined(_WIN32)
+#include <unistd.h> // for symlink
+#include <dlfcn.h>
+#endif
+
+
+/*
+ * Handle to the true OpenGL library.
+ */
+#if defined(_WIN32)
+HINSTANCE __libGlHandle = NULL;
+#else
+void *__libGlHandle = NULL;
+#endif
+
+
+
+#if defined(_WIN32)
+
+void *
+__getPublicProcAddress(const char *procName)
+{
+ if (!__libGlHandle) {
+ char szDll[MAX_PATH] = {0};
+
+ if (!GetSystemDirectoryA(szDll, MAX_PATH)) {
+ return NULL;
+ }
+
+ strcat(szDll, "\\\\opengl32.dll");
+
+ __libGlHandle = LoadLibraryA(szDll);
+ if (!__libGlHandle) {
+ os::log("apitrace: error: couldn't load %s\n", szDll);
+ return NULL;
+ }
+ }
+
+ return (void *)GetProcAddress(__libGlHandle, procName);
+}
+
+
+void *
+__getPrivateProcAddress(const char *procName) {
+ return (void *)__wglGetProcAddress(procName);
+}
+
+
+#elif defined(__APPLE__)
+
+
+/*
+ * Path to the true OpenGL framework
+ */
+static const char *libgl_filename = "/System/Library/Frameworks/OpenGL.framework/OpenGL";
+
+
+/*
+ * Lookup a libGL symbol
+ */
+void * __libgl_sym(const char *symbol)
+{
+ void *result;
+
+ if (!__libGlHandle) {
+ /*
+ * Unfortunately we can't just dlopen the true dynamic library because
+ * DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATH take precedence, even for
+ * absolute paths. So we create a temporary symlink, and dlopen that
+ * instead.
+ */
+
+ char temp_filename[] = "/tmp/tmp.XXXXXX";
+
+ if (mktemp(temp_filename) != NULL) {
+ if (symlink(libgl_filename, temp_filename) == 0) {
+ __libGlHandle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
+ remove(temp_filename);
+ }
+ }
+
+ if (!__libGlHandle) {
+ os::log("apitrace: error: couldn't load %s\n", libgl_filename);
+ os::abort();
+ return NULL;
+ }
+ }
+
+ result = dlsym(__libGlHandle, symbol);
+
+#ifndef RETRACE
+ if (result == dlsym(RTLD_SELF, symbol)) {
+ os::log("apitrace: error: symbol lookup recursion\n");
+ os::abort();
+ return NULL;
+ }
+#endif
+
+ return result;
+}
+
+
+void *
+__getPublicProcAddress(const char *procName)
+{
+ return __libgl_sym(procName);
+}
+
+void *
+__getPrivateProcAddress(const char *procName)
+{
+ return __libgl_sym(procName);
+}
+
+
+#else
+
+
+/*
+ * Invoke the true dlopen() function.
+ */
+static void *
+__dlopen(const char *filename, int flag)
+{
+ typedef void * (*PFNDLOPEN)(const char *, int);
+ static PFNDLOPEN dlopen_ptr = NULL;
+
+ if (!dlopen_ptr) {
+ dlopen_ptr = (PFNDLOPEN)dlsym(RTLD_NEXT, "dlopen");
+ if (!dlopen_ptr) {
+ os::log("apitrace: error: dlsym(RTLD_NEXT, \"dlopen\") failed\n");
+ return NULL;
+ }
+ }
+
+ return dlopen_ptr(filename, flag);
+}
+
+
+/*
+ * Lookup a libGL symbol
+ */
+void * __libgl_sym(const char *symbol)
+{
+ void *result;
+
+ if (!__libGlHandle) {
+ /*
+ * The app doesn't directly link against libGL.so, nor does it directly
+ * dlopen it. So we have to load it ourselves.
+ */
+
+ const char * libgl_filename = getenv("TRACE_LIBGL");
+
+ if (!libgl_filename) {
+ /*
+ * Try to use whatever libGL.so the library is linked against.
+ */
+
+ result = dlsym(RTLD_NEXT, symbol);
+ if (result) {
+ __libGlHandle = RTLD_NEXT;
+ return result;
+ }
+
+ libgl_filename = "libGL.so.1";
+ }
+
+ /*
+ * It would have been preferable to use RTLD_LOCAL to ensure that the
+ * application can never access libGL.so symbols directly, but this
+ * won't work, given libGL.so often loads a driver specific SO and
+ * exposes symbols to it.
+ */
+
+ __libGlHandle = __dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY);
+ if (!__libGlHandle) {
+ os::log("apitrace: error: couldn't find libGL.so\n");
+ return NULL;
+ }
+ }
+
+ return dlsym(__libGlHandle, symbol);
+}
+
+
+void *
+__getPublicProcAddress(const char *procName)
+{
+ return __libgl_sym(procName);
+}
+
+void *
+__getPrivateProcAddress(const char *procName)
+{
+ return (void *)__glXGetProcAddressARB((const GLubyte *)procName);
+}
+
+
+#endif
+
diff --git a/glstate.cpp b/glstate.cpp
index 6b9c072..329276f 100644
--- a/glstate.cpp
+++ b/glstate.cpp
@@ -738,6 +738,7 @@ getDrawableBounds(GLint *width, GLint *height) {
#else
+#if !TRACE_EGL
Display *display;
Drawable drawable;
Window root;
@@ -760,6 +761,9 @@ getDrawableBounds(GLint *width, GLint *height) {
*width = w;
*height = h;
+#else
+ return false;
+#endif
#endif
diff --git a/glws_egl_xlib.cpp b/glws_egl_xlib.cpp
index 958e951..d127705 100644
--- a/glws_egl_xlib.cpp
+++ b/glws_egl_xlib.cpp
@@ -29,9 +29,10 @@
#include <iostream>
-#include "glws.hpp"
+#include <dlfcn.h>
#include "glproc.hpp"
+#include "glws.hpp"
namespace glws {
@@ -136,7 +137,7 @@ public:
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
EGLConfig config = static_cast<const EglVisual *>(visual)->config;
- surface = eglCreateWindowSurface(eglDisplay, config, window, NULL);
+ surface = eglCreateWindowSurface(eglDisplay, config, (EGLNativeWindowType)window, NULL);
}
void waitForEvent(int type) {
@@ -219,8 +220,23 @@ public:
}
};
+/**
+ * Load the symbols from the specified shared object into global namespace, so
+ * that they can be later found by dlsym(RTLD_NEXT, ...);
+ */
+static void
+load(const char *filename)
+{
+ if (!dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) {
+ std::cerr << "error: unable to open " << filename << "\n";
+ exit(1);
+ }
+}
+
void
init(void) {
+ load("libEGL.so.1");
+
display = XOpenDisplay(NULL);
if (!display) {
std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
@@ -229,7 +245,7 @@ init(void) {
screen = DefaultScreen(display);
- eglDisplay = eglGetDisplay(display);
+ eglDisplay = eglGetDisplay((EGLNativeDisplayType)display);
if (eglDisplay == EGL_NO_DISPLAY) {
std::cerr << "error: unable to get EGL display\n";
XCloseDisplay(display);
@@ -320,12 +336,15 @@ createContext(const Visual *_visual, Context *shareContext, Profile profile)
switch (profile) {
case PROFILE_COMPAT:
+ load("libGL.so.1");
eglBindAPI(EGL_OPENGL_API);
break;
case PROFILE_ES1:
+ load("libGLESv1_CM.so.1");
eglBindAPI(EGL_OPENGL_ES_API);
break;
case PROFILE_ES2:
+ load("libGLESv2.so.2");
eglBindAPI(EGL_OPENGL_ES_API);
attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2);
break;
diff --git a/glws_glx.cpp b/glws_glx.cpp
index 8a0b403..db24b7f 100644
--- a/glws_glx.cpp
+++ b/glws_glx.cpp
@@ -28,9 +28,8 @@
#include <iostream>
-#include "glws.hpp"
-
#include "glproc.hpp"
+#include "glws.hpp"
namespace glws {
diff --git a/glws_wgl.cpp b/glws_wgl.cpp
index 2487eb0..63ce5fe 100644
--- a/glws_wgl.cpp
+++ b/glws_wgl.cpp
@@ -23,7 +23,7 @@
*
**************************************************************************/
-#include "glimports.hpp"
+#include "glproc.hpp"
#include "glws.hpp"
@@ -188,6 +188,10 @@ public:
void
init(void) {
+ /*
+ * OpenGL library must be loaded by the time we call GDI.
+ */
+ __libGlHandle = LoadLibraryA("OPENGL32");
}
void
diff --git a/glxtrace.py b/glxtrace.py
index be577cb..c9e9518 100644
--- a/glxtrace.py
+++ b/glxtrace.py
@@ -95,12 +95,6 @@ if __name__ == '__main__':
/*
- * Handle to the true libGL.so
- */
-static void *libgl_handle = NULL;
-
-
-/*
* Invoke the true dlopen() function.
*/
static void *__dlopen(const char *filename, int flag)
@@ -145,7 +139,7 @@ void * dlopen(const char *filename, int flag)
strcmp(filename, "libGL.so.1") == 0) {
// Use the true libGL.so handle instead of RTLD_NEXT from now on
- libgl_handle = handle;
+ __libGlHandle = handle;
// Get the file path for our shared object, and use it instead
static int dummy = 0xdeedbeef;
@@ -163,51 +157,5 @@ void * dlopen(const char *filename, int flag)
}
-/*
- * Lookup a libGL symbol
- */
-void * __libgl_sym(const char *symbol)
-{
- void *result;
-
- if (!libgl_handle) {
- /*
- * The app doesn't directly link against libGL.so, nor does it directly
- * dlopen it. So we have to load it ourselves.
- */
-
- const char * libgl_filename = getenv("TRACE_LIBGL");
-
- if (!libgl_filename) {
- /*
- * Try to use whatever libGL.so the library is linked against.
- */
-
- result = dlsym(RTLD_NEXT, symbol);
- if (result) {
- libgl_handle = RTLD_NEXT;
- return result;
- }
-
- libgl_filename = "libGL.so.1";
- }
-
- /*
- * It would have been preferable to use RTLD_LOCAL to ensure that the
- * application can never access libGL.so symbols directly, but this
- * won't work, given libGL.so often loads a driver specific SO and
- * exposes symbols to it.
- */
-
- libgl_handle = __dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY);
- if (!libgl_handle) {
- os::log("apitrace: error: couldn't find libGL.so\n");
- return NULL;
- }
- }
-
- return dlsym(libgl_handle, symbol);
-}
-
'''
diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp
index c94688e..5758b07 100644
--- a/gui/apitrace.cpp
+++ b/gui/apitrace.cpp
@@ -82,9 +82,7 @@ bool ApiTrace::isCallAFrameMarker(const ApiTraceCall *call,
switch (marker) {
case FrameMarker_SwapBuffers:
- return call->name().contains(QLatin1String("SwapBuffers")) ||
- call->name() == QLatin1String("CGLFlushDrawable") ||
- call->name() == QLatin1String("glFrameTerminatorGREMEDY");
+ return call->flags() & trace::CALL_FLAG_END_FRAME;
case FrameMarker_Flush:
return call->name() == QLatin1String("glFlush");
case FrameMarker_Finish:
diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp
index d0eb542..bc88c3b 100644
--- a/gui/apitracecall.cpp
+++ b/gui/apitracecall.cpp
@@ -670,6 +670,7 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
}
}
m_argValues.squeeze();
+ m_flags = call->flags;
}
ApiTraceCall::~ApiTraceCall()
@@ -785,6 +786,11 @@ QVariant ApiTraceCall::returnValue() const
return m_returnValue;
}
+trace::CallFlags ApiTraceCall::flags() const
+{
+ return m_flags;
+}
+
QUrl ApiTraceCall::helpUrl() const
{
return m_signature->helpUrl();
diff --git a/gui/apitracecall.h b/gui/apitracecall.h
index f017f5d..784834b 100644
--- a/gui/apitracecall.h
+++ b/gui/apitracecall.h
@@ -253,6 +253,7 @@ public:
QStringList argNames() const;
QVector<QVariant> arguments() const;
QVariant returnValue() const;
+ trace::CallFlags flags() const;
QUrl helpUrl() const;
void setHelpUrl(const QUrl &url);
ApiTraceFrame *parentFrame()const;
@@ -285,6 +286,7 @@ private:
ApiTraceCallSignature *m_signature;
QVector<QVariant> m_argValues;
QVariant m_returnValue;
+ trace::CallFlags m_flags;
ApiTraceFrame *m_parentFrame;
QVector<QVariant> m_editedValues;
diff --git a/wgltrace.py b/wgltrace.py
index cf2cc97..d5a5248 100644
--- a/wgltrace.py
+++ b/wgltrace.py
@@ -69,31 +69,6 @@ if __name__ == '__main__':
print '#include "trace_writer.hpp"'
print '#include "os.hpp"'
print
- print '''
-static HINSTANCE g_hDll = NULL;
-
-PROC
-__getPublicProcAddress(LPCSTR lpProcName)
-{
- if (!g_hDll) {
- char szDll[MAX_PATH] = {0};
-
- if (!GetSystemDirectoryA(szDll, MAX_PATH)) {
- return NULL;
- }
-
- strcat(szDll, "\\\\opengl32.dll");
-
- g_hDll = LoadLibraryA(szDll);
- if (!g_hDll) {
- return NULL;
- }
- }
-
- return GetProcAddress(g_hDll, lpProcName);
-}
-
- '''
print '// To validate our prototypes'
print '#define GL_GLEXT_PROTOTYPES'
print '#define WGL_GLXEXT_PROTOTYPES'