17#include "frontend/GPUDisplayInfo.inc"
22#define GPUSETTINGS_ALL
47#include <unordered_map>
69 using keyLambdaEntry = std::tuple<uint16_t, std::string, uint32_t, configKeyCallback>;
83 std::vector<std::tuple<std::string, std::string, std::vector<int32_t>>>
helpTextEntries;
92 static constexpr std::string_view
possibleKeys =
" 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ#.:;>'^_";
94 template <
class T,
size_t I = 0>
97 if constexpr (std::is_same_v<std::tuple_element_t<I, std::remove_cv_t<
decltype(
configStructs)>>, T
GPUDisplay::*>) {
100 return configStructIndex<T, I + 1>();
117 template <
class T,
class M>
120 const T& obj = configStruct<T>(
display);
121 return rttiReverseId[configStructIndex<T>()][(
const char*)&(obj.*member) - (
const char*)&obj];
138 if (bindings.empty()) {
145 std::sort(keyCodes.begin(), keyCodes.end());
147 bound += (bound.empty() ?
"" :
"|") +
getKeyName(k);
149 keys += (
keys.empty() ?
"[" :
" [") + (bound.empty() ?
"N/A" : bound) +
"]";
158 return key < 0 ? std::vector<int32_t>() : std::vector<int32_t>{
key};
213#include "utils/qconfig_genrtti.inc"
218 const auto& [oldCfgH, oldCfgL, oldCfgR] = mOldCfg;
219 const bool changedH = memcmp((
void*)&oldCfgH, (
void*)&mCfgH,
sizeof(mCfgH)) != 0, changedL = memcmp((
void*)&oldCfgL, (
void*)&mCfgL,
sizeof(mCfgL)) != 0, changedR = memcmp((
void*)&oldCfgR, (
void*)&mCfgR,
sizeof(mCfgR)) != 0;
220 if (mAnimate && (changedH || changedL || changedR ||
mCfgC.resetScene.load())) {
224 mUpdateEventData =
true;
226 if (mCfgL.propagateTracks != 0 && !mTracksArePropagated) {
227 mUpdateVertexLists =
true;
229 if (changedL || changedR) {
230 mUpdateDrawCommands =
true;
232 if (oldCfgR.drawQualityMSAA != mCfgR.drawQualityMSAA || oldCfgR.drawQualityDownsampleFSAA != mCfgR.drawQualityDownsampleFSAA || oldCfgL.depthBuffer != mCfgL.depthBuffer || oldCfgR.screenshotScaleFactor != mCfgR.screenshotScaleFactor) {
233 mUpdateRenderPipeline =
true;
235 if (oldCfgL.depthBuffer != mCfgL.depthBuffer) {
236 mBackend->setDepthBuffer();
239 if (oldCfgR.drawQualityVSync != mCfgR.drawQualityVSync) {
240 mFrontend->
SetVSync(mCfgR.drawQualityVSync);
241 mBackend->SetVSync(mCfgR.drawQualityVSync);
243 if (oldCfgR.fullScreen != mCfgR.fullScreen) {
246 if (oldCfgR.maximized != mCfgR.maximized) {
249 if (oldCfgR.useGLIndirectDraw != mCfgR.useGLIndirectDraw) {
250 mUpdateEventData =
true;
252 if (oldCfgH.trackFilter != mCfgH.trackFilter) {
253 mUpdateTrackFilter =
true;
256 if (
mCfgC.showConsole != mConsoleShown) {
257 mConsoleShown =
mCfgC.showConsole;
259 mConsoleTimer.
Reset();
261 mConsoleTimer.
Start();
262 if (
mCfgC.showConsole) {
263 const bool shift = mFrontend->
mKeys[mFrontend->KEY_SHIFT];
264 std::fill(std::begin(mFrontend->
mKeys), std::end(mFrontend->
mKeys),
false);
265 mFrontend->
mKeys[mFrontend->KEY_SHIFT] = shift;
268 if (
mCfgO.applyToAllPoints && oldCfgL.animationMode != mCfgL.animationMode) {
269 for (
auto& p : mAnimationVectors) {
270 p.cfgL.animationMode = mCfgL.animationMode;
273 if (
mCfgC.animationPoints.selected >= 0 &&
mCfgC.animationPoints.selected < (
int32_t)mAnimationVectors.size()) {
274 mAnimationVectors[
mCfgC.animationPoints.selected].cfgL = mCfgL;
276 updateAnimationPointsGUI();
281 bool shifted =
key >=
'A' &&
key <=
'Z';
286 bool oldShift = mFrontend->
mKeys[mFrontend->KEY_SHIFT];
287 mFrontend->
mKeys[mFrontend->KEY_SHIFT] = shifted;
289 mFrontend->
mKeys[mFrontend->KEY_SHIFT] = oldShift;
292void GPUDisplayFrontend::HandleExternalGUIKeys()
301template <
typename... Args>
302void GPUDisplayFrontend::add_key_binding(Args&&... args)
305 static_assert(nKeys >= 1 && (
sizeof...(Args) == nKeys + 1 ||
sizeof...(Args) == nKeys + 2),
"add_key_binding needs at least one key, the help text, and optionally the keys to show in the help text");
306 auto argTuple = std::forward_as_tuple(args...);
308 std::vector<int32_t> bindings;
309 auto addKey = [&](
auto&
key) {
311 const std::string
name = mConfiguration->getKeyName(character);
314 throw std::runtime_error(
"Key [" +
name +
"] assigned twice in display frontend");
319 throw std::runtime_error(
"Key down mapping " + mConfiguration->keyMapNames[
id] +
" assigned twice in display frontend");
321 mKeyDownMap[
id] = character >=
'a' && character <=
'z' ? character +
'A' -
'a' : character;
324 const std::string& actionName = std::get<1>(
key);
325 const auto& mapNames = mConfiguration->keyMapNames;
326 if (mConfiguration->keyActionsNames.contains(actionName) || std::find(mapNames.begin(), mapNames.end(), actionName) != mapNames.end()) {
327 throw std::runtime_error(
"Key action " + actionName +
" defined twice in display frontend, or name of a key down mapping");
329 binding = mConfiguration->keyActions.size();
330 mConfiguration->keyActionsNames.emplace(actionName,
binding);
331 mConfiguration->keyActions.push_back({actionName, std::get<2>(
key), std::move(std::get<3>(
key))});
332 mConfiguration->currentActionKeys.emplace_back();
334 static_assert(
false,
"invalid code path");
336 mConfiguration->setKeyBinding(character,
binding);
337 bindings.emplace_back(
binding);
340 [&]<
size_t... I>(std::index_sequence<I...>) { (addKey(std::get<I>(argTuple)), ...); }(std::make_index_sequence<nKeys>());
341 if constexpr (
sizeof...(Args) == nKeys + 2) {
342 keys = std::get<nKeys + 1>(argTuple);
344 mConfiguration->helpTextEntries.emplace_back(std::move(
keys), std::get<nKeys>(argTuple), std::move(bindings));
348 guiType(
GPUDisplayGUIChannel::ElementType t, std::vector<std::pair<std::string, GPUDisplayGUIValue>>
c = {}, std::function<
GPUDisplayGUIChannel::Options()> o = {},
uint32_t l = 0,
int64_t b = 0,
double s = 0) :
type(
t), choices(
std::move(
c)), options(
std::move(o)), lines(l), bitMask(
b),
step(
s) {}
350 std::vector<std::pair<std::string, GPUDisplayGUIValue>>
choices;
357static std::vector<std::pair<std::string, GPUDisplayGUIValue>> guiSliderValues(std::initializer_list<GPUDisplayGUIValue>
values)
359 auto name = [](
const auto&
x) -> std::string {
360 if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(
x)>, std::string>) {
368 std::vector<std::pair<std::string, GPUDisplayGUIValue>>
retVal;
376static std::vector<std::pair<std::string, GPUDisplayGUIValue>> guiNamedChoices(
const T& names)
378 std::vector<std::pair<std::string, GPUDisplayGUIValue>>
retVal;
379 for (
const auto&
name : names) {
399 std::visit([&](
const auto&
v) {
400 using V = std::remove_cvref_t<
decltype(
v)>;
401 if constexpr (std::is_same_v<T, V>) {
403 }
else if constexpr (std::is_same_v<T, GPUDisplayMultiSliderValue> || std::is_same_v<V, GPUDisplayMultiSliderValue>) {
404 throw std::runtime_error(
"GUI value of a multi slider for another element type, or vice versa");
405 }
else if constexpr (std::is_same_v<T, std::string>) {
406 if constexpr (std::is_same_v<V, std::string>) {
411 }
else if constexpr (std::is_same_v<V, std::string>) {
412 dst =
static_cast<T
>(std::stod(
v));
414 dst =
static_cast<T
>(
v);
423 if constexpr (std::is_same_v<T, std::string>) {
425 }
else if constexpr (std::is_integral_v<T>) {
428 static_assert(std::is_floating_point_v<T>,
"Unsupported option type for the Qt GUI");
438 return toGUIValue(
v.load());
445template <
typename... Args>
446void GPUDisplayFrontend::add_gui_binding(Args&&... args)
448 constexpr size_t nElements = (0 + ... + std::is_same_v<std::remove_cvref_t<Args>,
guiElement>);
449 constexpr size_t nHorizontal = (0 + ... + std::is_same_v<std::remove_cvref_t<Args>,
bool>);
450 constexpr size_t nVertical = (0 + ... + std::is_same_v<std::remove_cvref_t<Args>,
guiVertical>);
451 static_assert(nElements >= 1 && nHorizontal <= 1 &&
sizeof...(Args) <= nElements + nHorizontal + nVertical + 1,
"add_gui_binding needs at least one GUI element, and optionally the description, the horizontal flag, and guiVertical between elements");
453 bool horizontal =
false;
454 auto getHorizontal = [&](
auto& arg) {
455 if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(arg)>,
bool>) {
459 (getHorizontal(args), ...);
460 auto addElement = [&](
auto&
element) {
465 set(std::get<int64_t>(
v) ? (current |
mask) : (current & ~
mask));
470 const uint32_t id = mConfiguration->guiElements.size();
471 auto& el = frame.
elements.emplace_back(
GPUDisplayGUIChannel::Element{.
name =
element.name, .description =
element.rttiIndex < mConfiguration->rttiEntries.size() ? mConfiguration->rttiEntries[
element.rttiIndex].description :
"", .rttiIndex =
element.rttiIndex, .type =
element.type.type, .id =
id, .isInteger = std::holds_alternative<int64_t>(
element.get(defaults)), .isString = std::holds_alternative<std::string>(
element.get(defaults)), .lines =
element.type.lines, .step =
element.type.step, .choices = std::move(
element.type.choices), .dynamicOptions = std::move(
element.type.options), .get =
element.get});
472 if (el.dynamicOptions && !((el.type == Type::SLIDER && el.choices.empty()) || el.type == Type::DROPDOWN)) {
473 throw std::runtime_error(
"GUI element " +
element.name +
": dynamic options only for sliders with range and dropdown menus");
475 if (el.type == Type::SLIDER && !el.dynamicOptions) {
476 if (
element.rttiIndex >= mConfiguration->rttiEntries.size()) {
477 throw std::runtime_error(
"GUI slider " +
element.name +
" needs an option with RTTI for min and max values");
479 const auto&
e = mConfiguration->rttiEntries[
element.rttiIndex];
480 if (
e.min.empty() ||
e.max.empty()) {
481 throw std::runtime_error(
"GUI slider " +
element.name +
": option " +
e.name +
" needs min and max values");
483 el.min = std::stod(
e.min);
484 el.max = std::stod(
e.max);
486 if (el.type == Type::TEXTBOX &&
element.rttiIndex < mConfiguration->rttiEntries.size() && !mConfiguration->rttiEntries[
element.rttiIndex].min.empty() && !mConfiguration->rttiEntries[
element.rttiIndex].max.empty()) {
487 el.min = std::stod(mConfiguration->rttiEntries[
element.rttiIndex].min);
488 el.max = std::stod(mConfiguration->rttiEntries[
element.rttiIndex].max);
491 if (el.step > 0 && !(el.type == Type::MULTI_SLIDER || (el.type == Type::SLIDER && el.choices.empty()))) {
492 throw std::runtime_error(
"GUI element " +
element.name +
": a step only for sliders with a range and multi sliders");
494 if (el.type == Type::MULTI_SLIDER && (!std::holds_alternative<GPUDisplayMultiSliderValue>(
element.get(defaults)) || el.step <= 0)) {
495 throw std::runtime_error(
"GUI multi slider " +
element.name +
" needs an option of type GPUDisplayMultiSliderValue and a step > 0");
497 if ((el.type == Type::RADIO_BUTTONS || el.type == Type::DROPDOWN) ? (el.choices.empty() && !el.dynamicOptions) : (!el.choices.
empty() && el.
type !=
Type::SLIDER)) {
498 throw std::runtime_error(
"GUI element " +
element.name +
": choices are needed for radio buttons and dropdown menus, and only allowed for them and sliders");
500 el.horizontal = horizontal;
501 mConfiguration->guiElements.emplace_back(GPUDisplayConfiguration::guiElementCallbacks{
element.rttiIndex, std::move(
element.set)});
503 auto addArg = [&](
auto& arg) {
504 if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(arg)>,
guiElement>) {
506 }
else if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(arg)>,
guiVertical>) {
507 horizontal = !arg.vertical;
508 }
else if constexpr (!std::is_same_v<std::remove_cvref_t<
decltype(arg)>,
bool>) {
513 mConfiguration->guiLayout.emplace_back(std::move(frame));
521 if (
id >= mConfiguration->guiElements.size()) {
524 const auto&
e = mConfiguration->guiElements[
id];
527 }
catch (
const std::exception& ex) {
528 GPUError(
"Invalid value from the GUI for element %u: %s",
id, ex.what());
531 if (
mDisplay->
mCfgO.guiPrintInfo &&
e.rttiIndex < mConfiguration->configInfos.size()) {
537const std::vector<std::string>& GPUDisplayFrontend::getHelpText()
539 if (!mConfiguration->helpTextUpToDate) {
540 mConfiguration->rebuildHelpText();
542 return mConfiguration->helpText;
545static std::pair<int32_t, uint16_t> keyOrder(
uint16_t k)
547 return {k >=
'0' && k <=
'9' ? 0
548 : k >=
'a' && k <=
'z' ? 1
549 : k >=
'A' && k <=
'Z' ? 2
556void GPUDisplayFrontend::listKeys(
const std::function<
void(
const std::string&)>&
print)
558 const auto& rtti = *mConfiguration;
559 std::vector<uint16_t> boundKeys;
560 for (
uint32_t k = 1; k < rtti.configKeys.size(); k++) {
562 boundKeys.emplace_back(k);
565 std::sort(boundKeys.begin(), boundKeys.end(), [](
uint16_t a,
uint16_t b) { return keyOrder(a) < keyOrder(b); });
566 std::vector<std::pair<std::string, int32_t>>
rows;
568 rows.emplace_back(
"[" + rtti.getKeyName(k) +
"]", rtti.configKeys[k]);
571 if (rtti.boundKeys(
binding).empty()) {
575 for (
uint32_t i = 0;
i < rtti.keyActions.size();
i++) {
581 size_t keyWidth = 0, nameWidth = 0;
583 keyWidth = std::max(keyWidth,
key.size());
584 nameWidth = std::max(nameWidth, rtti.bindingName(
binding).size());
586 print(
"Key bindings (key, action or key down mapping, option):");
588 const std::string
name = rtti.bindingName(
binding);
591 print(
" " +
key + std::string(keyWidth -
key.size() + 1,
' ') +
name + std::string(nameWidth -
name.size() + 1,
' ') +
option);
594 print(
"Key down mappings (id, name, key):");
597 snprintf(line,
sizeof(line),
" %2u %-28s %s",
i, rtti.keyMapNames[
i].c_str(), rtti.currentMappedKeys[
i] < 0 ?
"[N/A]" : (
"[" + rtti.getKeyName(rtti.currentMappedKeys[
i]) +
"]").c_str());
602void GPUDisplayFrontend::listConfig()
604 const auto& rtti = *mConfiguration;
605 std::vector<uint16_t> boundKeys, availableKeys;
606 for (
uint32_t k = 1; k < rtti.configKeys.size(); k++) {
608 const bool possible = base != KEY_SHIFT && ((base <
N_SPECIAL_KEYS && !rtti.keyNames[base].empty()) || (k < 256 && rtti.possibleKeys.find((
char)k) != std::string_view::npos));
610 boundKeys.emplace_back(k);
611 }
else if (possible) {
612 availableKeys.emplace_back(k);
615 std::sort(boundKeys.begin(), boundKeys.end(), [&](
uint16_t a,
uint16_t b) { return keyOrder(a) < keyOrder(b); });
616 std::sort(availableKeys.begin(), availableKeys.end(), [&](
uint16_t a,
uint16_t b) { return keyOrder(a) < keyOrder(b); });
619 GPUInfo(
"Display config options with RTTI (struct, option, type, default, in Qt GUI, keys):");
620 uint32_t nOptionsWithKey = 0, nOptionsInGUI = 0;
621 int32_t structWidth = 0, nameWidth = 0, typeWidth = 0, defaultWidth = 0;
622 for (
const auto&
e : rtti.rttiEntries) {
623 structWidth = std::max<int32_t>(structWidth,
e.configStruct.size());
624 nameWidth = std::max<int32_t>(nameWidth,
e.name.size());
625 typeWidth = std::max<int32_t>(typeWidth,
e.type.size());
626 defaultWidth = std::max<int32_t>(defaultWidth,
e.defaultValue.size());
628 for (
uint32_t i = 0;
i < rtti.rttiEntries.size();
i++) {
629 const auto&
e = rtti.rttiEntries[
i];
632 if (rtti.keyRTTIIndex(k) ==
i) {
633 keys += (
keys.empty() ?
"[" :
" [") + rtti.getKeyName(k) +
"]";
636 const bool inGUI = std::any_of(rtti.guiElements.begin(), rtti.guiElements.end(), [
i](
const auto&
g) { return g.rttiIndex == i; });
637 nOptionsWithKey += !
keys.empty();
638 nOptionsInGUI += inGUI;
639 GPUInfo(
" %-*s %-*s %-*s %-*s %-3s %s", structWidth,
e.configStruct.c_str(), nameWidth,
e.name.c_str(), typeWidth,
e.type.c_str(), defaultWidth,
e.defaultValue.c_str(), inGUI ?
"GUI" :
"---",
keys.c_str());
642 listKeys([](
const std::string& line) { GPUInfo(
"%s",
line.c_str()); });
644 static constexpr std::string_view availablePrefix =
"Available keys: ";
645 static constexpr size_t MAX_LINE_LENGTH = 240;
646 std::string available(availablePrefix);
648 const std::string
key =
"[" + rtti.getKeyName(k) +
"]";
649 if (available.size() > availablePrefix.size() && available.size() + 1 +
key.size() > MAX_LINE_LENGTH) {
650 GPUInfo(
"%s", available.c_str());
651 available.assign(availablePrefix.size(),
' ');
652 }
else if (available.size() > availablePrefix.size()) {
657 GPUInfo(
"%s", available.c_str());
659 GPUInfo(
"Help text:");
660 for (
const auto& line : getHelpText()) {
661 GPUInfo(
" %s",
line.c_str());
664 mConsole->printCommands([](
const std::string& line) { GPUInfo(
"%s",
line.c_str()); });
666 GPUInfo(
"%zu options with RTTI, %u of them with a key, %u in the Qt GUI, %zu bound keys, %zu available keys, %zu console commands", rtti.rttiEntries.size(), nOptionsWithKey, nOptionsInGUI, boundKeys.size(), availableKeys.size(), mConsole->mConsoleCommands.size());
670#include "GPUDisplayFrontendConfigKeys.inc"
671#include "GPUDisplayFrontendConfigInfo.inc"
672#include "GPUDisplayFrontendConfigQtGUI.inc"
673#include "GPUDisplayFrontendConfigConsole.inc"
675void GPUDisplay::buildConfig()
677 auto& rtti = mFrontend->mConfiguration;
680 rtti->unbindAllKeys();
682 rtti->keyNames.resize(rtti->configKeys.size());
683 rtti->keyMapNames.resize(GPUDisplayFrontend::KEY_MAP_MAX + 1);
684#define GPUDisplayFrontendAddKey(code, key) rtti->keyNames[code] = #key
685#define GPUDisplayFrontendKeyDownMap(code, key) rtti->keyMapNames[code] = #key
690 for (
uint32_t i = 0;
i < rtti->rttiEntries.size();
i++) {
691 const auto&
entry = rtti->rttiEntries[
i];
692 rtti->rttiReverseId[
entry.configStructIndex][
entry.offset] =
i;
697 rtti->configInfos.resize(rtti->rttiEntries.size());
698 for (
uint32_t i = 0;
i < rtti->rttiEntries.size();
i++) {
699 const auto&
e = rtti->rttiEntries[
i];
700 if (
e.message.empty()) {
703 if (!rtti->valueString(*
this,
i)) {
704 GPUError(
"No info message support for type %s of %s",
e.type.c_str(),
e.name.c_str());
707 rtti->configInfos[
i] = [
this,
i,
message =
e.message]() {
710 if (n < 0 || n >= (int32_t)
sizeof(
buffer)) {
711 GPUError(
"Info message too long: %s",
message.c_str());
719 mFrontend->buildConsoleCommands();
720 mFrontend->mConsole->mPrintToTerminal = mConfig.internal.consolePrintToTerminal;
721 rtti->buildHelpText();
731 const auto& action = mConfiguration->keyActions[
binding];
733 if (action.rttiIndex < mConfiguration->configInfos.size()) {
743 if (mConfiguration->configInfos[
index]) {
744 mConfiguration->configInfos[
index]();
746 const auto&
e = mConfiguration->rttiEntries[
index];
747 mDisplay->SetInfo(
"%s.%s changed to %s", mConfiguration->configStructNames[
e.configStructIndex].c_str(),
e.name.c_str(),
value->c_str());
753 if (
mCfgC.showConsole && !bypassConsole && mFrontend->mConfiguration->keyRTTIIndex(mFrontend->
shiftedKey(
key)) != mFrontend->mConfiguration->getRTTIIndex(*
this, &GPUDisplayControl::showConsole)) {
755 mFrontend->mConsole->handleConsoleKey(
key, mFrontend->
mKeys[mFrontend->KEY_SHIFT]);
759 const uint8_t originKey = mFrontend->
mKeyDownMap[mFrontend->KEY_MAP_FOCUS_ORIGIN], upKey = mFrontend->
mKeyDownMap[mFrontend->KEY_MAP_FOCUS_ORIENT_UP];
760 if (originKey && upKey && (
key >=
'a' &&
key <=
'z' ?
key +
'A' -
'a' :
key) == originKey) {
761 mFrontend->
mKeys[upKey] =
false;
770 if (
e.type ==
"std::string") {
771 const std::string*
str = std::get_if<std::string>(&
value);
773 return "string expected";
775 *(std::string*)
ptr = *
str;
778 if (
e.isVector ||
e.arraySize) {
779 return "unsupported type " +
e.type;
781 if (
e.type ==
"float") {
782 const double v = std::holds_alternative<int64_t>(
value) ? (double)std::get<int64_t>(
value) : (std::holds_alternative<double>(
value) ? std::get<double>(
value) : std::nan(
""));
784 return "number expected";
785 }
else if ((
e.min.size() &&
v < std::stod(
e.min)) || (
e.max.size() &&
v > std::stod(
e.max))) {
786 return "value out of range [" +
e.min +
", " +
e.max +
"]";
792 if (
const std::string*
str = std::get_if<std::string>(&
value)) {
793 if (
e.type !=
"bool" || (*
str !=
"true" && *
str !=
"false")) {
794 return "number expected";
797 }
else if (
const int64_t*
i = std::get_if<int64_t>(&
value)) {
800 return "integer expected";
802 if ((
e.min.size() &&
v < std::stoll(
e.min)) || (
e.max.size() &&
v > std::stoll(
e.max))) {
803 return "value out of range [" +
e.min +
", " +
e.max +
"]";
805 auto store = [&]<
class T>(
auto&&
assign) -> std::string {
806 if (
v < (int64_t)std::numeric_limits<T>::min() || (
v > 0 && (
uint64_t)
v > (
uint64_t)std::numeric_limits<T>::max())) {
807 return "value out of range of " +
e.type;
812 if (
e.type ==
"bool") {
813 return store.template operator()<
bool>([&](
bool x) { *(
bool*)
ptr =
x; });
814 }
else if (
e.type ==
"int8_t") {
816 }
else if (
e.type ==
"uint8_t") {
818 }
else if (
e.type ==
"int32_t") {
820 }
else if (
e.type ==
"uint32_t") {
822 }
else if (
e.type ==
"int64_t") {
823 return store.template operator()<int64_t>([&](int64_t
x) { *(int64_t*)
ptr =
x; });
824 }
else if (
e.type ==
"uint64_t") {
826 }
else if (
e.type ==
"GPUDisplayCopyableAtomic<int32_t>") {
828 }
else if (
e.type ==
"GPUDisplayCopyableAtomic<bool>") {
831 return "unsupported type " +
e.type;
836 const auto&
e = rttiEntries[
index];
837 const char*
ptr = configStructPtr(
display,
e.configStructIndex) +
e.offset;
838 if (
e.isVector ||
e.arraySize) {
840 }
else if (
e.type ==
"bool") {
842 }
else if (
e.type ==
"float") {
844 std::ostringstream
s;
845 s << std::setprecision(std::numeric_limits<float>::max_digits10) << *(
const float*)
ptr;
849 }
else if (
e.type ==
"int8_t") {
851 }
else if (
e.type ==
"uint8_t") {
853 }
else if (
e.type ==
"int32_t") {
855 }
else if (
e.type ==
"uint32_t") {
857 }
else if (
e.type ==
"int64_t") {
859 }
else if (
e.type ==
"uint64_t") {
861 }
else if (
e.type ==
"GPUDisplayCopyableAtomic<int32_t>") {
863 }
else if (
e.type ==
"GPUDisplayCopyableAtomic<bool>") {
865 }
else if (
e.type ==
"std::string") {
866 return *(
const std::string*)
ptr;
std::function< void(void *, const void *)> assign
unsigned short int uint16_t
std::vector< std::string > keys
std::function< void()> configKeyCallback
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual Show related Highlight grid Show only individual collision Color clusters belonging to track objects Set line Enable drawing TPC data Enable drawing TOF data Enable drawing magnetic field Set field line step count Invert colors configStandalone Heavy OpenGL display display_heavy Show tracks with ITS contribution Show tracks with TOF contribution Enable propagation of loopers Show clusters at nominal x of pad row for early transformed data Split CE tracks when they cross the central Mark clusters Mark adjacent clusters Hide rejected tracks Apply filter on tracks to be displayed Separate increase X h configStandalone Camera window renderer OpenGL display display_camera Orient the camera such that the y axis is always upwards Full Screen MultiSample Anti Downsampling Anti Enable Vertical Sync Target frame or if the backend cannot limit to the refresh Use OpenGL indirect draws to reduce number of draw calls Display h configStandalone Vulkan display display_vulkan Have uniform buffers in host accessible device memory h configStandalone Internal display display_internal Number of updates the Qt GUI may send ahead of the last one the display has before it waits for the display Opacity of the console background Number of console lines the history is shortened to this when it reaches twice the size Time in seconds an info message fades out after setInfoTime h OpenGL display display Font size Do not use Freetype for font auto
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder Print launch bounds used for RTC code as debugging option
double GetCurrentElapsedTime(bool reset=false)
std::variant< int64_t, double, std::string > consoleArg
std::mutex mExternalGUIKeyMutex
static constexpr uint32_t N_SPECIAL_KEYS
void requestMaximized(bool set)
void showConfigInfo(uint32_t index)
bool processKeyLambda(uint32_t key)
static constexpr uint32_t SPECIAL_KEYS_SHIFTED
uint32_t shiftedKey(uint32_t key) const
std::vector< int32_t > mExternalGUIKeys
std::array< uint8_t, KEY_MAP_MAX > mKeyDownMap
virtual void SetVSync(bool enable)=0
void requestFullScreen(bool set)
void HandleKey(uint8_t key, bool external=false, bool bypassConsole=false)
void HandleExternalGUIKey(int32_t key, bool bypassConsole=false)
void checkAndApplyConfigChanges()
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
GLenum GLsizei GLsizei GLint * values
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLsizei const GLchar * message
GLboolean GLboolean GLboolean GLboolean a
int32_t const char int32_t line
std::variant< int64_t, double, std::string, GPUDisplayMultiSliderValue > GPUDisplayGUIValue
std::string print_type(T val, bool precise=false)
std::tuple< std::vector< qConfigRTTIentry >, std::vector< std::string > > qConfigGenRTTI(const std::vector< std::string > *configStructs)
std::string to_string(gsl::span< T, Size > span)
std::function< void(const GPUDisplayGUIValue &)> set
configKeyCallback callback
static T & configStruct(GPUDisplay &display)
std::string setValue(GPUDisplay &display, uint32_t index, const GPUDisplayConsole::consoleArg &value)
std::string getKeyName(uint16_t key) const
static constexpr std::string_view possibleKeys
std::vector< keyAction > keyActions
std::string bindingName(int32_t binding) const
std::vector< std::string > keyNames
static char * configStructPtr(GPUDisplay &display, uint32_t index)
static constexpr int32_t KEY_UNBOUND
std::vector< int32_t > boundKeys(int32_t binding) const
static constexpr uint32_t INVALID_INDEX
std::vector< std::string > keyMapNames
std::vector< std::string > configStructNames
std::vector< std::string > helpText
static constexpr int32_t KEY_MAP_INDEX
static constexpr std::tuple configStructs
std::vector< guiElementCallbacks > guiElements
std::vector< std::tuple< std::string, std::string, std::vector< int32_t > > > helpTextEntries
std::vector< std::vector< int32_t > > currentActionKeys
std::tuple< uint8_t, uint8_t > keyDownMapEntry
std::optional< std::string > valueString(GPUDisplay &display, uint32_t index, bool precise=false) const
int32_t removeKeyBinding(uint32_t key)
uint32_t getRTTIIndex(GPUDisplay &display, M T::*member)
uint32_t keyRTTIIndex(uint32_t key) const
std::tuple< uint16_t, std::string, uint32_t, configKeyCallback > keyLambdaEntry
std::vector< std::vector< uint32_t > > rttiReverseId
std::unordered_map< std::string, uint32_t > keyActionsNames
std::vector< configKeyCallback > configInfos
void setKeyBinding(uint32_t key, int32_t binding)
std::vector< configRTTIExt > rttiEntries
static constexpr uint32_t configStructIndex()
std::vector< int32_t > currentMappedKeys
std::vector< GPUDisplayGUIChannel::Frame > guiLayout
std::array< int32_t, N_TOTAL_KEYS > configKeys
static bool isKeyMap(int32_t binding)
guiElement(std::string n, uint32_t i, guiType t, std::function< void(const GPUDisplayGUIValue &)> s, std::function< GPUDisplayGUIValue(const GPUDisplayGUIChannel::Settings &)> g)
std::function< void(const GPUDisplayGUIValue &)> set
std::function< GPUDisplayGUIValue(const GPUDisplayGUIChannel::Settings &)> get
std::vector< std::pair< std::string, GPUDisplayGUIValue > > choices
std::function< GPUDisplayGUIChannel::Options()> options
guiType(GPUDisplayGUIChannel::ElementType t, std::vector< std::pair< std::string, GPUDisplayGUIValue > > c={}, std::function< GPUDisplayGUIChannel::Options()> o={}, uint32_t l=0, int64_t b=0, double s=0)
GPUDisplayGUIChannel::ElementType type
std::vector< Element > elements
std::vector< Frame > layout
std::vector< ReadoutWindowData > rows