* Whether this call is verbose (i.e., not usually interesting).
*/
CALL_FLAG_VERBOSE = (1 << 7),
+
+ /**
+ * String markers.
+ */
+ CALL_FLAG_MARKER = (1 << 8),
+ CALL_FLAG_MARKER_PUSH = (1 << 9),
+ CALL_FLAG_MARKER_POP = (1 << 10),
};
{ "glMultiModeDrawElementsIBM", CALL_FLAG_RENDER },
{ "glObjectLabel", CALL_FLAG_NO_SIDE_EFFECTS },
{ "glObjectPtrLabel", CALL_FLAG_NO_SIDE_EFFECTS },
- { "glPopDebugGroup", CALL_FLAG_NO_SIDE_EFFECTS },
- { "glPushDebugGroup", CALL_FLAG_NO_SIDE_EFFECTS },
- { "glStringMarkerGREMEDY", CALL_FLAG_NO_SIDE_EFFECTS },
+ { "glPopDebugGroup", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER | CALL_FLAG_MARKER_POP},
+ { "glPushDebugGroup", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER | CALL_FLAG_MARKER_PUSH },
+ { "glStringMarkerGREMEDY", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER },
{ "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 },
connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
connect(m_loader,
- SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
+ SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>, QVector<ApiTraceCall*>,quint64)),
this,
- SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
+ SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,QVector<ApiTraceCall*>,quint64)));
connect(m_loader, SIGNAL(guessedApi(int)),
this, SLOT(guessedApi(int)));
connect(m_loader, SIGNAL(finishedParsing()),
{
const ApiTraceFrame *frame = frameAt(idx);
if (frame) {
- return frame->numChildren();
+ return frame->numTotalCalls();
} else {
return 0;
}
}
void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &topLevelItems,
const QVector<ApiTraceCall*> &calls,
quint64 binaryDataSize)
{
if (!frame->isLoaded()) {
emit beginLoadingFrame(frame, calls.size());
- frame->setCalls(calls, binaryDataSize);
+ frame->setCalls(topLevelItems, calls, binaryDataSize);
emit endLoadingFrame(frame);
m_loadingFrames.remove(frame);
}
for (int frameIdx = 0; frameIdx < m_frames.size(); ++frameIdx) {
const ApiTraceFrame *frame = m_frames[frameIdx];
unsigned numCallsInFrame = frame->isLoaded()
- ? frame->numChildren()
+ ? frame->numTotalCalls()
: frame->numChildrenToLoad();
unsigned firstCall = numCalls;
unsigned endCall = numCalls + numCallsInFrame;
void guessedApi(int api);
void finishedParsing();
void loaderFrameLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &topLevelItems,
const QVector<ApiTraceCall*> &calls,
quint64 binaryDataSize);
void loaderSearchResult(const ApiTrace::SearchRequest &request,
TraceLoader *loader,
const trace::Call *call)
: ApiTraceEvent(ApiTraceEvent::Call),
- m_parentFrame(parentFrame)
+ m_parentFrame(parentFrame),
+ m_parentCall(0)
+{
+ loadData(loader, call);
+}
+
+ApiTraceCall::ApiTraceCall(ApiTraceCall *parentCall,
+ TraceLoader *loader,
+ const trace::Call *call)
+ : ApiTraceEvent(ApiTraceEvent::Call),
+ m_parentFrame(parentCall->parentFrame()),
+ m_parentCall(parentCall)
+{
+ loadData(loader, call);
+}
+
+
+ApiTraceCall::~ApiTraceCall()
+{
+}
+
+
+void
+ApiTraceCall::loadData(TraceLoader *loader,
+ const trace::Call *call)
{
m_index = call->no;
}
}
-ApiTraceCall::~ApiTraceCall()
+ApiTraceCall *
+ApiTraceCall::parentCall() const
+{
+ return m_parentCall;
+}
+
+
+ApiTraceEvent *
+ApiTraceCall::parentEvent() const
+{
+ if (m_parentCall)
+ return m_parentCall;
+ else
+ return m_parentFrame;
+}
+
+QVector<ApiTraceCall*>
+ApiTraceCall::children() const
{
+ return m_children;
}
+void
+ApiTraceCall::addChild(ApiTraceCall *call)
+{
+ m_children.append(call);
+}
+
+
+int
+ApiTraceCall::callIndex(ApiTraceCall *call) const
+{
+ return m_children.indexOf(call);
+}
+
+void
+ApiTraceCall::finishedAddingChildren()
+{
+ m_children.squeeze();
+}
bool ApiTraceCall::hasError() const
{
return m_editedValues;
}
+ApiTraceEvent *
+ApiTraceCall::eventAtRow(int row) const
+{
+ if (row < m_children.count())
+ return m_children.value(row);
+ else
+ return NULL;
+}
+
QVariant ApiTraceCall::returnValue() const
{
return m_returnValue;
int ApiTraceCall::numChildren() const
{
- return 0;
+ return m_children.count();
}
bool ApiTraceCall::contains(const QString &str,
int ApiTraceFrame::numChildren() const
{
- return m_calls.count();
+ return m_children.count();
}
-ApiTrace * ApiTraceFrame::parentTrace() const
+int ApiTraceFrame::numTotalCalls() const
{
- return m_parentTrace;
+ return m_calls.count();
}
-void ApiTraceFrame::addCall(ApiTraceCall *call)
+ApiTrace * ApiTraceFrame::parentTrace() const
{
- m_calls.append(call);
- if (call->hasBinaryData()) {
- QByteArray data =
- call->arguments()[call->binaryDataIndex()].toByteArray();
- m_binaryDataSize += data.size();
- }
+ return m_parentTrace;
}
QVector<ApiTraceCall*> ApiTraceFrame::calls() const
return m_calls;
}
-ApiTraceCall * ApiTraceFrame::call(int idx) const
+ApiTraceEvent * ApiTraceFrame::eventAtRow(int row) const
{
- return m_calls.value(idx);
+ if (row < m_children.count())
+ return m_children.value(row);
+ else
+ return NULL;
}
int ApiTraceFrame::callIndex(ApiTraceCall *call) const
{
- return m_calls.indexOf(call);
+ return m_children.indexOf(call);
}
bool ApiTraceFrame::isEmpty() const
return m_binaryDataSize;
}
-void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
+void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &children,
+ const QVector<ApiTraceCall*> &calls,
quint64 binaryDataSize)
{
+ m_children = children;
m_calls = calls;
m_binaryDataSize = binaryDataSize;
m_loaded = true;
return m_loaded;
}
-void ApiTraceFrame::setLoaded(bool l)
-{
- m_loaded = l;
-}
-
void ApiTraceFrame::setNumChildren(int num)
{
m_callsToLoad = num;
QUrl m_helpUrl;
};
+class ApiTraceCall;
+
class ApiTraceEvent
{
public:
virtual QStaticText staticText() const = 0;
virtual int numChildren() const = 0;
+ virtual int callIndex(ApiTraceCall *call) const = 0;
+ virtual ApiTraceEvent *eventAtRow(int row) const = 0;
QVariantMap stateParameters() const;
ApiTraceState *state() const;
class ApiTraceCall : public ApiTraceEvent
{
public:
+ ApiTraceCall(ApiTraceCall *parentCall, TraceLoader *loader,
+ const trace::Call *tcall);
ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader,
const trace::Call *tcall);
~ApiTraceCall();
ApiTraceFrame *parentFrame()const;
void setParentFrame(ApiTraceFrame *frame);
+ int callIndex(ApiTraceCall *call) const;
+
+ ApiTraceEvent *parentEvent() const;
+ ApiTraceCall *parentCall() const;
+ QVector<ApiTraceCall*> children() const;
+ ApiTraceEvent *eventAtRow(int row) const;
+ void addChild(ApiTraceCall *call);
+ void finishedAddingChildren();
+
bool hasError() const;
QString error() const;
void setError(const QString &msg);
QString backtrace() const;
void setBacktrace(QString backtrace);
+private:
+ void loadData(TraceLoader *loader,
+ const trace::Call *tcall);
private:
int m_index;
ApiTraceCallSignature *m_signature;
QVariant m_returnValue;
trace::CallFlags m_flags;
ApiTraceFrame *m_parentFrame;
+ ApiTraceCall *m_parentCall;
+ QVector<ApiTraceCall*> m_children;
QVector<QVariant> m_editedValues;
void setNumChildren(int num);
int numChildren() const;
int numChildrenToLoad() const;
+ int numTotalCalls() const;
QStaticText staticText() const;
+ ApiTraceEvent *eventAtRow(int row) const;
int callIndex(ApiTraceCall *call) const;
- ApiTraceCall *call(int idx) const;
ApiTraceCall *callWithIndex(int index) const;
- void addCall(ApiTraceCall *call);
QVector<ApiTraceCall*> calls() const;
- void setCalls(const QVector<ApiTraceCall*> &calls,
+ void setCalls(const QVector<ApiTraceCall*> &topLevelCalls,
+ const QVector<ApiTraceCall*> &allCalls,
quint64 binaryDataSize);
ApiTraceCall *findNextCall(ApiTraceCall *from,
int binaryDataSize() const;
bool isLoaded() const;
- void setLoaded(bool l);
void setLastCallIndex(unsigned index);
unsigned lastCallIndex() const;
private:
ApiTrace *m_parentTrace;
quint64 m_binaryDataSize;
+ QVector<ApiTraceCall*> m_children;
QVector<ApiTraceCall*> m_calls;
bool m_loaded;
unsigned m_callsToLoad;
}
int numCalls = frame->isLoaded()
- ? frame->numChildren()
+ ? frame->numTotalCalls()
: frame->numChildrenToLoad();
return tr(htmlTempl)
if ((parent.isValid() && parent.column() != 0) || column != 0)
return QModelIndex();
- ApiTraceEvent *event = item(parent);
- if (event) {
- if (event->type() != ApiTraceEvent::Frame) {
- qDebug()<<"got a valid parent but it's not a frame "<<event->type();
+ //qDebug()<<"At row = "<<row<<", column = "<<column<<", parent "<<parent;
+ ApiTraceEvent *parentEvent = item(parent);
+ if (parentEvent) {
+ ApiTraceEvent *event = parentEvent->eventAtRow(row);
+ if (event) {
+ Q_ASSERT(event->type() == ApiTraceEvent::Call);
+ return createIndex(row, column, event);
+ } else {
return QModelIndex();
}
- ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
- ApiTraceCall *call = frame->call(row);
- if (call)
- return createIndex(row, column, call);
- else
- return QModelIndex();
} else {
ApiTraceFrame *frame = m_trace->frameAt(row);
if (frame)
{
if (parent.isValid()) {
ApiTraceEvent *event = item(parent);
- if (event && event->type() == ApiTraceEvent::Frame) {
+ if (!event)
+ return false;
+ if (event->type() == ApiTraceEvent::Frame) {
ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
return !frame->isEmpty();
- } else
- return false;
+ } else {
+ Q_ASSERT(event->type() == ApiTraceEvent::Call);
+ ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
+ return call->numChildren() != 0;
+ }
} else {
return (rowCount() > 0);
}
return QModelIndex();
ApiTraceEvent *event = item(index);
- if (event && event->type() == ApiTraceEvent::Call) {
+
+ if (event->type() == ApiTraceEvent::Call) {
ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
- Q_ASSERT(call->parentFrame());
- return createIndex(call->parentFrame()->number,
- 0, call->parentFrame());
+
+ if (call->parentCall()) {
+ ApiTraceCall *parentCall = call->parentCall();
+ ApiTraceEvent *topEvent = parentCall->parentEvent();
+ return createIndex(topEvent->callIndex(parentCall), 0, parentCall);
+ } else {
+ Q_ASSERT(call->parentFrame());
+ return createIndex(call->parentFrame()->number,
+ 0, call->parentFrame());
+ }
}
return QModelIndex();
}
return m_trace->numFrames();
ApiTraceEvent *event = item(parent);
- if (!event || event->type() == ApiTraceEvent::Call)
+ if (!event)
return 0;
- ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
- if (frame)
- return frame->numChildren();
-
- return 0;
+ return event->numChildren();
}
int ApiTraceModel::columnCount(const QModelIndex &parent) const
if (event->type() == ApiTraceEvent::Call) {
ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
- ApiTraceFrame *frame = call->parentFrame();
- int row = frame->callIndex(call);
- QModelIndex index = createIndex(row, 0, call);
+ QModelIndex index = indexForCall(call);
emit dataChanged(index, index);
} else if (event->type() == ApiTraceEvent::Frame) {
ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
return QModelIndex();
}
- ApiTraceFrame *frame = call->parentFrame();
- Q_ASSERT(frame);
+ ApiTraceEvent *parentEvent = call->parentEvent();
+ Q_ASSERT(parentEvent);
- int row = frame->callIndex(call);
+ int row = parentEvent->callIndex(call);
if (row < 0) {
qDebug() << "Couldn't find call num "<<call->index()<<" inside parent!";
return QModelIndex();
if (trace->needsSaving())
trace->save();
- ApiTraceFrame *frame = call->parentFrame();
- int row = frame->callIndex(call);
- QModelIndex index = createIndex(row, 0, call);
+ QModelIndex index = indexForCall(call);
emit dataChanged(index, index);
}
imageIndex = tr("_call_%1")
.arg(selectedCall()->index());
} else if (selectedFrame()) {
- ApiTraceCall *firstCall = selectedFrame()->call(0);
+ ApiTraceCall *firstCall =
+ static_cast<ApiTraceCall *>(selectedFrame()->eventAtRow(0));
if (firstCall) {
imageIndex = tr("_frame_%1")
.arg(firstCall->index());
#include "apitrace.h"
#include <QDebug>
#include <QFile>
+#include <QStack>
#define FRAMES_TO_CACHE 100
apiCallFromTraceCall(const trace::Call *call,
const QHash<QString, QUrl> &helpHash,
ApiTraceFrame *frame,
+ ApiTraceCall *parentCall,
TraceLoader *loader)
{
- ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+ ApiTraceCall *apiCall;
+
+ if (parentCall)
+ apiCall = new ApiTraceCall(parentCall, loader, call);
+ else
+ apiCall = new ApiTraceCall(frame, loader, call);
apiCall->setHelpUrl(helpHash.value(apiCall->name()));
QList<ApiTraceFrame*> frames;
ApiTraceFrame *currentFrame = 0;
int frameCount = 0;
- QVector<ApiTraceCall*> calls;
+ QStack<ApiTraceCall*> groups;
+ QVector<ApiTraceCall*> topLevelItems;
+ QVector<ApiTraceCall*> allCalls;
quint64 binaryDataSize = 0;
int lastPercentReport = 0;
++frameCount;
}
ApiTraceCall *apiCall =
- apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
- calls.append(apiCall);
+ apiCallFromTraceCall(call, m_helpHash, currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
+ allCalls.append(apiCall);
+ if (groups.count() == 0) {
+ topLevelItems.append(apiCall);
+ }
+ if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+ groups.push(apiCall);
+ } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+ groups.top()->finishedAddingChildren();
+ groups.pop();
+ }
+ if (!groups.isEmpty()) {
+ groups.top()->addChild(apiCall);
+ }
if (apiCall->hasBinaryData()) {
QByteArray data =
- apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+ apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
binaryDataSize += data.size();
}
if (call->flags & trace::CALL_FLAG_END_FRAME) {
- calls.squeeze();
- currentFrame->setCalls(calls, binaryDataSize);
- calls.clear();
+ allCalls.squeeze();
+ topLevelItems.squeeze();
+ if (topLevelItems.count() == allCalls.count()) {
+ currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+ } else {
+ currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+ }
+ allCalls.clear();
+ groups.clear();
+ topLevelItems.clear();
frames.append(currentFrame);
currentFrame = 0;
binaryDataSize = 0;
// it's just a bunch of Delete calls for every object
// after the last SwapBuffers
if (currentFrame) {
- calls.squeeze();
- currentFrame->setCalls(calls, binaryDataSize);
+ allCalls.squeeze();
+ if (topLevelItems.count() == allCalls.count()) {
+ currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+ } else {
+ currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+ }
frames.append(currentFrame);
currentFrame = 0;
}
* FIXME: do string comparison directly on trace::Call
*/
ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
- 0, this);
+ 0, 0, this);
bool result = apiCall->contains(str, sensitivity);
delete apiCall;
return result;
if (numOfCalls) {
quint64 binaryDataSize = 0;
- QVector<ApiTraceCall*> calls(numOfCalls);
+ QStack<ApiTraceCall*> groups;
+ QVector<ApiTraceCall*> topLevelItems;
+ QVector<ApiTraceCall*> allCalls(numOfCalls);
const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
m_parser.setBookmark(frameBookmark.start);
while ((call = m_parser.parse_call())) {
ApiTraceCall *apiCall =
apiCallFromTraceCall(call, m_helpHash,
- currentFrame, this);
+ currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
Q_ASSERT(apiCall);
Q_ASSERT(parsedCalls < calls.size());
- calls[parsedCalls++] = apiCall;
+ allCalls[parsedCalls++] = apiCall;
+ if (groups.count() == 0) {
+ topLevelItems.append(apiCall);
+ }
+ if (!groups.isEmpty()) {
+ groups.top()->addChild(apiCall);
+ }
+ if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+ groups.push(apiCall);
+ } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+ groups.top()->finishedAddingChildren();
+ groups.pop();
+ }
if (apiCall->hasBinaryData()) {
QByteArray data =
apiCall->arguments()[
// threads cross the frame boundary
Q_ASSERT(parsedCalls <= numOfCalls);
Q_ASSERT(parsedCalls <= calls.size());
- calls.resize(parsedCalls);
- calls.squeeze();
+ allCalls.resize(parsedCalls);
+ allCalls.squeeze();
Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad());
- emit frameContentsLoaded(currentFrame,
- calls, binaryDataSize);
- return calls;
+ if (topLevelItems.count() == allCalls.count()) {
+ emit frameContentsLoaded(currentFrame, allCalls,
+ allCalls, binaryDataSize);
+ } else {
+ emit frameContentsLoaded(currentFrame, topLevelItems,
+ allCalls, binaryDataSize);
+ }
+ return allCalls;
}
}
return QVector<ApiTraceCall*>();
void framesLoaded(const QList<ApiTraceFrame*> &frames);
void frameContentsLoaded(ApiTraceFrame *frame,
+ const QVector<ApiTraceCall*> &topLevelItems,
const QVector<ApiTraceCall*> &calls,
quint64 binaryDataSize);