summaryrefslogtreecommitdiff
path: root/retrace
diff options
context:
space:
mode:
authorMark Janes <mark.a.janes@intel.com>2017-04-24 18:08:50 -0700
committerMark Janes <mark.a.janes@intel.com>2017-06-19 14:04:51 -0700
commit74ecc79877c13dbdf43b7f70aa77b2a594f92a8c (patch)
tree5feb9d186194947592f5dbcb6844c012aed829e6 /retrace
parenta24d7abd1116bc1b0a5d8035bc9459db72ce9d51 (diff)
Batch: display batches sent to hardware
Slight modifications to Mesa enable batch buffer display
Diffstat (limited to 'retrace')
-rw-r--r--retrace/daemon/CMakeLists.txt6
-rw-r--r--retrace/daemon/doc/0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch46
-rw-r--r--retrace/daemon/doc/README.txt10
-rw-r--r--retrace/daemon/glframe_batch.cpp71
-rw-r--r--retrace/daemon/glframe_batch.hpp62
-rw-r--r--retrace/daemon/glframe_retrace.cpp20
-rw-r--r--retrace/daemon/glframe_retrace.hpp3
-rw-r--r--retrace/daemon/glframe_retrace_context.cpp28
-rw-r--r--retrace/daemon/glframe_retrace_context.hpp7
-rw-r--r--retrace/daemon/glframe_retrace_interface.hpp5
-rw-r--r--retrace/daemon/glframe_retrace_skeleton.cpp29
-rw-r--r--retrace/daemon/glframe_retrace_skeleton.hpp4
-rw-r--r--retrace/daemon/glframe_retrace_stub.cpp69
-rw-r--r--retrace/daemon/glframe_retrace_stub.hpp2
-rw-r--r--retrace/daemon/glframe_state.hpp3
-rw-r--r--retrace/daemon/glframe_stderr.cpp16
-rw-r--r--retrace/daemon/glframe_stderr.hpp9
-rw-r--r--retrace/daemon/playback.proto13
-rw-r--r--retrace/daemon/test/retrace_daemon_test.cpp3
-rw-r--r--retrace/daemon/test/retrace_file_transfer_test.cpp5
-rw-r--r--retrace/daemon/test/retrace_metrics_test.cpp3
-rw-r--r--retrace/daemon/ui/CMakeLists.txt2
-rw-r--r--retrace/daemon/ui/glframe_batch_model.cpp94
-rw-r--r--retrace/daemon/ui/glframe_batch_model.hpp77
-rw-r--r--retrace/daemon/ui/glframe_metrics_model.hpp3
-rw-r--r--retrace/daemon/ui/glframe_retrace_model.cpp17
-rw-r--r--retrace/daemon/ui/glframe_retrace_model.hpp9
-rw-r--r--retrace/daemon/ui/main.cpp2
-rw-r--r--retrace/daemon/ui/qml/BatchControl.qml75
-rw-r--r--retrace/daemon/ui/qml/mainwin.qml9
-rw-r--r--retrace/daemon/ui/resources.qrc1
31 files changed, 700 insertions, 3 deletions
diff --git a/retrace/daemon/CMakeLists.txt b/retrace/daemon/CMakeLists.txt
index 2d3a3c33..6f37f0d4 100644
--- a/retrace/daemon/CMakeLists.txt
+++ b/retrace/daemon/CMakeLists.txt
@@ -26,11 +26,12 @@ include_directories (
)
set (RETRACE_LINUX_SOURCE
- glframe_perf_enabled_linux.cpp
+ glframe_batch.cpp
+ glframe_gpu_speed_linux.cpp
glframe_os_linux.cpp
+ glframe_perf_enabled_linux.cpp
glframe_stderr.cpp
glframe_thread_linux.cpp
- glframe_gpu_speed_linux.cpp
)
set (RETRACE_WIN_SOURCE
@@ -47,6 +48,7 @@ endif()
set (RETRACE_SOURCES
${RETRACE_OS_SOURCE}
+ glframe_batch.hpp
glframe_gpu_speed.hpp
glframe_metrics.cpp
glframe_metrics.hpp
diff --git a/retrace/daemon/doc/0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch b/retrace/daemon/doc/0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch
new file mode 100644
index 00000000..8df4d0c3
--- /dev/null
+++ b/retrace/daemon/doc/0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch
@@ -0,0 +1,46 @@
+From 0e4bfd6a5795b86d1f8b91376484de99c8c54c64 Mon Sep 17 00:00:00 2001
+From: Mark Janes <mark.a.janes@intel.com>
+Date: Mon, 24 Apr 2017 09:11:04 -0700
+Subject: [PATCH] i965/batch: unconditionally allocate DEBUG_BATCH hash tables
+
+FrameRetrace instruments DEBUG_BATCH on a per-frame basis, but the
+associated data structure must be created in advance of toggling output.
+---
+ src/intel/common/gen_debug.h | 3 ++-
+ src/mesa/drivers/dri/i965/intel_batchbuffer.c | 4 ++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/intel/common/gen_debug.h b/src/intel/common/gen_debug.h
+index c0b74ea2afe..c1292805aca 100644
+--- a/src/intel/common/gen_debug.h
++++ b/src/intel/common/gen_debug.h
+@@ -39,7 +39,8 @@ extern "C" {
+ * list of debugging flags, as well as some macros for handling them.
+ */
+
+-extern uint64_t INTEL_DEBUG;
++// extern uint64_t INTEL_DEBUG;
++extern uint64_t __attribute__((visibility ("default"))) INTEL_DEBUG;
+
+ #define DEBUG_TEXTURE (1ull << 0)
+ #define DEBUG_STATE (1ull << 1)
+diff --git a/src/mesa/drivers/dri/i965/intel_batchbuffer.c b/src/mesa/drivers/dri/i965/intel_batchbuffer.c
+index 6e4b55cf9ec..edcfe8a19a7 100644
+--- a/src/mesa/drivers/dri/i965/intel_batchbuffer.c
++++ b/src/mesa/drivers/dri/i965/intel_batchbuffer.c
+@@ -81,10 +81,10 @@ intel_batchbuffer_init(struct intel_batchbuffer *batch,
+ batch->exec_objects =
+ malloc(batch->exec_array_size * sizeof(batch->exec_objects[0]));
+
+- if (INTEL_DEBUG & DEBUG_BATCH) {
++ /* if (INTEL_DEBUG & DEBUG_BATCH) { */
+ batch->state_batch_sizes =
+ _mesa_hash_table_create(NULL, uint_key_hash, uint_key_compare);
+- }
++ /* } */
+ }
+
+ static void
+--
+2.11.0
+
diff --git a/retrace/daemon/doc/README.txt b/retrace/daemon/doc/README.txt
new file mode 100644
index 00000000..0d3e5d12
--- /dev/null
+++ b/retrace/daemon/doc/README.txt
@@ -0,0 +1,10 @@
+To enable display of i965 batches for each render, apply the patch in
+this directory to mesa:
+
+0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch
+
+After recompiling Mesa, ensure that LIBGL_DRIVERS_PATH points to the
+directory containing i965_dri.so
+
+This feature is a proof-of-concept.
+
diff --git a/retrace/daemon/glframe_batch.cpp b/retrace/daemon/glframe_batch.cpp
new file mode 100644
index 00000000..42ac9bc8
--- /dev/null
+++ b/retrace/daemon/glframe_batch.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) Intel Corp. 2017. 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 (including the
+// next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+
+// **********************************************************************/
+// * Authors:
+// * Mark Janes <mark.a.janes@intel.com>
+// **********************************************************************/
+
+#include "glframe_batch.hpp"
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sstream>
+
+using glretrace::MesaBatch;
+
+// This class is a proof-of-concept. If it sticks, the path
+// resolution needs to be improved.
+MesaBatch::MesaBatch() : m_debug(NULL) {
+ // TODO(majanes) handle missing path
+ // TODO(majanes) handle colon-separated path
+ const char* driver_path = getenv("LIBGL_DRIVERS_PATH");
+ if (!driver_path)
+ return;
+ std::stringstream p;
+ p << driver_path << "/" << "i965_dri.so";
+ void *lib = dlopen(p.str().c_str(),
+ RTLD_NOW);
+ if (!lib)
+ return;
+ m_debug = reinterpret_cast<uint64_t*>(dlsym(lib, "INTEL_DEBUG"));
+}
+
+bool
+MesaBatch::batchSupported() const {
+ return (m_debug != NULL);
+}
+
+#define DEBUG_BATCH (1ull << 6)
+
+void
+MesaBatch::batchOn() {
+ (*m_debug) |= DEBUG_BATCH;
+}
+
+void
+MesaBatch::batchOff() {
+ (*m_debug) &= ~DEBUG_BATCH;
+}
+
diff --git a/retrace/daemon/glframe_batch.hpp b/retrace/daemon/glframe_batch.hpp
new file mode 100644
index 00000000..8f79f8a3
--- /dev/null
+++ b/retrace/daemon/glframe_batch.hpp
@@ -0,0 +1,62 @@
+// Copyright (C) Intel Corp. 2017. 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 (including the
+// next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+
+// **********************************************************************/
+// * Authors:
+// * Mark Janes <mark.a.janes@intel.com>
+// **********************************************************************/
+
+#ifndef _GLFRAME_BATCH_HPP__
+#define _GLFRAME_BATCH_HPP__
+
+#include <stdint.h>
+
+namespace glretrace {
+
+class BatchControl {
+ public:
+ virtual ~BatchControl() {}
+ virtual bool batchSupported() const = 0;
+ virtual void batchOn() = 0;
+ virtual void batchOff() = 0;
+};
+
+class WinBatch : public BatchControl {
+ public:
+ bool batchSupported() const { return false; }
+ void batchOn() {}
+ void batchOff() {}
+};
+
+class MesaBatch : public BatchControl {
+ public:
+ MesaBatch();
+ bool batchSupported() const;
+ void batchOn();
+ void batchOff();
+ private:
+ uint64_t *m_debug;
+};
+
+} // namespace glretrace
+
+#endif // _GLFRAME_BATCH_HPP__
diff --git a/retrace/daemon/glframe_retrace.cpp b/retrace/daemon/glframe_retrace.cpp
index da421c93..edcbc44b 100644
--- a/retrace/daemon/glframe_retrace.cpp
+++ b/retrace/daemon/glframe_retrace.cpp
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include "glframe_batch.hpp"
#include "glframe_glhelper.hpp"
#include "glframe_gpu_speed.hpp"
#include "glframe_logger.hpp"
@@ -57,6 +58,7 @@ using glretrace::ExperimentId;
using glretrace::FrameRetrace;
using glretrace::FrameState;
using glretrace::GlFunctions;
+using glretrace::MesaBatch;
using glretrace::MetricId;
using glretrace::MetricSeries;
using glretrace::NoRedirect;
@@ -71,6 +73,7 @@ using glretrace::ShaderAssembly;
using glretrace::StateTrack;
using glretrace::StdErrRedirect;
using glretrace::WARN;
+using glretrace::WinBatch;
using image::Image;
using retrace::parser;
using trace::Call;
@@ -80,8 +83,10 @@ extern retrace::Retracer retracer;
#ifdef WIN32
static WinShaders assemblyOutput;
+static WinBatch batchControl;
#else
static StdErrRedirect assemblyOutput;
+static MesaBatch batchControl;
#endif
FrameRetrace::FrameRetrace()
@@ -320,6 +325,21 @@ FrameRetrace::replaceShaders(RenderId renderId,
void
FrameRetrace::retraceApi(const RenderSelection &selection,
OnFrameRetrace *callback) {
+ // reset to beginning of frame
+ parser->setBookmark(frame_start.start);
for (auto i : m_contexts)
i->retraceApi(selection, callback);
}
+
+void
+FrameRetrace::retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback) {
+ // reset to beginning of frame
+ parser->setBookmark(frame_start.start);
+ if (!batchControl.batchSupported())
+ return;
+ for (auto i : m_contexts)
+ i->retraceBatch(selection, m_tracker, &batchControl,
+ &assemblyOutput, callback);
+ batchControl.batchOff();
+}
diff --git a/retrace/daemon/glframe_retrace.hpp b/retrace/daemon/glframe_retrace.hpp
index 6f5dd9f1..c42b4857 100644
--- a/retrace/daemon/glframe_retrace.hpp
+++ b/retrace/daemon/glframe_retrace.hpp
@@ -100,6 +100,9 @@ class FrameRetrace : public IFrameRetrace {
void retraceApi(const RenderSelection &selection,
OnFrameRetrace *callback);
+ void retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback);
+
private:
// these are global
// trace::Parser parser;
diff --git a/retrace/daemon/glframe_retrace_context.cpp b/retrace/daemon/glframe_retrace_context.cpp
index 0fc02e5e..6b0ae2a5 100644
--- a/retrace/daemon/glframe_retrace_context.cpp
+++ b/retrace/daemon/glframe_retrace_context.cpp
@@ -32,6 +32,7 @@
#include <vector>
#include "trace_model.hpp"
+#include "glframe_batch.hpp"
#include "glframe_glhelper.hpp"
#include "glretrace.hpp"
#include "glframe_logger.hpp"
@@ -39,6 +40,7 @@
#include "glframe_retrace_render.hpp"
#include "glstate.hpp"
+using glretrace::OutputPoller;
using glretrace::RenderId;
using glretrace::RenderSelection;
using glretrace::RetraceContext;
@@ -395,3 +397,29 @@ RetraceContext::retraceShaderAssembly(const RenderSelection &selection,
}
}
}
+
+void
+RetraceContext::retraceBatch(const RenderSelection &selection,
+ const StateTrack &tracker,
+ BatchControl *control,
+ OutputPoller *poller,
+ OnFrameRetrace *callback) {
+ trace::ParseBookmark bm;
+ m_parser->getBookmark(bm);
+ assert(bm.offset == m_start_bookmark.offset);
+
+ for (auto r : m_renders) {
+ if (isSelected(r.first, selection)) {
+ GlFunctions::Finish();
+ control->batchOn();
+ } else {
+ control->batchOff();
+ }
+ r.second->retrace(tracker);
+ if (isSelected(r.first, selection)) {
+ GlFunctions::Finish();
+ poller->pollBatch(selection.id, r.first, callback);
+ }
+ }
+ control->batchOff();
+}
diff --git a/retrace/daemon/glframe_retrace_context.hpp b/retrace/daemon/glframe_retrace_context.hpp
index b5c056c0..ccbcb41f 100644
--- a/retrace/daemon/glframe_retrace_context.hpp
+++ b/retrace/daemon/glframe_retrace_context.hpp
@@ -48,10 +48,12 @@ namespace glretrace {
struct Context;
+class BatchControl;
class StateTrack;
class OnFrameRetrace;
class ExperimentId;
class MetricId;
+class OutputPoller;
class PerfMetrics;
class RetraceRender;
@@ -88,6 +90,11 @@ class RetraceContext {
StateTrack *tracker,
OnFrameRetrace *callback);
int getRenderCount() const;
+ void retraceBatch(const RenderSelection &selection,
+ const StateTrack &tracker,
+ BatchControl *control,
+ OutputPoller *poller,
+ OnFrameRetrace *callback);
private:
trace::AbstractParser *m_parser;
diff --git a/retrace/daemon/glframe_retrace_interface.hpp b/retrace/daemon/glframe_retrace_interface.hpp
index 0a20dc09..7b169256 100644
--- a/retrace/daemon/glframe_retrace_interface.hpp
+++ b/retrace/daemon/glframe_retrace_interface.hpp
@@ -240,6 +240,9 @@ class OnFrameRetrace {
RenderId renderId,
const std::vector<std::string> &api_calls) = 0;
virtual void onError(ErrorSeverity s, const std::string &message) = 0;
+ virtual void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) = 0;
};
class IFrameRetrace {
@@ -279,6 +282,8 @@ class IFrameRetrace {
OnFrameRetrace *callback) = 0;
virtual void retraceApi(const RenderSelection &selection,
OnFrameRetrace *callback) = 0;
+ virtual void retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback) = 0;
};
class FrameState {
diff --git a/retrace/daemon/glframe_retrace_skeleton.cpp b/retrace/daemon/glframe_retrace_skeleton.cpp
index c3201e44..15d506be 100644
--- a/retrace/daemon/glframe_retrace_skeleton.cpp
+++ b/retrace/daemon/glframe_retrace_skeleton.cpp
@@ -297,6 +297,23 @@ FrameRetraceSkeleton::Run() {
writeResponse(m_socket, proto_response, &m_buf);
break;
}
+ case ApiTrace::BATCH_REQUEST:
+ {
+ assert(request.has_batch());
+ auto batch = request.batch();
+ RenderSelection selection;
+ makeRenderSelection(batch.selection(), &selection);
+ m_frame->retraceBatch(selection,
+ this);
+ // send empty message to signal the last response
+ RetraceResponse proto_response;
+ auto batch_resp = proto_response.mutable_batch();
+ batch_resp->set_render_id(-1);
+ batch_resp->set_selection_count(-1);
+ batch_resp->set_batch("");
+ writeResponse(m_socket, proto_response, &m_buf);
+ break;
+ }
}
}
}
@@ -425,3 +442,15 @@ FrameRetraceSkeleton::onError(ErrorSeverity s, const std::string &message) {
if (s == RETRACE_FATAL)
m_fatal_error = true;
}
+
+void
+FrameRetraceSkeleton::onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {
+ RetraceResponse proto_response;
+ auto response = proto_response.mutable_batch();
+ response->set_render_id(renderId());
+ response->set_selection_count(selectionCount());
+ response->set_batch(batch);
+ writeResponse(m_socket, proto_response, &m_buf);
+}
diff --git a/retrace/daemon/glframe_retrace_skeleton.hpp b/retrace/daemon/glframe_retrace_skeleton.hpp
index 4a9015ab..95ab3da8 100644
--- a/retrace/daemon/glframe_retrace_skeleton.hpp
+++ b/retrace/daemon/glframe_retrace_skeleton.hpp
@@ -83,6 +83,10 @@ class FrameRetraceSkeleton : public Thread,
const std::vector<std::string> &api_calls);
virtual void onError(ErrorSeverity s, const std::string &message);
+ virtual void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch);
+
protected:
bool m_force_upload; // for unit test
diff --git a/retrace/daemon/glframe_retrace_stub.cpp b/retrace/daemon/glframe_retrace_stub.cpp
index 23f6a362..c3eedb12 100644
--- a/retrace/daemon/glframe_retrace_stub.cpp
+++ b/retrace/daemon/glframe_retrace_stub.cpp
@@ -588,6 +588,63 @@ class ApiRequest : public IRetraceRequest {
OnFrameRetrace *m_callback;
};
+class BatchRequest : public IRetraceRequest {
+ public:
+ BatchRequest(SelectionId *current_selection,
+ std::mutex *protect,
+ const RenderSelection &selection,
+ OnFrameRetrace *cb)
+ : m_sel_count(current_selection),
+ m_protect(protect),
+ m_callback(cb) {
+ auto batchRequest = m_proto_msg.mutable_batch();
+ auto selectionRequest = batchRequest->mutable_selection();
+ makeRenderSelection(selection, selectionRequest);
+ m_proto_msg.set_requesttype(ApiTrace::BATCH_REQUEST);
+ }
+ virtual void retrace(RetraceSocket *s) {
+ {
+ std::lock_guard<std::mutex> l(*m_protect);
+ const auto &sel = m_proto_msg.batch().selection();
+ const SelectionId id(sel.selection_count());
+ if (*m_sel_count != id)
+ // more recent selection was made while this was enqueued
+ return;
+ }
+ RetraceResponse response;
+ // sends single request, read multiple responses
+ s->request(m_proto_msg);
+ while (true) {
+ response.Clear();
+ s->response(&response);
+ assert(response.has_batch());
+ const auto &batch_response = response.batch();
+ if (batch_response.render_id() == -1)
+ // all responses sent
+ break;
+
+ const auto selection = batch_response.selection_count();
+ {
+ std::lock_guard<std::mutex> l(*m_protect);
+ if (*m_sel_count != SelectionId(selection))
+ // more recent selection was made while retrace was being
+ // executed.
+ continue;
+ }
+
+ const RenderId rid(batch_response.render_id());
+ m_callback->onBatch(SelectionId(selection),
+ rid, batch_response.batch());
+ }
+ }
+
+ private:
+ const SelectionId * const m_sel_count;
+ std::mutex *m_protect;
+ RetraceRequest m_proto_msg;
+ OnFrameRetrace *m_callback;
+};
+
class NullRequest : public IRetraceRequest {
public:
// to pump the thread, and force it to stop
@@ -778,3 +835,15 @@ FrameRetraceStub::Flush() {
m_thread->push(new FlushRequest(&sem));
sem.wait();
}
+
+void
+FrameRetraceStub::retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback) {
+ {
+ std::lock_guard<std::mutex> l(m_mutex);
+ m_current_render_selection = selection.id;
+ }
+ m_thread->push(new BatchRequest(&m_current_render_selection,
+ &m_mutex,
+ selection, callback));
+}
diff --git a/retrace/daemon/glframe_retrace_stub.hpp b/retrace/daemon/glframe_retrace_stub.hpp
index 9dd27b28..749c12b5 100644
--- a/retrace/daemon/glframe_retrace_stub.hpp
+++ b/retrace/daemon/glframe_retrace_stub.hpp
@@ -78,6 +78,8 @@ class FrameRetraceStub : public IFrameRetrace {
OnFrameRetrace *callback);
virtual void retraceApi(const RenderSelection &selection,
OnFrameRetrace *callback);
+ virtual void retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback);
private:
mutable std::mutex m_mutex;
diff --git a/retrace/daemon/glframe_state.hpp b/retrace/daemon/glframe_state.hpp
index 52a73aa8..108e3a2d 100644
--- a/retrace/daemon/glframe_state.hpp
+++ b/retrace/daemon/glframe_state.hpp
@@ -48,6 +48,9 @@ class StateTrack;
class OutputPoller {
public:
virtual void poll(int current_program, StateTrack *cb) = 0;
+ virtual void pollBatch(SelectionId selectionCount,
+ RenderId id,
+ OnFrameRetrace *cb) = 0;
virtual ~OutputPoller() {}
virtual void init() = 0;
};
diff --git a/retrace/daemon/glframe_stderr.cpp b/retrace/daemon/glframe_stderr.cpp
index 7ebaea7c..fc6de8fa 100644
--- a/retrace/daemon/glframe_stderr.cpp
+++ b/retrace/daemon/glframe_stderr.cpp
@@ -313,3 +313,19 @@ StdErrRedirect::init() {
close(out_pipe[1]);
buf.resize(1024);
}
+
+void
+StdErrRedirect::pollBatch(SelectionId selectionCount,
+ RenderId id,
+ OnFrameRetrace *cb) {
+ fflush(stdout);
+ std::string batch_output;
+ int bytes = read(out_pipe[0], buf.data(), buf.size() - 1);
+ while (0 < bytes) {
+ buf[bytes] = '\0';
+ batch_output.append(buf.data());
+ bytes = read(out_pipe[0], buf.data(), buf.size() - 1);
+ }
+
+ cb->onBatch(selectionCount, id, batch_output);
+}
diff --git a/retrace/daemon/glframe_stderr.hpp b/retrace/daemon/glframe_stderr.hpp
index e906da80..0d3c13f8 100644
--- a/retrace/daemon/glframe_stderr.hpp
+++ b/retrace/daemon/glframe_stderr.hpp
@@ -35,6 +35,9 @@ class StdErrRedirect : public OutputPoller {
public:
StdErrRedirect();
void poll(int current_program, StateTrack *cb);
+ void pollBatch(SelectionId selectionCount,
+ RenderId id,
+ OnFrameRetrace *cb);
~StdErrRedirect();
void init();
@@ -47,6 +50,9 @@ class NoRedirect : public OutputPoller {
public:
NoRedirect() {}
void poll(int, StateTrack *) {}
+ void pollBatch(SelectionId,
+ RenderId,
+ OnFrameRetrace *) {}
~NoRedirect() {}
void init() {}
};
@@ -55,6 +61,9 @@ class WinShaders : public OutputPoller {
public:
WinShaders() {}
void poll(int current_program, StateTrack *cb);
+ void pollBatch(SelectionId,
+ RenderId,
+ OnFrameRetrace *) {}
~WinShaders() {}
void init();
private:
diff --git a/retrace/daemon/playback.proto b/retrace/daemon/playback.proto
index c09b1adf..82232165 100644
--- a/retrace/daemon/playback.proto
+++ b/retrace/daemon/playback.proto
@@ -14,6 +14,7 @@ enum RequestType {
ALL_METRICS_REQUEST = 5;
REPLACE_SHADERS_REQUEST = 6;
API_REQUEST = 7;
+ BATCH_REQUEST = 8;
};
message OpenFileRequest {
@@ -150,6 +151,16 @@ message ErrorResponse {
required string message = 2;
}
+message BatchRequest {
+ required RenderSelection selection = 1;
+}
+
+message BatchResponse {
+ required uint32 render_id = 1;
+ required uint32 selection_count = 2;
+ required string batch = 3;
+}
+
message RetraceRequest {
required RequestType requestType = 1;
optional RenderTargetRequest renderTarget = 2;
@@ -159,6 +170,7 @@ message RetraceRequest {
optional AllMetricsRequest allMetrics = 6;
optional ReplaceShadersRequest shaders = 7;
optional ApiRequest api = 8;
+ optional BatchRequest batch = 9;
}
message RetraceResponse {
@@ -170,4 +182,5 @@ message RetraceResponse {
optional ReplaceShadersResponse shadersData = 6;
optional ApiResponse api = 7;
optional ErrorResponse error = 8;
+ optional BatchResponse batch = 9;
}
diff --git a/retrace/daemon/test/retrace_daemon_test.cpp b/retrace/daemon/test/retrace_daemon_test.cpp
index c0562a0a..b6ef5d3f 100644
--- a/retrace/daemon/test/retrace_daemon_test.cpp
+++ b/retrace/daemon/test/retrace_daemon_test.cpp
@@ -98,6 +98,9 @@ class NullCallback : public OnFrameRetrace {
void onError(ErrorSeverity s, const std::string &message) {
file_error = true;
}
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {}
int renderTargetCount;
SelectionId last_selection;
std::string compile_error;
diff --git a/retrace/daemon/test/retrace_file_transfer_test.cpp b/retrace/daemon/test/retrace_file_transfer_test.cpp
index 25aa62b3..36b9b6e4 100644
--- a/retrace/daemon/test/retrace_file_transfer_test.cpp
+++ b/retrace/daemon/test/retrace_file_transfer_test.cpp
@@ -89,6 +89,8 @@ class FileTransfer : public IFrameRetrace {
OnFrameRetrace *callback) {}
void retraceApi(const RenderSelection &selection,
OnFrameRetrace *callback) {}
+ void retraceBatch(const RenderSelection &selection,
+ OnFrameRetrace *callback) {}
};
class FileTransferCB : public OnFrameRetrace {
@@ -124,6 +126,9 @@ class FileTransferCB : public OnFrameRetrace {
RenderId renderId,
const std::vector<std::string> &api_calls) {}
void onError(ErrorSeverity s, const std::string &message) {}
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {}
bool m_needUpload;
};
diff --git a/retrace/daemon/test/retrace_metrics_test.cpp b/retrace/daemon/test/retrace_metrics_test.cpp
index 9eb41d81..7a259652 100644
--- a/retrace/daemon/test/retrace_metrics_test.cpp
+++ b/retrace/daemon/test/retrace_metrics_test.cpp
@@ -74,6 +74,9 @@ class MetricsCallback : public OnFrameRetrace {
RenderId renderId,
const std::vector<std::string> &api_calls) {}
void onError(ErrorSeverity s, const std::string &message) {}
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {}
std::vector<MetricId> ids;
std::vector<std::string> names;
std::vector<MetricSeries> data;
diff --git a/retrace/daemon/ui/CMakeLists.txt b/retrace/daemon/ui/CMakeLists.txt
index 2dd89b31..caebf9af 100644
--- a/retrace/daemon/ui/CMakeLists.txt
+++ b/retrace/daemon/ui/CMakeLists.txt
@@ -23,6 +23,8 @@ set (UI_SRC
main.cpp
glframe_api_model.hpp
glframe_api_model.cpp
+ glframe_batch_model.hpp
+ glframe_batch_model.cpp
glframe_metrics_model.hpp
glframe_metrics_model.cpp
glframe_qutil.hpp
diff --git a/retrace/daemon/ui/glframe_batch_model.cpp b/retrace/daemon/ui/glframe_batch_model.cpp
new file mode 100644
index 00000000..a46c53c0
--- /dev/null
+++ b/retrace/daemon/ui/glframe_batch_model.cpp
@@ -0,0 +1,94 @@
+/**************************************************************************
+ *
+ * Copyright 2017 Intel Corporation
+ * 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.
+ *
+ * Authors:
+ * Mark Janes <mark.a.janes@intel.com>
+ **************************************************************************/
+
+#include "glframe_batch_model.hpp"
+
+#include <string>
+#include <vector>
+
+#include "glframe_os.hpp"
+#include "glframe_qutil.hpp"
+
+using glretrace::ExperimentId;
+using glretrace::QBatchModel;
+using glretrace::RenderId;
+using glretrace::ScopedLock;
+using glretrace::SelectionId;
+
+QBatchModel::QBatchModel() : m_sel_count(0), m_index(-1) {
+}
+
+QBatchModel::~QBatchModel() {
+ m_batch.clear();
+}
+
+QString
+QBatchModel::batch() {
+ ScopedLock s(m_protect);
+ if (m_index < 0)
+ return QString("Mesa has the ability to display batches dispatched "
+ "to the GPU."
+ "\nSee apitrace/retrace/daemon/doc/README.txt");
+ if (m_index >= m_renders.size())
+ return QString("");
+ return m_batch[m_renders[m_index]];
+}
+
+void
+QBatchModel::onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {
+ {
+ ScopedLock s(m_protect);
+ if (m_sel_count != selectionCount) {
+ m_batch.clear();
+ m_renders.clear();
+ m_sel_count = selectionCount;
+ }
+
+ m_renders.push_back(QString("%1").arg(renderId.index()));
+ m_batch[m_renders.back()] = QString(batch.c_str());
+ }
+ setIndex(0);
+ emit onRenders();
+}
+
+void
+QBatchModel::setIndex(int index) {
+ {
+ ScopedLock s(m_protect);
+ m_index = index;
+ }
+ emit onBatchChanged();
+}
+
+QStringList
+QBatchModel::renders() const {
+ ScopedLock s(m_protect);
+ return m_renders;
+}
+
diff --git a/retrace/daemon/ui/glframe_batch_model.hpp b/retrace/daemon/ui/glframe_batch_model.hpp
new file mode 100644
index 00000000..cb60671f
--- /dev/null
+++ b/retrace/daemon/ui/glframe_batch_model.hpp
@@ -0,0 +1,77 @@
+/**************************************************************************
+ *
+ * Copyright 2017 Intel Corporation
+ * 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.
+ *
+ * Authors:
+ * Mark Janes <mark.a.janes@intel.com>
+ **************************************************************************/
+
+#ifndef _GLFRAME_BATCH_MODEL_HPP_
+#define _GLFRAME_BATCH_MODEL_HPP_
+
+#include <QObject>
+#include <QString>
+
+#include <mutex>
+#include <string>
+#include <map>
+#include <vector>
+
+#include "glframe_retrace_interface.hpp"
+#include "glframe_traits.hpp"
+
+namespace glretrace {
+
+// This class is highly similar to QApiModel. Consider merging them
+// and making the filter functionality optional. For now, it should
+// remain separate, as the feature is a proof-of-concept that may soon
+// be deleted.
+class QBatchModel : public QObject,
+ NoCopy, NoAssign, NoMove{
+ Q_OBJECT
+ Q_PROPERTY(QString batch READ batch NOTIFY onBatchChanged)
+ Q_PROPERTY(QStringList renders READ renders NOTIFY onRenders)
+ public:
+ QBatchModel();
+ ~QBatchModel();
+ QString batch();
+ QStringList renders() const;
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch);
+ Q_INVOKABLE void setIndex(int index);
+
+ signals:
+ void onBatchChanged();
+ void onRenders();
+
+ private:
+ std::map<QString, QString> m_batch;
+ QStringList m_renders;
+ SelectionId m_sel_count;
+ int m_index;
+ mutable std::mutex m_protect;
+};
+
+} // namespace glretrace
+
+#endif // _GLFRAME_BATCH_MODEL_HPP_
diff --git a/retrace/daemon/ui/glframe_metrics_model.hpp b/retrace/daemon/ui/glframe_metrics_model.hpp
index 4c17e15c..7198dba5 100644
--- a/retrace/daemon/ui/glframe_metrics_model.hpp
+++ b/retrace/daemon/ui/glframe_metrics_model.hpp
@@ -119,6 +119,9 @@ class QMetricsModel : public QObject, OnFrameRetrace,
RenderId renderId,
const std::vector<std::string> &api_calls) { assert(false); }
void onError(ErrorSeverity s, const std::string &message) { assert(false); }
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) { assert(false); }
void filter(const QString& f);
QQmlListProperty<QMetricValue> metrics();
diff --git a/retrace/daemon/ui/glframe_retrace_model.cpp b/retrace/daemon/ui/glframe_retrace_model.cpp
index e35a294e..ce158a48 100644
--- a/retrace/daemon/ui/glframe_retrace_model.cpp
+++ b/retrace/daemon/ui/glframe_retrace_model.cpp
@@ -280,6 +280,15 @@ FrameRetraceModel::retrace_api() {
}
void
+FrameRetraceModel::retrace_batch() {
+ RenderSelection sel;
+ glretrace::renderSelectionFromList(m_selection_count,
+ m_cached_selection,
+ &sel);
+ m_retrace.retraceBatch(sel, this);
+}
+
+void
FrameRetraceModel::onFileOpening(bool needUpload,
bool finished,
uint32_t frame_count) {
@@ -415,6 +424,7 @@ FrameRetraceModel::onSelect(QList<int> selection) {
retrace_rendertarget();
retrace_shader_assemblies();
retrace_api();
+ retrace_batch();
}
bool
@@ -537,3 +547,10 @@ FrameRetraceModel::onShadersChanged() {
m_retrace.retraceMetrics(m_active_metrics, ExperimentId(0),
this);
}
+
+void
+FrameRetraceModel::onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch) {
+ m_batch.onBatch(selectionCount, renderId, batch);
+}
diff --git a/retrace/daemon/ui/glframe_retrace_model.hpp b/retrace/daemon/ui/glframe_retrace_model.hpp
index 4d4431d4..59b9e54e 100644
--- a/retrace/daemon/ui/glframe_retrace_model.hpp
+++ b/retrace/daemon/ui/glframe_retrace_model.hpp
@@ -44,6 +44,7 @@
#include "glframe_retrace_stub.hpp"
#include "glframe_api_model.hpp"
#include "glframe_bargraph.hpp"
+#include "glframe_batch_model.hpp"
#include "glframe_os.hpp"
#include "glframe_qselection.hpp"
#include "glframe_shader_model.hpp"
@@ -110,6 +111,7 @@ class FrameRetraceModel : public QObject,
WRITE setHighlightRender)
Q_PROPERTY(glretrace::QRenderShadersList* shaders READ shaders CONSTANT)
Q_PROPERTY(glretrace::QApiModel* api READ api CONSTANT)
+ Q_PROPERTY(glretrace::QBatchModel* batch READ batch CONSTANT)
Q_PROPERTY(QString shaderCompileError READ shaderCompileError
NOTIFY onShaderCompileError)
Q_PROPERTY(QString argvZero READ argvZero WRITE setArgvZero
@@ -166,6 +168,9 @@ class FrameRetraceModel : public QObject,
RenderId renderId,
const std::vector<std::string> &api_calls);
void onError(ErrorSeverity s, const std::string &message);
+ void onBatch(SelectionId selectionCount,
+ RenderId renderId,
+ const std::string &batch);
void onShadersChanged();
QString renderTargetImage() const;
int frameCount() const { ScopedLock s(m_protect); return m_frame_count; }
@@ -173,6 +178,7 @@ class FrameRetraceModel : public QObject,
QString apiCalls();
QRenderShadersList *shaders() { return &m_shaders; }
QApiModel *api() { return &m_api; }
+ QBatchModel *batch() { return &m_batch; }
QString shaderCompileError() { return m_shader_compile_error; }
QString argvZero() { return main_exe; }
void setArgvZero(const QString &a) { main_exe = a; emit onArgvZero(); }
@@ -203,7 +209,6 @@ class FrameRetraceModel : public QObject,
void onRenderTarget();
void onFrameCount();
void onMaxMetric();
- void onApiCalls();
void onShaderCompileError();
void onArgvZero();
void onGeneralError();
@@ -215,11 +220,13 @@ class FrameRetraceModel : public QObject,
void retrace_rendertarget();
void retrace_shader_assemblies();
void retrace_api();
+ void retrace_batch();
mutable std::mutex m_protect;
FrameRetraceStub m_retrace;
QMetricsModel m_metrics_table;
QApiModel m_api;
+ QBatchModel m_batch;
FrameState *m_state;
QSelection *m_selection;
SelectionId m_selection_count;
diff --git a/retrace/daemon/ui/main.cpp b/retrace/daemon/ui/main.cpp
index 84dd572b..eb65b95d 100644
--- a/retrace/daemon/ui/main.cpp
+++ b/retrace/daemon/ui/main.cpp
@@ -108,6 +108,8 @@ int main(int argc, char *argv[]) {
"QRenderShadersList");
qmlRegisterType<glretrace::QApiModel>("ApiTrace", 1, 0,
"QApiModel");
+ qmlRegisterType<glretrace::QBatchModel>("ApiTrace", 1, 0,
+ "QBatchModel");
glretrace::FrameImages::Create();
diff --git a/retrace/daemon/ui/qml/BatchControl.qml b/retrace/daemon/ui/qml/BatchControl.qml
new file mode 100644
index 00000000..74dfce98
--- /dev/null
+++ b/retrace/daemon/ui/qml/BatchControl.qml
@@ -0,0 +1,75 @@
+import QtQuick 2.2
+import QtQuick.Controls 1.1
+import QtQuick.Layouts 1.1
+import QtQuick.Dialogs 1.1
+import ApiTrace 1.0
+
+// This control is highly similar to ApiControl. Consider merging
+// them and making the filter functionality optional. For now, it
+// should remain separate, as the feature is a proof-of-concept that
+// may soon be deleted.
+Item {
+ property QBatchModel batchModel
+
+ SplitView {
+ anchors.fill: parent
+
+ ScrollView {
+ Layout.preferredWidth: 100
+ Layout.preferredHeight: parent.height
+ Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+ ListView {
+ id: batch_selection
+ model: batchModel.renders
+ focus: true
+ highlight: Rectangle { color: "lightsteelblue"; radius: 5; }
+ delegate: Component {
+ Item {
+ height: render_text.height
+ width: batch_selection.width
+ Text {
+ id: render_text
+ text: modelData
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ batchModel.setIndex(index);
+ batch_selection.currentIndex = index;
+ }
+ }
+ }
+ }
+ Keys.onDownPressed: {
+ if (batch_selection.currentIndex + 1 < batch_selection.count) {
+ batch_selection.currentIndex += 1;
+ batchModel.setIndex(batch_selection.currentIndex);
+ }
+ }
+ Keys.onUpPressed: {
+ if (batch_selection.currentIndex > 0) {
+ batch_selection.currentIndex -= 1;
+ batchModel.setIndex(batch_selection.currentIndex);
+ }
+ }
+ }
+ }
+ ScrollView {
+ Layout.preferredWidth: 1000
+ Layout.preferredHeight: parent.height
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+ Flickable {
+ anchors.fill: parent
+ contentWidth: batch.width; contentHeight: batch.height
+ clip: true
+ TextEdit {
+ id: batch
+ readOnly: true
+ selectByMouse: true
+ text: batchModel.batch
+ }
+ }
+ }
+ }
+}
diff --git a/retrace/daemon/ui/qml/mainwin.qml b/retrace/daemon/ui/qml/mainwin.qml
index 5eca0263..ced6df06 100644
--- a/retrace/daemon/ui/qml/mainwin.qml
+++ b/retrace/daemon/ui/qml/mainwin.qml
@@ -380,6 +380,15 @@ ApplicationWindow {
}
}
Tab {
+ title: "Batch"
+ clip: true
+ anchors.fill: parent
+ BatchControl {
+ anchors.fill: parent
+ batchModel: frameRetrace.batch
+ }
+ }
+ Tab {
title: "Metrics"
id: metricTab
anchors.fill: parent
diff --git a/retrace/daemon/ui/resources.qrc b/retrace/daemon/ui/resources.qrc
index 04507f0d..e87c928d 100644
--- a/retrace/daemon/ui/resources.qrc
+++ b/retrace/daemon/ui/resources.qrc
@@ -9,5 +9,6 @@
<file>qml/images/no_render_target.png</file>
<file>qml/RenderShadersControl.qml</file>
<file>qml/ApiControl.qml</file>
+ <file>qml/BatchControl.qml</file>
</qresource>
</RCC>