diff options
-rwxr-xr-x | CMakeLists.txt | 17 | ||||
-rw-r--r-- | cgltrace.py | 62 | ||||
-rw-r--r-- | cli/cli_dump.cpp | 11 | ||||
-rw-r--r-- | common/formatter.hpp | 34 | ||||
-rw-r--r-- | common/trace_loader.cpp | 4 | ||||
-rw-r--r-- | common/trace_lookup.hpp | 111 | ||||
-rw-r--r-- | common/trace_model.cpp | 25 | ||||
-rw-r--r-- | common/trace_model.hpp | 87 | ||||
-rw-r--r-- | common/trace_parser.cpp | 48 | ||||
-rw-r--r-- | common/trace_parser.hpp | 15 | ||||
-rw-r--r-- | common/trace_parser_flags.cpp | 128 | ||||
-rw-r--r-- | dispatch.py | 11 | ||||
-rw-r--r-- | egltrace.py | 20 | ||||
-rw-r--r-- | glimports.hpp | 12 | ||||
-rw-r--r-- | glproc.py | 42 | ||||
-rw-r--r-- | glproc_egl.cpp | 100 | ||||
-rw-r--r-- | glproc_gl.cpp | 230 | ||||
-rw-r--r-- | glstate.cpp | 4 | ||||
-rw-r--r-- | glws_egl_xlib.cpp | 25 | ||||
-rw-r--r-- | glws_glx.cpp | 3 | ||||
-rw-r--r-- | glws_wgl.cpp | 6 | ||||
-rw-r--r-- | glxtrace.py | 54 | ||||
-rw-r--r-- | gui/apitrace.cpp | 4 | ||||
-rw-r--r-- | gui/apitracecall.cpp | 6 | ||||
-rw-r--r-- | gui/apitracecall.h | 2 | ||||
-rw-r--r-- | wgltrace.py | 25 |
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 @@ -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' |