From 74ecc79877c13dbdf43b7f70aa77b2a594f92a8c Mon Sep 17 00:00:00 2001 From: Mark Janes Date: Mon, 24 Apr 2017 18:08:50 -0700 Subject: Batch: display batches sent to hardware Slight modifications to Mesa enable batch buffer display --- retrace/daemon/CMakeLists.txt | 6 +- ...unconditionally-allocate-DEBUG_BATCH-hash.patch | 46 +++++++++++ retrace/daemon/doc/README.txt | 10 +++ retrace/daemon/glframe_batch.cpp | 71 ++++++++++++++++ retrace/daemon/glframe_batch.hpp | 62 ++++++++++++++ retrace/daemon/glframe_retrace.cpp | 20 +++++ retrace/daemon/glframe_retrace.hpp | 3 + retrace/daemon/glframe_retrace_context.cpp | 28 +++++++ retrace/daemon/glframe_retrace_context.hpp | 7 ++ retrace/daemon/glframe_retrace_interface.hpp | 5 ++ retrace/daemon/glframe_retrace_skeleton.cpp | 29 +++++++ retrace/daemon/glframe_retrace_skeleton.hpp | 4 + retrace/daemon/glframe_retrace_stub.cpp | 69 ++++++++++++++++ retrace/daemon/glframe_retrace_stub.hpp | 2 + retrace/daemon/glframe_state.hpp | 3 + retrace/daemon/glframe_stderr.cpp | 16 ++++ retrace/daemon/glframe_stderr.hpp | 9 +++ retrace/daemon/playback.proto | 13 +++ retrace/daemon/test/retrace_daemon_test.cpp | 3 + retrace/daemon/test/retrace_file_transfer_test.cpp | 5 ++ retrace/daemon/test/retrace_metrics_test.cpp | 3 + retrace/daemon/ui/CMakeLists.txt | 2 + retrace/daemon/ui/glframe_batch_model.cpp | 94 ++++++++++++++++++++++ retrace/daemon/ui/glframe_batch_model.hpp | 77 ++++++++++++++++++ retrace/daemon/ui/glframe_metrics_model.hpp | 3 + retrace/daemon/ui/glframe_retrace_model.cpp | 17 ++++ retrace/daemon/ui/glframe_retrace_model.hpp | 9 ++- retrace/daemon/ui/main.cpp | 2 + retrace/daemon/ui/qml/BatchControl.qml | 75 +++++++++++++++++ retrace/daemon/ui/qml/mainwin.qml | 9 +++ retrace/daemon/ui/resources.qrc | 1 + 31 files changed, 700 insertions(+), 3 deletions(-) create mode 100644 retrace/daemon/doc/0001-i965-batch-unconditionally-allocate-DEBUG_BATCH-hash.patch create mode 100644 retrace/daemon/doc/README.txt create mode 100644 retrace/daemon/glframe_batch.cpp create mode 100644 retrace/daemon/glframe_batch.hpp create mode 100644 retrace/daemon/ui/glframe_batch_model.cpp create mode 100644 retrace/daemon/ui/glframe_batch_model.hpp create mode 100644 retrace/daemon/ui/qml/BatchControl.qml (limited to 'retrace') 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 +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 +// **********************************************************************/ + +#include "glframe_batch.hpp" + +#include +#include +#include + +#include + +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(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 +// **********************************************************************/ + +#ifndef _GLFRAME_BATCH_HPP__ +#define _GLFRAME_BATCH_HPP__ + +#include + +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 #include +#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 #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 &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 &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 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 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 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 &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 &api_calls) {} void onError(ErrorSeverity s, const std::string &message) {} + void onBatch(SelectionId selectionCount, + RenderId renderId, + const std::string &batch) {} std::vector ids; std::vector names; std::vector 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 + **************************************************************************/ + +#include "glframe_batch_model.hpp" + +#include +#include + +#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 + **************************************************************************/ + +#ifndef _GLFRAME_BATCH_MODEL_HPP_ +#define _GLFRAME_BATCH_MODEL_HPP_ + +#include +#include + +#include +#include +#include +#include + +#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 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 &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 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 @@ -279,6 +279,15 @@ FrameRetraceModel::retrace_api() { m_retrace.retraceApi(sel, this); } +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, @@ -415,6 +424,7 @@ FrameRetraceModel::onSelect(QList 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 &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("ApiTrace", 1, 0, "QApiModel"); + qmlRegisterType("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 @@ -379,6 +379,15 @@ ApplicationWindow { apiModel: frameRetrace.api } } + Tab { + title: "Batch" + clip: true + anchors.fill: parent + BatchControl { + anchors.fill: parent + batchModel: frameRetrace.batch + } + } Tab { title: "Metrics" id: metricTab 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 @@ qml/images/no_render_target.png qml/RenderShadersControl.qml qml/ApiControl.qml + qml/BatchControl.qml -- cgit v1.2.3