From: José Fonseca Date: Wed, 30 Nov 2011 07:04:44 +0000 (+0000) Subject: Introduce call flags. X-Git-Url: https://git.cworth.org/git?p=apitrace;a=commitdiff_plain;h=340f569e669055e7fb095ba5ff38b34e2a64880f Introduce call flags. A central place for metainfo such as whether a call terminates a frame or not, etc. No trace format changes yet. Will introduce them later after more careful thought. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ab8d1..29df0cb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,6 +269,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 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] ...\n" << synopsis << "\n" "\n" + " -v, --verbose verbose output\n" " --color=\n" " --colour= 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..1449eda 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 */ @@ -142,6 +144,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 +#include + +#include +#include + + +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 & a, const Entry & 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 (& entries)[n], const T & default_) +{ + typedef const Entry * ConstIterator; + + ConstIterator first = &entries[0]; + ConstIterator last = &entries[n]; + + assert(first != last); + + Entry reference; + reference.name = name; + + EntryCompare 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 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 #include +#include #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 &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 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 FunctionSigState; + typedef SigState FunctionSigState; typedef SigState StructSigState; typedef SigState EnumSigState; typedef SigState 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 +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/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 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 m_argValues; QVariant m_returnValue; + trace::CallFlags m_flags; ApiTraceFrame *m_parentFrame; QVector m_editedValues;