summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jose.r.fonseca@gmail.com>2011-11-30 07:04:44 +0000
committerJosé Fonseca <jose.r.fonseca@gmail.com>2011-12-02 14:23:03 +0000
commit340f569e669055e7fb095ba5ff38b34e2a64880f (patch)
tree8b8518bbf45232d812eb6b1bab7b546555054e00
parent937c2451d4c8aa1b433e6f607536065620e76967 (diff)
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.
-rwxr-xr-xCMakeLists.txt1
-rw-r--r--cli/cli_dump.cpp11
-rw-r--r--common/formatter.hpp3
-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--gui/apitrace.cpp4
-rw-r--r--gui/apitracecall.cpp6
-rw-r--r--gui/apitracecall.h2
13 files changed, 428 insertions, 17 deletions
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] <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..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 <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/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;