Improvements to studio profiler
PiperOrigin-RevId: 938503994 Change-Id: I3a12647feea4c761dd8f8ba239f92355ceccfba1
This commit is contained in:
committed by
Copybara-Service
parent
56a182e67c
commit
c7b1171846
@@ -14,6 +14,12 @@
|
||||
|
||||
#include "experimental/platform/sim/sim_profiler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <implot.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
@@ -33,7 +39,7 @@ void SimProfiler::Clear() {
|
||||
dim_dof_.clear();
|
||||
dim_body_.clear();
|
||||
dim_constraint_.clear();
|
||||
dim_sqrt_nnz_.clear();
|
||||
dim_nnz_.clear();
|
||||
dim_contact_.clear();
|
||||
dim_iteration_.clear();
|
||||
|
||||
@@ -45,7 +51,7 @@ void SimProfiler::Clear() {
|
||||
dim_dof_.resize(kProfilerMaxFrames, 0);
|
||||
dim_body_.resize(kProfilerMaxFrames, 0);
|
||||
dim_constraint_.resize(kProfilerMaxFrames, 0);
|
||||
dim_sqrt_nnz_.resize(kProfilerMaxFrames, 0);
|
||||
dim_nnz_.resize(kProfilerMaxFrames, 0);
|
||||
dim_contact_.resize(kProfilerMaxFrames, 0);
|
||||
dim_iteration_.resize(kProfilerMaxFrames, 0);
|
||||
}
|
||||
@@ -63,20 +69,20 @@ void SimProfiler::Update(const mjModel* model, const mjData* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
mjtNum avg_total = total / number;
|
||||
mjtNum avg_total = 1000.0 * total / number;
|
||||
cpu_total_.erase(cpu_total_.begin());
|
||||
cpu_total_.push_back(avg_total);
|
||||
|
||||
mjtNum collision = data->timer[mjTIMER_POS_COLLISION].duration / number;
|
||||
mjtNum collision = 1000.0 * data->timer[mjTIMER_POS_COLLISION].duration / number;
|
||||
cpu_collision_.erase(cpu_collision_.begin());
|
||||
cpu_collision_.push_back(collision);
|
||||
|
||||
mjtNum prepare = (data->timer[mjTIMER_POS_MAKE].duration / number) +
|
||||
(data->timer[mjTIMER_POS_PROJECT].duration / number);
|
||||
mjtNum prepare = 1000.0 * ((data->timer[mjTIMER_POS_MAKE].duration / number) +
|
||||
(data->timer[mjTIMER_POS_PROJECT].duration / number));
|
||||
cpu_prepare_.erase(cpu_prepare_.begin());
|
||||
cpu_prepare_.push_back(prepare);
|
||||
|
||||
mjtNum solve = data->timer[mjTIMER_CONSTRAINT].duration / number;
|
||||
mjtNum solve = 1000.0 * data->timer[mjTIMER_CONSTRAINT].duration / number;
|
||||
cpu_solve_.erase(cpu_solve_.begin());
|
||||
cpu_solve_.push_back(solve);
|
||||
|
||||
@@ -85,15 +91,14 @@ void SimProfiler::Update(const mjModel* model, const mjData* data) {
|
||||
cpu_other_.push_back(other);
|
||||
|
||||
// Solver diagnostics.
|
||||
mjtNum sqrt_nnz = 0;
|
||||
mjtNum nnz = 0;
|
||||
int solver_niter = 0;
|
||||
const int nisland =
|
||||
data->nefc ? mjMAX(1, mjMIN(data->nisland, mjNISLAND)) : 0;
|
||||
for (int island = 0; island < nisland; island++) {
|
||||
sqrt_nnz += data->solver_nnz[island];
|
||||
nnz += data->solver_nnz[island];
|
||||
solver_niter += data->solver_niter[island];
|
||||
}
|
||||
sqrt_nnz = mju_sqrt(sqrt_nnz);
|
||||
|
||||
dim_dof_.erase(dim_dof_.begin());
|
||||
int nv = (model->opt.enableflags & mjENBL_SLEEP) ? data->nv_awake : model->nv;
|
||||
@@ -107,8 +112,8 @@ void SimProfiler::Update(const mjModel* model, const mjData* data) {
|
||||
dim_constraint_.erase(dim_constraint_.begin());
|
||||
dim_constraint_.push_back(data->nefc);
|
||||
|
||||
dim_sqrt_nnz_.erase(dim_sqrt_nnz_.begin());
|
||||
dim_sqrt_nnz_.push_back(sqrt_nnz);
|
||||
dim_nnz_.erase(dim_nnz_.begin());
|
||||
dim_nnz_.push_back(nnz);
|
||||
|
||||
dim_contact_.erase(dim_contact_.begin());
|
||||
dim_contact_.push_back(data->ncon);
|
||||
@@ -118,25 +123,65 @@ void SimProfiler::Update(const mjModel* model, const mjData* data) {
|
||||
mjMAX(1, nisland));
|
||||
}
|
||||
|
||||
// Returns a dynamically padded legend label for ImPlot.
|
||||
static std::string GetLegendLabel(const char* name, const std::vector<float>& values) {
|
||||
float sum = 0.f;
|
||||
int count = 0;
|
||||
for (float val : values) {
|
||||
if (val != 0.f) {
|
||||
sum += val;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
float avg = count > 0 ? (sum / count) : 0.f;
|
||||
|
||||
char buf[128];
|
||||
std::snprintf(buf, sizeof(buf), "%-9s (%4.0f)###%s", name, avg, name);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// Returns a dynamically padded legend label for the Dimensions plot.
|
||||
static std::string GetDimensionLabel(const char* name, float value) {
|
||||
char buf[128];
|
||||
std::snprintf(buf, sizeof(buf), "%-10s: %5.0f###%s", name, value, name);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
void SimProfiler::CpuTimeGraph(ImVec2 plot_size) {
|
||||
ScopedStyle style;
|
||||
style.Font(ScopedFont::kMono);
|
||||
|
||||
ImPlotFlags flags =
|
||||
ImPlot_SetupPlotFlags(plot_size) | ImPlotFlags_NoMouseText;
|
||||
if (ImPlot::BeginPlot("CPU msec vs frame", plot_size, flags)) {
|
||||
if (ImPlot::BeginPlot("CPU microseconds (avg) vs frame", plot_size, flags)) {
|
||||
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2.0f);
|
||||
ImPlot_SetupTimeAxis(plot_size, "");
|
||||
ImPlot_SetupValueAxis(plot_size, "", "%.2f");
|
||||
ImPlot_SetupValueAxis(plot_size, "", "%.0f");
|
||||
float max_val = 0.f;
|
||||
for (float val : cpu_total_) {
|
||||
if (val > max_val) {
|
||||
max_val = val;
|
||||
}
|
||||
}
|
||||
float rounded_max = std::max(100.0f, std::ceil(max_val / 100.0f) * 100.0f);
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 0.0, rounded_max, ImPlotCond_Always);
|
||||
ImPlot::SetupLegend(ImPlotLocation_NorthEast);
|
||||
ImPlot::SetupFinish();
|
||||
|
||||
ImPlot::PlotLine("total", cpu_total_.data(), cpu_total_.size(), 1,
|
||||
ImPlot::PlotLine(GetLegendLabel("total", cpu_total_).c_str(),
|
||||
cpu_total_.data(), cpu_total_.size(), 1,
|
||||
-(int)cpu_total_.size());
|
||||
ImPlot::PlotLine("prepare", cpu_prepare_.data(), cpu_prepare_.size(), 1,
|
||||
ImPlot::PlotLine(GetLegendLabel("prepare", cpu_prepare_).c_str(),
|
||||
cpu_prepare_.data(), cpu_prepare_.size(), 1,
|
||||
-(int)cpu_prepare_.size());
|
||||
ImPlot::PlotLine("solve", cpu_solve_.data(), cpu_solve_.size(), 1,
|
||||
ImPlot::PlotLine(GetLegendLabel("solve", cpu_solve_).c_str(),
|
||||
cpu_solve_.data(), cpu_solve_.size(), 1,
|
||||
-(int)cpu_solve_.size());
|
||||
ImPlot::PlotLine("collision", cpu_collision_.data(), cpu_collision_.size(),
|
||||
1, -(int)cpu_collision_.size());
|
||||
ImPlot::PlotLine("other", cpu_other_.data(), cpu_other_.size(), 1,
|
||||
ImPlot::PlotLine(GetLegendLabel("collision", cpu_collision_).c_str(),
|
||||
cpu_collision_.data(), cpu_collision_.size(), 1,
|
||||
-(int)cpu_collision_.size());
|
||||
ImPlot::PlotLine(GetLegendLabel("other", cpu_other_).c_str(),
|
||||
cpu_other_.data(), cpu_other_.size(), 1,
|
||||
-(int)cpu_other_.size());
|
||||
ImPlot::PopStyleVar();
|
||||
ImPlot::EndPlot();
|
||||
@@ -144,27 +189,62 @@ void SimProfiler::CpuTimeGraph(ImVec2 plot_size) {
|
||||
}
|
||||
|
||||
void SimProfiler::DimensionsGraph(ImVec2 plot_size) {
|
||||
ScopedStyle style;
|
||||
style.Font(ScopedFont::kMono);
|
||||
|
||||
ImPlotFlags flags =
|
||||
ImPlot_SetupPlotFlags(plot_size) | ImPlotFlags_NoMouseText;
|
||||
if (ImPlot::BeginPlot("Dimensions vs frame", plot_size, flags)) {
|
||||
if (ImPlot::BeginPlot("Dimensions: current vs frame", plot_size, flags)) {
|
||||
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2.0f);
|
||||
ImPlot_SetupTimeAxis(plot_size, "");
|
||||
ImPlot_SetupValueAxis(plot_size, "", "%.0f");
|
||||
ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10);
|
||||
float max_val = 10.f;
|
||||
for (float val : dim_dof_) { max_val = std::max(max_val, val); }
|
||||
for (float val : dim_body_) { max_val = std::max(max_val, val); }
|
||||
for (float val : dim_constraint_) { max_val = std::max(max_val, val); }
|
||||
for (float val : dim_nnz_) { max_val = std::max(max_val, val); }
|
||||
for (float val : dim_contact_) { max_val = std::max(max_val, val); }
|
||||
for (float val : dim_iteration_) { max_val = std::max(max_val, val); }
|
||||
float log_max = std::log10(max_val);
|
||||
float y_max = std::pow(10.f, log_max + 0.1f);
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 1.0, y_max, ImPlotCond_Always);
|
||||
ImPlot::SetupLegend(ImPlotLocation_NorthEast);
|
||||
ImPlot::SetupFinish();
|
||||
|
||||
ImPlot::PlotLine("dof", dim_dof_.data(), dim_dof_.size(), 1,
|
||||
-(int)dim_dof_.size());
|
||||
ImPlot::PlotLine("body", dim_body_.data(), dim_body_.size(), 1,
|
||||
-(int)dim_body_.size());
|
||||
ImPlot::PlotLine("constraint", dim_constraint_.data(),
|
||||
dim_constraint_.size(), 1, -(int)dim_constraint_.size());
|
||||
ImPlot::PlotLine("sqrt(nnz)", dim_sqrt_nnz_.data(), dim_sqrt_nnz_.size(), 1,
|
||||
-(int)dim_sqrt_nnz_.size());
|
||||
ImPlot::PlotLine("contact", dim_contact_.data(), dim_contact_.size(), 1,
|
||||
-(int)dim_contact_.size());
|
||||
ImPlot::PlotLine("iteration", dim_iteration_.data(), dim_iteration_.size(),
|
||||
1, -(int)dim_iteration_.size());
|
||||
const int count = static_cast<int>(dim_dof_.size());
|
||||
struct GetterData {
|
||||
const std::vector<float>* vec;
|
||||
int count;
|
||||
};
|
||||
auto getter = +[](int idx, void* user_data) -> ImPlotPoint {
|
||||
const auto* gd = static_cast<const GetterData*>(user_data);
|
||||
float val = (*gd->vec)[idx];
|
||||
double x = -gd->count + idx;
|
||||
double y = (val <= 0.0f) ? std::nan("") : static_cast<double>(val);
|
||||
return ImPlotPoint{x, y};
|
||||
};
|
||||
|
||||
GetterData nnz_data{&dim_nnz_, count};
|
||||
ImPlot::PlotLineG(GetDimensionLabel("nnz", dim_nnz_.back()).c_str(),
|
||||
getter, &nnz_data, count);
|
||||
GetterData constraint_data{&dim_constraint_, count};
|
||||
ImPlot::PlotLineG(
|
||||
GetDimensionLabel("constraint", dim_constraint_.back()).c_str(),
|
||||
getter, &constraint_data, count);
|
||||
GetterData dof_data{&dim_dof_, count};
|
||||
ImPlot::PlotLineG(GetDimensionLabel("dof", dim_dof_.back()).c_str(),
|
||||
getter, &dof_data, count);
|
||||
GetterData contact_data{&dim_contact_, count};
|
||||
ImPlot::PlotLineG(GetDimensionLabel("contact", dim_contact_.back()).c_str(),
|
||||
getter, &contact_data, count);
|
||||
GetterData body_data{&dim_body_, count};
|
||||
ImPlot::PlotLineG(GetDimensionLabel("body", dim_body_.back()).c_str(),
|
||||
getter, &body_data, count);
|
||||
GetterData iteration_data{&dim_iteration_, count};
|
||||
ImPlot::PlotLineG(
|
||||
GetDimensionLabel("iteration", dim_iteration_.back()).c_str(),
|
||||
getter, &iteration_data, count);
|
||||
ImPlot::PopStyleVar();
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class SimProfiler {
|
||||
std::vector<float> dim_dof_;
|
||||
std::vector<float> dim_body_;
|
||||
std::vector<float> dim_constraint_;
|
||||
std::vector<float> dim_sqrt_nnz_;
|
||||
std::vector<float> dim_nnz_;
|
||||
std::vector<float> dim_contact_;
|
||||
std::vector<float> dim_iteration_;
|
||||
};
|
||||
|
||||
@@ -1313,19 +1313,25 @@ static int GetPlotXLimit(const mjData* data) {
|
||||
for (int k = 0; k < nisland0; k++) {
|
||||
max_niter = mjMAX(max_niter, data->solver_niter[k]);
|
||||
}
|
||||
return mjMAX(10, ((max_niter + 9) / 10) * 10);
|
||||
return max_niter <= 10 ? 10 : ((max_niter + 59) / 60) * 60;
|
||||
}
|
||||
|
||||
void ConvergenceGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
ScopedStyle style;
|
||||
style.Font(ScopedFont::kMono);
|
||||
|
||||
int xlim = GetPlotXLimit(data);
|
||||
ImPlotFlags flags =
|
||||
ImPlot_SetupPlotFlags(plot_size) | ImPlotFlags_NoMouseText;
|
||||
if (ImPlot::BeginPlot("Convergence (log 10) vs iter", plot_size, flags)) {
|
||||
if (ImPlot::BeginPlot("Convergence vs iter", plot_size, flags)) {
|
||||
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2.0f);
|
||||
ImPlot::SetupAxis(ImAxis_X1, "", ImPlotAxisFlags_AutoFit);
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, 0, xlim, ImPlotCond_Always);
|
||||
ImPlot::SetupAxisFormat(ImAxis_Y1, "%.1f");
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, -20, 5, ImPlotCond_Always);
|
||||
ImPlot::SetupAxisFormat(ImAxis_Y1, "%.0e");
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, 1e-15, 1e0, ImPlotCond_Always);
|
||||
ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10);
|
||||
const double ticks[] = {1e-15, 1e-12, 1e-9, 1e-6, 1e-3, 1e0};
|
||||
ImPlot::SetupAxisTicks(ImAxis_Y1, ticks, 6);
|
||||
ImPlot::SetupLegend(ImPlotLocation_NorthEast);
|
||||
ImPlot::SetupFinish();
|
||||
|
||||
@@ -1342,7 +1348,7 @@ void ConvergenceGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
const mjSolverStat* stats =
|
||||
static_cast<const mjSolverStat*>(user_data);
|
||||
const float x = static_cast<float>(i);
|
||||
const float y = mju_log10(mju_max(mjMINVAL, stats[i].improvement));
|
||||
const float y = mju_max(mjMINVAL, stats[i].improvement);
|
||||
return ImPlotPoint{x, y};
|
||||
},
|
||||
stats, npoints);
|
||||
@@ -1357,7 +1363,7 @@ void ConvergenceGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
const mjSolverStat* stats =
|
||||
static_cast<const mjSolverStat*>(user_data);
|
||||
const float x = static_cast<float>(i);
|
||||
const float y = mju_log10(mju_max(mjMINVAL, stats[i].gradient));
|
||||
const float y = mju_max(mjMINVAL, stats[i].gradient);
|
||||
return ImPlotPoint{x, y};
|
||||
},
|
||||
stats, npoints);
|
||||
@@ -1368,7 +1374,7 @@ void ConvergenceGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
const mjSolverStat* stats =
|
||||
static_cast<const mjSolverStat*>(user_data);
|
||||
const float x = static_cast<float>(i);
|
||||
const float y = mju_log10(mju_max(mjMINVAL, stats[i].lineslope));
|
||||
const float y = mju_max(mjMINVAL, stats[i].lineslope);
|
||||
return ImPlotPoint{x, y};
|
||||
},
|
||||
stats, npoints);
|
||||
@@ -1380,6 +1386,9 @@ void ConvergenceGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
}
|
||||
|
||||
void CountsGui(const mjModel* model, mjData* data, ImVec2 plot_size) {
|
||||
ScopedStyle style;
|
||||
style.Font(ScopedFont::kMono);
|
||||
|
||||
int xlim = GetPlotXLimit(data);
|
||||
ImPlotFlags flags =
|
||||
ImPlot_SetupPlotFlags(plot_size) | ImPlotFlags_NoMouseText;
|
||||
@@ -1538,27 +1547,13 @@ void InfoGui(const mjModel* model, const mjData* data, bool paused,
|
||||
ImGui::Columns();
|
||||
}
|
||||
|
||||
void ProfilerGui(const mjModel* model, mjData* data, SimProfiler* profiler) {
|
||||
ImGui::SetWindowFontScale(0.8f);
|
||||
void ProfilerGui(const mjModel* model, mjData* data, SimProfiler* profiler, bool show_iter) {
|
||||
ImVec2 avail = ImGui::GetContentRegionAvail();
|
||||
const float pad = ImGui::GetStyle().ItemSpacing.x;
|
||||
const float aspect = avail.y > 0 ? avail.x / avail.y : 1.0f;
|
||||
|
||||
ImVec2 plot_size;
|
||||
int cols;
|
||||
if (aspect < 0.8f) {
|
||||
plot_size.x = avail.x;
|
||||
plot_size.y = (avail.y - pad * 3.0f) * 0.25f;
|
||||
cols = 1;
|
||||
} else if (aspect < 1.8f) {
|
||||
plot_size.x = (avail.x - pad) * 0.5f;
|
||||
plot_size.y = (avail.y - pad) * 0.5f;
|
||||
cols = 2;
|
||||
} else {
|
||||
plot_size.x = (avail.x - pad * 3.0f) * 0.25f;
|
||||
plot_size.y = avail.y;
|
||||
cols = 4;
|
||||
}
|
||||
|
||||
int current_col = 0;
|
||||
auto advance = [&]() {
|
||||
@@ -1570,23 +1565,52 @@ void ProfilerGui(const mjModel* model, mjData* data, SimProfiler* profiler) {
|
||||
}
|
||||
};
|
||||
|
||||
if (cols == 2) {
|
||||
// In 2x2 layout, vertically stack charts with the same x-axis.
|
||||
CountsGui(model, data, plot_size);
|
||||
advance();
|
||||
if (!show_iter) {
|
||||
if (aspect < 0.8f) {
|
||||
plot_size.x = avail.x;
|
||||
plot_size.y = (avail.y - pad) * 0.5f;
|
||||
cols = 1;
|
||||
} else {
|
||||
plot_size.x = (avail.x - pad) * 0.5f;
|
||||
plot_size.y = avail.y;
|
||||
cols = 2;
|
||||
}
|
||||
profiler->DimensionsGraph(plot_size);
|
||||
advance();
|
||||
ConvergenceGui(model, data, plot_size);
|
||||
advance();
|
||||
profiler->CpuTimeGraph(plot_size);
|
||||
} else {
|
||||
CountsGui(model, data, plot_size);
|
||||
advance();
|
||||
ConvergenceGui(model, data, plot_size);
|
||||
advance();
|
||||
profiler->DimensionsGraph(plot_size);
|
||||
advance();
|
||||
profiler->CpuTimeGraph(plot_size);
|
||||
if (aspect < 0.8f) {
|
||||
plot_size.x = avail.x;
|
||||
plot_size.y = (avail.y - pad * 3.0f) * 0.25f;
|
||||
cols = 1;
|
||||
} else if (aspect < 1.8f) {
|
||||
plot_size.x = (avail.x - pad) * 0.5f;
|
||||
plot_size.y = (avail.y - pad) * 0.5f;
|
||||
cols = 2;
|
||||
} else {
|
||||
plot_size.x = (avail.x - pad * 3.0f) * 0.25f;
|
||||
plot_size.y = avail.y;
|
||||
cols = 4;
|
||||
}
|
||||
|
||||
if (cols == 2) {
|
||||
// In 2x2 layout, vertically stack charts with the same x-axis.
|
||||
CountsGui(model, data, plot_size);
|
||||
advance();
|
||||
profiler->DimensionsGraph(plot_size);
|
||||
advance();
|
||||
ConvergenceGui(model, data, plot_size);
|
||||
advance();
|
||||
profiler->CpuTimeGraph(plot_size);
|
||||
} else {
|
||||
CountsGui(model, data, plot_size);
|
||||
advance();
|
||||
ConvergenceGui(model, data, plot_size);
|
||||
advance();
|
||||
profiler->DimensionsGraph(plot_size);
|
||||
advance();
|
||||
profiler->CpuTimeGraph(plot_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ void CountsGui(const mjModel* model, mjData* data,
|
||||
ImVec2 plot_size = ImVec2(-1, 0));
|
||||
|
||||
// UX for Profiler panel combining Solver and Performance metrics.
|
||||
void ProfilerGui(const mjModel* model, mjData* data, SimProfiler* profiler);
|
||||
void ProfilerGui(const mjModel* model, mjData* data, SimProfiler* profiler, bool show_iter);
|
||||
|
||||
// UX for displaying basic simulation information. Note that the pause state and
|
||||
// FPS needs to be tracked by the caller and passed here to be displayed.
|
||||
|
||||
@@ -126,6 +126,11 @@ T ReadIniValue(const KeyValues& key_values, const std::string& key, T def) {
|
||||
}
|
||||
}
|
||||
|
||||
enum class ScopedFont {
|
||||
kDefault = 0,
|
||||
kMono = 1,
|
||||
};
|
||||
|
||||
// Helper class for setting ImGui style options; automatically resets the
|
||||
// styles when going out of scope.
|
||||
struct ScopedStyle {
|
||||
@@ -143,6 +148,20 @@ struct ScopedStyle {
|
||||
void Swap(ScopedStyle& other) {
|
||||
std::swap(num_colors, other.num_colors);
|
||||
std::swap(num_vars, other.num_vars);
|
||||
std::swap(num_fonts, other.num_fonts);
|
||||
}
|
||||
|
||||
ScopedStyle& Font(int index) {
|
||||
ImFontAtlas* atlas = ImGui::GetIO().Fonts;
|
||||
if (atlas && index >= 0 && index < atlas->Fonts.Size) {
|
||||
ImGui::PushFont(atlas->Fonts[index]);
|
||||
++num_fonts;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedStyle& Font(ScopedFont font) {
|
||||
return Font(static_cast<int>(font));
|
||||
}
|
||||
|
||||
ScopedStyle& Color(ImGuiCol col, ImColor color) {
|
||||
@@ -172,14 +191,19 @@ struct ScopedStyle {
|
||||
ImVec4 CurrentColor(ImGuiCol col) { return ImGui::GetStyle().Colors[col]; }
|
||||
|
||||
void Reset() {
|
||||
for (int i = 0; i < num_fonts; ++i) {
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::PopStyleVar(num_vars);
|
||||
ImGui::PopStyleColor(num_colors);
|
||||
num_colors = 0;
|
||||
num_vars = 0;
|
||||
num_fonts = 0;
|
||||
}
|
||||
|
||||
int num_colors = 0;
|
||||
int num_vars = 0;
|
||||
int num_fonts = 0;
|
||||
};
|
||||
|
||||
// Helper for displaying rows of key/value pairs in an ImGui table.
|
||||
|
||||
@@ -314,7 +314,7 @@ void App::UpdatePhysics() {
|
||||
platform::StepControl::Status status =
|
||||
step_control_.Advance(model(), data());
|
||||
if (status == platform::StepControl::Status::kPaused) {
|
||||
// do nothing
|
||||
profiler_.Update(model(), data());
|
||||
} else if (status == platform::StepControl::Status::kOk) {
|
||||
stepped = true;
|
||||
// If we are adding to the history we didn't have a divergence error
|
||||
@@ -694,7 +694,15 @@ void App::HandleKeyboardEvents() {
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F2)) {
|
||||
ToggleWindow(tmp_.info);
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F3)) {
|
||||
ToggleWindow(tmp_.profiler);
|
||||
// Cycle through profiler views.
|
||||
if (!tmp_.profiler) {
|
||||
tmp_.profiler = true;
|
||||
tmp_.profiler_show_iter = false;
|
||||
} else if (!tmp_.profiler_show_iter) {
|
||||
tmp_.profiler_show_iter = true;
|
||||
} else {
|
||||
tmp_.profiler = false;
|
||||
}
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F6)) {
|
||||
vis_options_.frame = (vis_options_.frame + 1) % mjNFRAME;
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F7)) {
|
||||
@@ -949,7 +957,7 @@ void App::BuildGui() {
|
||||
if (tmp_.profiler) {
|
||||
if (ImGui::Begin("Profiler", &tmp_.profiler,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
platform::ProfilerGui(model(), data(), &profiler_);
|
||||
platform::ProfilerGui(model(), data(), &profiler_, tmp_.profiler_show_iter);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -2003,7 +2011,14 @@ void App::MainMenuGui() {
|
||||
ToggleWindow(tmp_.info);
|
||||
}
|
||||
if (ImGui::MenuItem("Profiler", "F3", tmp_.profiler)) {
|
||||
ToggleWindow(tmp_.profiler);
|
||||
if (!tmp_.profiler) {
|
||||
tmp_.profiler = true;
|
||||
tmp_.profiler_show_iter = false;
|
||||
} else if (!tmp_.profiler_show_iter) {
|
||||
tmp_.profiler_show_iter = true;
|
||||
} else {
|
||||
tmp_.profiler = false;
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ class App {
|
||||
bool help = false;
|
||||
bool info = false;
|
||||
bool profiler = false;
|
||||
bool profiler_show_iter = false;
|
||||
bool picture_in_picture = false;
|
||||
bool options_panel = true;
|
||||
bool toolbar = false;
|
||||
|
||||
Reference in New Issue
Block a user