From 2af3978c6b08b2dfb83c10f6235e807af38a7b53 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 15 Oct 2026 15:52:02 +0200 Subject: [PATCH 1/4] GPU Display: Cleanup --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 7 ++--- .../Standalone/Benchmark/standalone.cxx | 1 + GPU/GPUTracking/display/GPUDisplay.h | 2 +- GPU/GPUTracking/display/GPUDisplayInterface.h | 3 +- .../display/frontend/GPUDisplayFrontend.cxx | 29 ++++++++++++------- .../display/frontend/GPUDisplayFrontend.h | 12 ++++---- .../frontend/GPUDisplayFrontendGlfw.cxx | 7 +---- .../display/frontend/GPUDisplayFrontendGlfw.h | 1 - .../frontend/GPUDisplayFrontendGlut.cxx | 2 +- .../frontend/GPUDisplayFrontendNone.cxx | 2 +- .../frontend/GPUDisplayFrontendWayland.cxx | 2 +- .../frontend/GPUDisplayFrontendWindows.cxx | 1 + .../frontend/GPUDisplayFrontendX11.cxx | 2 +- .../display/frontend/GPUDisplayKeys.cxx | 2 +- 15 files changed, 40 insertions(+), 34 deletions(-) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 47d769631449a..6110ff8eea44b 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -422,6 +422,7 @@ AddOption(debugOnFailureMaxSize, uint32_t, 0, "", 0, "Max size of existing dumps AddOption(debugOnFailureDirectory, std::string, ".", "", 0, "Target folder for debug / dump") AddOption(ROOTDumpFile, std::string, "gpudebug.root", "", 0, "File name for ROOT dump (default gpudebug.root)") AddOption(memoryStat, bool, false, "", 0, "Print memory statistics") +AddVariable(runsStandalone, bool, false) AddVariable(eventDisplay, o2::gpu::GPUDisplayFrontendInterface*, nullptr) AddSubConfig(GPUSettingsProcessingRTC, rtc) AddSubConfig(GPUSettingsProcessingRTCtechnical, rtctech) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 63bec89446d4e..f05ca6983e8ba 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -849,24 +849,23 @@ int32_t GPUChainTracking::RunChainFinalize() mEventDisplay->WaitTillEventShown(); - if (GetProcessingSettings().eventDisplay->EnableSendKey()) { + if (GetProcessingSettings().runsStandalone) { while (kbhit()) { getch(); } GPUInfo("Press key for next event!"); } - int32_t iKey; do { usleep(10000); - if (GetProcessingSettings().eventDisplay->EnableSendKey()) { + if (GetProcessingSettings().runsStandalone) { iKey = kbhit() ? getch() : 0; if (iKey == 27) { GetProcessingSettings().eventDisplay->setDisplayControl(2); } else if (iKey == 'n') { break; } else if (iKey) { - GetProcessingSettings().eventDisplay->sendKey(iKey); + GetProcessingSettings().eventDisplay->sendExternalGUIKey(iKey); } } } while (GetProcessingSettings().eventDisplay->getDisplayControl() == 0); diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index 5600191b1bc85..f92413318542f 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -760,6 +760,7 @@ int32_t main(int argc, char** argv) if (ReadConfiguration(argc, argv)) { return 1; } + configStandalone.proc.runsStandalone = true; eventsDir = std::string(configStandalone.absoluteEventsDir ? "" : "events/") + configStandalone.eventsDir + "/"; GPUSettingsDeviceBackend deviceSet; diff --git a/GPU/GPUTracking/display/GPUDisplay.h b/GPU/GPUTracking/display/GPUDisplay.h index cb8bbce8bfc4f..c0bfcd7ddecf2 100644 --- a/GPU/GPUTracking/display/GPUDisplay.h +++ b/GPU/GPUTracking/display/GPUDisplay.h @@ -60,7 +60,7 @@ class GPUDisplay : public GPUDisplayInterface void HandleKey(uint8_t key); int32_t DrawGLScene(); - void HandleSendKey(int32_t key); + void HandleExternalGUIKey(int32_t key); int32_t InitDisplay(bool initFailure = false); void ResizeScene(int32_t width, int32_t height, bool init = false); diff --git a/GPU/GPUTracking/display/GPUDisplayInterface.h b/GPU/GPUTracking/display/GPUDisplayInterface.h index 5f5a101233191..aabc1c25b75e1 100644 --- a/GPU/GPUTracking/display/GPUDisplayInterface.h +++ b/GPU/GPUTracking/display/GPUDisplayInterface.h @@ -57,10 +57,9 @@ class GPUDisplayFrontendInterface virtual ~GPUDisplayFrontendInterface(); static GPUDisplayFrontendInterface* getFrontend(const char* type); virtual void StopDisplay() = 0; - virtual bool EnableSendKey() = 0; virtual int32_t getDisplayControl() const = 0; virtual void setDisplayControl(int32_t v) = 0; - virtual void sendKey(int32_t v) = 0; + virtual void sendExternalGUIKey(int32_t v) = 0; virtual const char* frontendName() const = 0; protected: diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx index 1a2b5e0932d40..0655a995451cf 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx @@ -85,7 +85,7 @@ void GPUDisplayFrontend::waitForFPSLimit() mNextFrameTime = now; return; } - const auto period = std::chrono::duration_cast(std::chrono::duration(1. / cfg.fpsRate)); + const auto period = std::chrono::duration_cast(std::chrono::duration(1. / cfg.fpsRate)); // TODO: wake up on HasExternalGUISignals mNextFrameTime += period; if (mNextFrameTime < now - period) { // More than one frame behind (slow rendering, first frame), do not try to catch up mNextFrameTime = now; @@ -93,19 +93,29 @@ void GPUDisplayFrontend::waitForFPSLimit() std::this_thread::sleep_until(mNextFrameTime); } -void GPUDisplayFrontend::HandleSendKeys() +void GPUDisplayFrontend::HandleExternalGUISignals() { - std::lock_guard lock(mSendKeyMutex); - for (auto key : mSendKeys) { - mDisplay->HandleSendKey(key); + HandleExternalGUIKeys(); +} + +bool GPUDisplayFrontend::HasExternalGUISignals() const +{ + +} + +void GPUDisplayFrontend::HandleExternalGUIKeys() +{ + std::lock_guard lock(mExternalGUIKeyMutex); + for (auto key : mExternalGUIKeys) { + mDisplay->HandleExternalGUIKey(key); } - mSendKeys.clear(); + mExternalGUIKeys.clear(); } -void GPUDisplayFrontend::sendKey(int32_t v) +void GPUDisplayFrontend::sendExternalGUIKey(int32_t v) { - std::lock_guard lock(mSendKeyMutex); - mSendKeys.emplace_back(v); + std::lock_guard lock(mExternalGUIKeyMutex); + mExternalGUIKeys.emplace_back(v); } void GPUDisplayFrontend::HandleKey(uint8_t key) { mDisplay->HandleKey(key); } @@ -124,7 +134,6 @@ void GPUDisplayFrontend::ExitDisplay() stopGUI(); mGUI.reset(nullptr); } -bool GPUDisplayFrontend::EnableSendKey() { return true; } void GPUDisplayFrontend::stopGUI() { diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h index bc38c1b29a57d..c0f8d533064a0 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h @@ -57,7 +57,6 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface virtual void ToggleMaximized(bool set) = 0; // Maximize window virtual void SetVSync(bool enable) = 0; // Enable / disable vsync virtual bool canSetVSync() { return false; } // OpenGL: swap interval can be set - bool EnableSendKey() override; // Request external keys (e.g. from terminal) virtual void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) = 0; // Print text on the display (needs the backend to build the font) GPUDisplayBackend* backend(); static GPUDisplayFrontend* getFrontend(const char* type); @@ -69,7 +68,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface int32_t getDisplayControl() const override { return mDisplayControl; } void setDisplayControl(int32_t v) override { mDisplayControl = v; } - void sendKey(int32_t v) override; + void sendExternalGUIKey(int32_t v) override; frontendTypes frontendType() const { return mFrontendType; } const char* frontendName() const override { return mFrontendName; } @@ -121,8 +120,8 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface // volatile variables to exchange control informations between display and backend volatile int32_t mDisplayControl = 0; // Control for next event (=1) or quit (=2) volatile int32_t mNeedUpdate = 0; // flag that backend shall update the GL window, and call DrawGLScene - std::mutex mSendKeyMutex; - std::vector mSendKeys; // Keys sent by external entity (usually console), may be ignored by backend. + std::mutex mExternalGUIKeyMutex; + std::vector mExternalGUIKeys; // Keys sent by external entity (usually console), may be ignored by backend. std::mutex mExitStateMutex; // Keyboard / Mouse actions @@ -151,7 +150,8 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface void HandleKey(uint8_t key); // Callback for handling key presses int32_t DrawGLScene(); // Callback to draw the GL scene - void HandleSendKeys(); // Optional callback to handle key press from external source (e.g. stdin by default) + void HandleExternalGUISignals(); // Callback to handle signals from external GUIs + bool HasExternalGUISignals() const; // Returns whether there are currently pending signals from external GUIs to be handled void ResizeScene(int32_t width, int32_t height); // Callback when GL window is resized int32_t InitDisplay(bool initFailure = false); // Callback to initialize the GL Display (to be called in StartDisplay) void ExitDisplay(); // Callback to clean up the GL Display @@ -160,6 +160,8 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface void setWindowState(bool fullScreen, bool maximized); // Sync the settings if the window manager changed the window state void focusLost(); // Release all keys and mouse buttons when the window loses focus, since the release events go to another window void applyInitialWindowState(); // Switch to fullscreen / maximize at startup according to the settings + private: + void HandleExternalGUIKeys(); }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx index 49566fa690340..ac61ddacdd0f6 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx @@ -326,7 +326,7 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain() int32_t retVal = 0; while (!glfwWindowShouldClose(mWindow)) { - HandleSendKeys(); + HandleExternalGUISignals(); if (DrawGLScene()) { fprintf(stderr, "Error drawing GL scene\n"); retVal = 1; @@ -398,11 +398,6 @@ void GPUDisplayFrontendGlfw::SetVSync(bool enable) bool GPUDisplayFrontendGlfw::canSetVSync() { return backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL; } -bool GPUDisplayFrontendGlfw::EnableSendKey() -{ - return true; -} - float GPUDisplayFrontendGlfw::getRefreshRate() { GLFWmonitor* monitor = glfwGetWindowMonitor(mWindow) ? glfwGetWindowMonitor(mWindow) : glfwGetPrimaryMonitor(); // Monitor of a windowed window is not known, use the primary one diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h index 274b08ca33d99..f079c87852e13 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h @@ -32,7 +32,6 @@ class GPUDisplayFrontendGlfw : public GPUDisplayFrontend void ToggleMaximized(bool set) override; void SetVSync(bool enable) override; void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override; - bool EnableSendKey() override; void getSize(int32_t& width, int32_t& height) override; float getDisplayScale() const override { return mScale; } float getRefreshRate() override; diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx index 445f1e40bb22b..368a86413194c 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlut.cxx @@ -45,7 +45,7 @@ void GPUDisplayFrontendGlut::displayFunc() // TODO: Functions should be lambdas, void GPUDisplayFrontendGlut::glutLoopFunc() { - me->HandleSendKeys(); + me->HandleExternalGUISignals(); displayFunc(); } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.cxx index 73bba8c9458aa..5d5748e13349a 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendNone.cxx @@ -28,9 +28,9 @@ int32_t GPUDisplayFrontendNone::FrontendMain() return 1; } do { + HandleExternalGUISignals(); DrawGLScene(); waitForFPSLimit(); - HandleSendKeys(); } while (mDisplayControl != 2); return 0; } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx index 264a8e9dabece..66701557a8068 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWayland.cxx @@ -611,8 +611,8 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() if (mDisplayControl == 2) { break; } - HandleSendKeys(); handleKeyRepeat(); + HandleExternalGUISignals(); if (!mSuspended) { // Window not visible, compositor would not release swapchain images DrawGLScene(); } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx index 14a65e6634476..80537c15c4700 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendWindows.cxx @@ -352,6 +352,7 @@ int32_t GPUDisplayFrontendWindows::FrontendMain() DispatchMessage(&msg); // Dispatch The Message } } else { + HandleExternalGUISignals(); if (active) // Program Active? { if (mKeys[VK_ESCAPE]) { diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx index 42de509f47ebf..a06f75d094cda 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx @@ -358,7 +358,6 @@ int32_t GPUDisplayFrontendX11::FrontendMain() if (mDisplayControl == 2) { break; } - HandleSendKeys(); if (!XPending(mXDisplay)) { event.type = Expose; } else { @@ -455,6 +454,7 @@ int32_t GPUDisplayFrontendX11::FrontendMain() break; } + HandleExternalGUISignals(); DrawGLScene(); if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) { glXSwapBuffers(mXDisplay, mWindow); diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx index 97d2cd17e3faa..537f511766595 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx @@ -534,7 +534,7 @@ void GPUDisplay::HandleKey(uint8_t key) } } -void GPUDisplay::HandleSendKey(int32_t key) +void GPUDisplay::HandleExternalGUIKey(int32_t key) { // GPUError("key %d '%c'", key, (char) key); From d7c38e71d07997743b45a9590512c8f8faabefd7 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 15 Oct 2026 17:58:46 +0200 Subject: [PATCH 2/4] GPU Display GUI: First version of protocol to send updates between frontend and GUI --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 2 + GPU/GPUTracking/display/CMakeLists.txt | 1 + GPU/GPUTracking/display/GPUDisplay.h | 5 +- .../display/frontend/GPUDisplayFrontend.cxx | 59 ++++++- .../display/frontend/GPUDisplayFrontend.h | 9 +- .../display/frontend/GPUDisplayGUI.cxx | 132 +++++++++++++++- .../display/frontend/GPUDisplayGUI.h | 29 +++- .../display/frontend/GPUDisplayGUI.ui | 55 +++++-- .../display/frontend/GPUDisplayGUIChannel.h | 63 ++++++++ .../display/frontend/GPUDisplayGUIWrapper.cxx | 146 +++++++----------- .../display/frontend/GPUDisplayGUIWrapper.h | 7 +- .../display/frontend/GPUDisplayKeys.cxx | 17 +- 12 files changed, 394 insertions(+), 131 deletions(-) create mode 100644 GPU/GPUTracking/display/frontend/GPUDisplayGUIChannel.h diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 6110ff8eea44b..fa560ec535313 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -532,6 +532,8 @@ AddOption(noFreetype, bool, false, "", 0, "Do not use Freetype for font renderin AddOption(displayRenderer, std::string, "auto", "renderer", 0, "Renderer for event display: opengl | vulkan | auto") AddOption(displayFrontend, std::string, "auto", "displayFrontend", 0, "Frontend to use for event display: auto | win32 | x11 | glut | glfw | wayland") AddOptionVec(filterMacros, std::string, "", 0, "ROOT macros used as track filter") +AddOption(guiReplyTimeout, uint32_t, 100, "", 0, "Time in ms the Qt GUI waits at most for the display to process its update") +AddOption(guiMaxUpdatesAhead, uint32_t, 3, "", 0, "Number of updates the Qt GUI may send ahead of the last one the display has processed, before it waits for the display") AddSubConfig(GPUSettingsDisplayLight, light) AddSubConfig(GPUSettingsDisplayHeavy, heavy) AddSubConfig(GPUSettingsDisplayRenderer, renderer) diff --git a/GPU/GPUTracking/display/CMakeLists.txt b/GPU/GPUTracking/display/CMakeLists.txt index ce24228f2d134..9edefc19a072c 100644 --- a/GPU/GPUTracking/display/CMakeLists.txt +++ b/GPU/GPUTracking/display/CMakeLists.txt @@ -174,6 +174,7 @@ if(GPUCA_EVENT_DISPLAY_QT) set(SRCS ${SRCS} frontend/GPUDisplayGUI.cxx frontend/GPUDisplayGUIWrapper.cxx) set(SRCS_NO_H ${SRCS_NO_H} ${GPUCA_QT_MOC_SRCS} ${GPUCA_QT_UI_HDRS}) + set(HDRS_INSTALL ${HDRS_INSTALL} frontend/GPUDisplayGUIChannel.h) endif() string(REPLACE ".cxx" ".h" HDRS "${SRCS}") diff --git a/GPU/GPUTracking/display/GPUDisplay.h b/GPU/GPUTracking/display/GPUDisplay.h index c0bfcd7ddecf2..67ab1a10334c9 100644 --- a/GPU/GPUTracking/display/GPUDisplay.h +++ b/GPU/GPUTracking/display/GPUDisplay.h @@ -58,11 +58,12 @@ class GPUDisplay : public GPUDisplayInterface void UpdateCalib(const GPUCalibObjectsConst* calib) override { mCalib = calib; } void UpdateParam(const GPUParam* param) override { mParam = param; } - void HandleKey(uint8_t key); + void HandleKey(uint8_t key, bool doNotHandleConfigChanges = false); // With doNotHandleConfigChanges, the caller must call checkAndApplyConfigChanges int32_t DrawGLScene(); - void HandleExternalGUIKey(int32_t key); + void HandleExternalGUIKey(int32_t key); // Does not handle config changes, see HandleKey int32_t InitDisplay(bool initFailure = false); void ResizeScene(int32_t width, int32_t height, bool init = false); + void checkAndApplyConfigChanges(const GPUSettingsDisplayHeavy& oldCfgH, const GPUSettingsDisplayLight& oldCfgL, const GPUSettingsDisplayRenderer& oldCfgR); // Set update flags / apply the settings that changed compared to the old copies const GPUSettingsDisplayRenderer& cfgR() const { return mCfgR; } const GPUSettingsDisplayLight& cfgL() const { return mCfgL; } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx index 0655a995451cf..b48d7f6c59d5c 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.cxx @@ -38,12 +38,14 @@ GPUDisplayFrontend* createGPUDisplayFrontendWayland(); #endif #include "GPUDisplayFrontendNone.h" +#include "GPUDisplayGUIChannel.h" #include "GPULogging.h" #include #include #include #include #include +#include #ifdef GPUCA_BUILD_EVENT_DISPLAY_QT #include "GPUDisplayGUIWrapper.h" @@ -58,6 +60,7 @@ class GPUDisplayGUIWrapper using namespace o2::gpu; +GPUDisplayFrontend::GPUDisplayFrontend() = default; GPUDisplayFrontend::~GPUDisplayFrontend() = default; void* GPUDisplayFrontend::FrontendThreadWrapper(void* ptr) @@ -95,21 +98,57 @@ void GPUDisplayFrontend::waitForFPSLimit() void GPUDisplayFrontend::HandleExternalGUISignals() { - HandleExternalGUIKeys(); + const GPUSettingsDisplayHeavy oldCfgH = mDisplay->mCfgH; + const GPUSettingsDisplayLight oldCfgL = mDisplay->mCfgL; + const GPUSettingsDisplayRenderer oldCfgR = mDisplay->mCfgR; + bool changes = HandleExternalGUIKeys(); + + const bool gui = isGUIRunning(); + std::optional update; + if (gui) { + std::lock_guard lock(mGUIChannel->mutex); + update = std::exchange(mGUIChannel->update, std::nullopt); + mGUIChannel->displayProcessingCurrentUpdate = update && mGUIChannel->guiSleeping; // GUI waits for the reply when it wakes up + } + if (update) { + for (int32_t key : update->keys) { + mDisplay->HandleExternalGUIKey(key); + } + if (update->lineWidth) { + mDisplay->mCfgL.lineWidth = *update->lineWidth; + } + changes = true; + } + + if (changes) { + mDisplay->checkAndApplyConfigChanges(oldCfgH, oldCfgL, oldCfgR); + } + if (gui) { + { + std::lock_guard lock(mGUIChannel->mutex); + mGUIChannel->state.cfg = {mDisplay->mCfgH, mDisplay->mCfgL, mDisplay->mCfgR}; + if (update) { + mGUIChannel->state.appliedUpdate = update->id; + } + mGUIChannel->state.counter++; + mGUIChannel->displayProcessingCurrentUpdate = false; + } + mGUIChannel->stateUpdated.notify_all(); + } } bool GPUDisplayFrontend::HasExternalGUISignals() const { - + return mExternalGUIKeys.size(); } -void GPUDisplayFrontend::HandleExternalGUIKeys() +bool GPUDisplayFrontend::HandleExternalGUIKeys() { std::lock_guard lock(mExternalGUIKeyMutex); for (auto key : mExternalGUIKeys) { mDisplay->HandleExternalGUIKey(key); } - mExternalGUIKeys.clear(); + return !std::exchange(mExternalGUIKeys, {}).empty(); } void GPUDisplayFrontend::sendExternalGUIKey(int32_t v) @@ -149,9 +188,19 @@ int32_t GPUDisplayFrontend::startGUI() int32_t retVal = 1; #ifdef GPUCA_BUILD_EVENT_DISPLAY_QT if (!mGUI) { - mGUI.reset(new GPUDisplayGUIWrapper); + mGUIChannel = std::make_unique(); + mGUI = std::make_unique(*mGUIChannel); } if (!mGUI->isRunning()) { + { + std::lock_guard lock(mGUIChannel->mutex); + mGUIChannel->update.reset(); + mGUIChannel->state = {}; + mGUIChannel->guiSleeping = mGUIChannel->displayProcessingCurrentUpdate = mGUIChannel->stop = false; + mGUIChannel->replyTimeout = std::chrono::milliseconds(mDisplay->cfg().guiReplyTimeout); + mGUIChannel->maxUpdatesAhead = std::max(mDisplay->cfg().guiMaxUpdatesAhead, 1); // 0 would block all updates + mGUIChannel->windowName = DISPLAY_WINDOW_NAME; + } mGUI->start(); } else { mGUI->focus(); diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h index c0f8d533064a0..1bfbc36883f41 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayFrontend.h @@ -28,13 +28,15 @@ class GPUReconstruction; class GPUDisplay; class GPUDisplayBackend; class GPUDisplayGUIWrapper; +struct GPUDisplayGUIChannel; class GPUDisplayFrontend : public GPUDisplayFrontendInterface { friend class GPUDisplay; + friend class GPUDisplayGUI; // Key codes public: - GPUDisplayFrontend() = default; + GPUDisplayFrontend(); ~GPUDisplayFrontend() override; enum frontendTypes { @@ -101,7 +103,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface static constexpr int32_t KEY_ENTER = 13; // fixed at 13 static constexpr int32_t KEY_F1 = 14; static constexpr int32_t KEY_F2 = 15; - static constexpr int32_t KEY_F3 = 26; + static constexpr int32_t KEY_F3 = 16; static constexpr int32_t KEY_F4 = 17; static constexpr int32_t KEY_F5 = 18; static constexpr int32_t KEY_F6 = 19; @@ -146,6 +148,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface const char* mFrontendName = nullptr; volatile bool mDisplayRunning = false; + std::unique_ptr mGUIChannel; // Must outlive mGUI std::unique_ptr mGUI; void HandleKey(uint8_t key); // Callback for handling key presses @@ -161,7 +164,7 @@ class GPUDisplayFrontend : public GPUDisplayFrontendInterface void focusLost(); // Release all keys and mouse buttons when the window loses focus, since the release events go to another window void applyInitialWindowState(); // Switch to fullscreen / maximize at startup according to the settings private: - void HandleExternalGUIKeys(); + bool HandleExternalGUIKeys(); // Returns whether keys were handled, config changes are not handled }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.cxx index f02fd7914de0b..93a5caa2fa4dd 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.cxx @@ -13,22 +13,140 @@ /// \author David Rohr #include "GPUDisplayGUI.h" -#include "GPUDisplayGUIWrapper.h" +#include "GPUDisplayFrontend.h" #include "ui_GPUDisplayGUI.h" +#include +#include + +#include +#include + using namespace o2::gpu; -GPUDisplayGUI::GPUDisplayGUI(QWidget* parent) : QMainWindow(parent), ui(new Ui::GPUDisplayGUI) +GPUDisplayGUI::GPUDisplayGUI(GPUDisplayGUIChannel& channel, QWidget* parent) : QMainWindow(parent), mUi(std::make_unique()), mChannel(channel) +{ + mUi->setupUi(this); + { + std::lock_guard lock(mChannel.mutex); + setWindowTitle(QString::fromStdString(mChannel.windowName + " GUI")); + } + connect(mUi->lineWidthSlider, &QSlider::valueChanged, this, [this](int32_t value) { + mUpdate.lineWidth = value * 0.1f; + mUi->lineWidthValue->setNum(*mUpdate.lineWidth); + }); + connect(&mTimer, &QTimer::timeout, this, &GPUDisplayGUI::timerTick); + mTimer.start(std::chrono::milliseconds(10)); +} + +GPUDisplayGUI::~GPUDisplayGUI() = default; + +void GPUDisplayGUI::timerTick() +{ + std::unique_lock lock(mChannel.mutex); + mChannel.guiSleeping = false; + if (mUpdate.empty()) { // Display processes the update we went to sleep with, wait for the reply (with new changes we would not apply it anyway) + mChannel.stateUpdated.wait_for(lock, mChannel.replyTimeout, [this] { return !mChannel.displayProcessingCurrentUpdate || mChannel.stop; }); + } + if (!mUpdate.empty() && mLastSentId - mLastAppliedId >= mChannel.maxUpdatesAhead) { // Too far ahead of the display, wait for the reply to the last update + mChannel.stateUpdated.wait_for(lock, mChannel.replyTimeout, [this] { return mChannel.state.appliedUpdate == mLastSentId || mChannel.stop; }); + } + if (mChannel.stop) { + lock.unlock(); + close(); + return; + } + + const bool newState = mChannel.state.counter != mState.counter; + if (newState) { + mState = mChannel.state; + if (mState.appliedUpdate == mLastSentId) { + mLastAppliedId = mLastSentId; + } + } + const bool apply = newState && mUpdate.empty() && mState.appliedUpdate == mLastSentId; // State contains all our updates, and we have no unsent changes + if (!mUpdate.empty() && mLastSentId - mLastAppliedId < mChannel.maxUpdatesAhead) { + if (mChannel.update) { // Previous update not yet picked up by the display, merge + auto& update = *mChannel.update; + update.keys.insert(update.keys.end(), mUpdate.keys.begin(), mUpdate.keys.end()); + if (mUpdate.lineWidth) { + update.lineWidth = mUpdate.lineWidth; + } + } else { + mChannel.update = std::move(mUpdate); + } + mChannel.update->id = ++mLastSentId; + mChannel.guiSleeping = true; + mUpdate = {}; + } + lock.unlock(); + + if (apply) { + applySettings(); + } +} + +void GPUDisplayGUI::applySettings() +{ + const QSignalBlocker blocker(mUi->lineWidthSlider); // Not a user change + mUi->lineWidthSlider->setValue(std::lround(mState.cfg.cfgL.lineWidth * 10.f)); + mUi->lineWidthValue->setNum(mState.cfg.cfgL.lineWidth); +} + +void GPUDisplayGUI::bringToFront() { - ui->setupUi(this); + setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); + show(); + raise(); + activateWindow(); } -GPUDisplayGUI::~GPUDisplayGUI() +void GPUDisplayGUI::keyPressEvent(QKeyEvent* event) { - delete ui; + const int32_t key = translateKey(event); + if (key < 0) { + QMainWindow::keyPressEvent(event); + return; + } + mUpdate.keys.emplace_back(key); } -void GPUDisplayGUI::UpdateTimer() +int32_t GPUDisplayGUI::translateKey(const QKeyEvent* event) { - mWrapper->UpdateTimer(); + switch (event->key()) { + case Qt::Key_Up: + return GPUDisplayFrontend::KEY_UP; + case Qt::Key_Down: + return GPUDisplayFrontend::KEY_DOWN; + case Qt::Key_Left: + return GPUDisplayFrontend::KEY_LEFT; + case Qt::Key_Right: + return GPUDisplayFrontend::KEY_RIGHT; + case Qt::Key_PageUp: + return GPUDisplayFrontend::KEY_PAGEUP; + case Qt::Key_PageDown: + return GPUDisplayFrontend::KEY_PAGEDOWN; + case Qt::Key_Home: + return GPUDisplayFrontend::KEY_HOME; + case Qt::Key_End: + return GPUDisplayFrontend::KEY_END; + case Qt::Key_Insert: + return GPUDisplayFrontend::KEY_INSERT; + case Qt::Key_Escape: + return GPUDisplayFrontend::KEY_ESCAPE; + case Qt::Key_Return: + case Qt::Key_Enter: + return GPUDisplayFrontend::KEY_ENTER; + default: + break; + } + if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F12) { + static_assert(GPUDisplayFrontend::KEY_F12 - GPUDisplayFrontend::KEY_F1 == Qt::Key_F12 - Qt::Key_F1); + return GPUDisplayFrontend::KEY_F1 + (event->key() - Qt::Key_F1); + } + const QString text = event->text(); + if (text.size() == 1 && text[0].unicode() >= 32 && text[0].unicode() < 127) { // Printable ASCII, with shift applied + return text[0].unicode(); + } + return -1; } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.h b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.h index 95e7718f6e520..e0da6423e94d2 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.h @@ -20,7 +20,12 @@ { #define QT_END_NAMESPACE } +#include "GPUDisplayGUIChannel.h" #include +#include +#include + +class QKeyEvent; QT_BEGIN_NAMESPACE namespace Ui @@ -31,22 +36,30 @@ QT_END_NAMESPACE namespace o2::gpu { -class GPUDisplayGUIWrapper; class GPUDisplayGUI : public QMainWindow { Q_OBJECT public: - GPUDisplayGUI(QWidget* parent = nullptr); - ~GPUDisplayGUI(); - void setWrapper(GPUDisplayGUIWrapper* w) { mWrapper = w; } + explicit GPUDisplayGUI(GPUDisplayGUIChannel& channel, QWidget* parent = nullptr); + ~GPUDisplayGUI() override; + void bringToFront(); - private slots: - void UpdateTimer(); + protected: + void keyPressEvent(QKeyEvent* event) override; private: - Ui::GPUDisplayGUI* ui; - GPUDisplayGUIWrapper* mWrapper; + void timerTick(); // Exchange updates / settings with the display + void applySettings(); + static int32_t translateKey(const QKeyEvent* event); // Qt key → display key code, -1 if not forwarded + + std::unique_ptr mUi; + QTimer mTimer; + GPUDisplayGUIChannel& mChannel; + GPUDisplayGUIChannel::Update mUpdate; // Changes collected since the last tick + GPUDisplayGUIChannel::State mState; // Last state received from the display + uint64_t mLastSentId = 0; // Id of the last update sent + uint64_t mLastAppliedId = 0; // Id of the last update for which the display state was received }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.ui b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.ui index 6f4bcd6dbad32..77b2a7401be11 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayGUI.ui +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUI.ui @@ -13,17 +13,52 @@ GPUDisplayGUI - - - - - 0 - 0 - 899 - 38 - - + + + + + + + + Line width + + + + + + + 1 + + + 50 + + + Qt::Orientation::Horizontal + + + + + + + + 40 + 0 + + + + + + + + + + Qt::Orientation::Vertical + + + + + diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUIChannel.h b/GPU/GPUTracking/display/frontend/GPUDisplayGUIChannel.h new file mode 100644 index 0000000000000..cf24951477d0a --- /dev/null +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUIChannel.h @@ -0,0 +1,63 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUDisplayGUIChannel.h +/// \author David Rohr + +#ifndef GPUDISPLAYGUICHANNEL_H +#define GPUDISPLAYGUICHANNEL_H + +#include "GPUSettings.h" +#include +#include +#include +#include +#include +#include +#include + +namespace o2::gpu +{ +// Communication between the Qt GUI thread (GPUDisplayGUI) and the display thread (GPUDisplayFrontend::HandleExternalGUISignals), Qt-free. +// The GUI sends at most one update per timer tick, the display processes it once per frame and publishes the complete settings with the id of the last processed update. +// If the GUI went to sleep with an update ready and the display picks it up, the GUI waits for the reply when it wakes up, so it continues with the settings including its update. +struct GPUDisplayGUIChannel { + struct Settings { + GPUSettingsDisplayHeavy cfgH; + GPUSettingsDisplayLight cfgL; + GPUSettingsDisplayRenderer cfgR; + }; + struct Update { // GUI → display + uint64_t id = 0; + std::vector keys; // Keys pressed in the GUI and not handled by it, display key codes + std::optional lineWidth; // For testing, to be replaced by generic settings updates + bool empty() const { return keys.empty() && !lineWidth; } + }; + struct State { // display → GUI + Settings cfg; + uint64_t appliedUpdate = 0; // Id of the last GUI update included in cfg + uint64_t counter = 0; // Incremented with every published state + }; + + std::mutex mutex; // Protects all members below + std::condition_variable stateUpdated; // Notified when a new state is published or the GUI shall stop + std::optional update; // Pending update, not yet picked up by the display + State state; // Latest state published by the display + bool guiSleeping = false; // GUI waits for its next timer tick with an update ready + bool displayProcessingCurrentUpdate = false; // Display processes the update the GUI went to sleep with, GUI waits for the reply + bool stop = false; // GUI shall close + std::chrono::milliseconds replyTimeout; // Maximum time the GUI waits for a reply + uint32_t maxUpdatesAhead = 0; // GUI waits for the reply if it is that many updates ahead of the last one it applied + std::string windowName; // Name of the display window, set when starting the GUI +}; +} // namespace o2::gpu + +#endif // GPUDISPLAYGUICHANNEL_H diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.cxx index ff7763ea62948..183c243a3d1fb 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.cxx @@ -14,143 +14,113 @@ #include "GPUDisplayGUIWrapper.h" #include "GPUDisplayGUI.h" +#include "GPUDisplayGUIChannel.h" #include -#include -#include -#include +#include #include +#include +#include +#include using namespace o2::gpu; namespace o2::gpu::internal { struct GPUDisplayGUIWrapperObjects { + int argc = 1; + char appName[64] = "GPU CA Standalone Event Display GUI"; + char* argv[2] = {appName, nullptr}; // Must outlive the QApplication std::unique_ptr app; - std::unique_ptr gui; - std::unique_ptr timer; - std::thread t; - volatile bool start = false; - volatile bool stop = false; - volatile bool terminate = false; - volatile bool started = false; - volatile bool stopped = false; - std::mutex mutex, mutexRet; - std::condition_variable signal, signalRet; + std::unique_ptr gui; // Protected by mutex + std::thread thread; + std::mutex mutex; + std::condition_variable signal; + bool start = false, terminate = false; // Protected by mutex + std::atomic started = false; // Written under mutex }; } // namespace o2::gpu::internal -GPUDisplayGUIWrapper::GPUDisplayGUIWrapper() +namespace { - static bool first = true; - static std::mutex mutex; - { - std::lock_guard guard(mutex); - if (!first) { - throw std::runtime_error("Must not start QApplication twice"); - first = true; - } +std::atomic instanceExists = false; // Qt supports only one QApplication +} // namespace + +GPUDisplayGUIWrapper::GPUDisplayGUIWrapper(GPUDisplayGUIChannel& channel) : mChannel(channel) +{ + if (instanceExists.exchange(true)) { + throw std::runtime_error("Must not start QApplication twice"); } - mO.reset(new internal::GPUDisplayGUIWrapperObjects); - mO->t = std::thread(&GPUDisplayGUIWrapper::guiThread, this); + mO = std::make_unique(); + mO->thread = std::thread(&GPUDisplayGUIWrapper::guiThread, this); } + GPUDisplayGUIWrapper::~GPUDisplayGUIWrapper() { stop(); { - std::lock_guard guard(mO->mutex); + std::lock_guard lock(mO->mutex); mO->terminate = true; - mO->signal.notify_one(); - } - mO->t.join(); -} - -void GPUDisplayGUIWrapper::UpdateTimer() -{ - if (mO->stop) { - mO->gui->close(); - mO->stop = false; } + mO->signal.notify_all(); + mO->thread.join(); + instanceExists = false; } void GPUDisplayGUIWrapper::guiThread() { - static int32_t tmp_argc = 1; - static const char* tmp_argv[2] = {"GPU CA Standalone Event Display GUI", NULL}; - mO->app.reset(new QApplication(tmp_argc, (char**)tmp_argv)); - while (!mO->terminate) { - { - std::unique_lock lock(mO->mutex); - if (!mO->start && !mO->terminate) { - mO->signal.wait(lock); - } - } + mO->app = std::make_unique(mO->argc, mO->argv); + std::unique_lock lock(mO->mutex); + while (true) { + mO->signal.wait(lock, [this] { return mO->start || mO->terminate; }); if (mO->terminate) { break; } - if (mO->start) { - mO->start = false; - mO->stopped = false; - mO->gui.reset(new GPUDisplayGUI); - mO->gui->setWrapper(this); - mO->gui->show(); - mO->timer.reset(new QTimer(mO->gui.get())); - mO->timer->start(10); - mO->gui->connect(mO->timer.get(), SIGNAL(timeout()), mO->gui.get(), SLOT(UpdateTimer())); - { - std::lock_guard guard(mO->mutexRet); - mO->started = true; - mO->signalRet.notify_one(); - } - mO->app->exec(); - mO->timer->stop(); - mO->timer.reset(nullptr); - mO->gui.reset(nullptr); - std::lock_guard guard(mO->mutexRet); - mO->started = false; - mO->stopped = true; - mO->signalRet.notify_one(); - } + mO->start = false; + mO->gui = std::make_unique(mChannel); + mO->gui->show(); + mO->started = true; + mO->signal.notify_all(); + lock.unlock(); + mO->app->exec(); // Returns when the GUI window is closed, by the user or by stop() + lock.lock(); + mO->gui.reset(); + mO->started = false; + mO->signal.notify_all(); } - mO->app.reset(nullptr); + lock.unlock(); + mO->app.reset(); } int32_t GPUDisplayGUIWrapper::start() { + std::unique_lock lock(mO->mutex); if (!mO->started) { - { - std::lock_guard guard(mO->mutex); - mO->start = true; - mO->signal.notify_one(); - } - { - std::unique_lock lock(mO->mutexRet); - while (mO->started == false) { - mO->signalRet.wait(lock); - } - } + mO->start = true; + mO->signal.notify_all(); + mO->signal.wait(lock, [this] { return mO->started.load(); }); } return 0; } int32_t GPUDisplayGUIWrapper::stop() { - if (mO->started) { - mO->stop = true; - { - std::unique_lock lock(mO->mutexRet); - while (mO->stopped == false) { - mO->signalRet.wait(lock); - } - } + { + std::lock_guard lock(mChannel.mutex); + mChannel.stop = true; } + mChannel.stateUpdated.notify_all(); // Wake up the GUI if it waits for a reply + std::unique_lock lock(mO->mutex); + mO->signal.wait(lock, [this] { return !mO->started; }); return 0; } int32_t GPUDisplayGUIWrapper::focus() { + std::lock_guard lock(mO->mutex); if (mO->started) { + QMetaObject::invokeMethod(mO->gui.get(), &GPUDisplayGUI::bringToFront, Qt::QueuedConnection); // Widgets must only be accessed from the GUI thread } return 0; } diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.h b/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.h index 4bf88b4726532..9fa9d029800c2 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.h +++ b/GPU/GPUTracking/display/frontend/GPUDisplayGUIWrapper.h @@ -20,6 +20,7 @@ namespace o2::gpu { +struct GPUDisplayGUIChannel; namespace internal { struct GPUDisplayGUIWrapperObjects; @@ -28,16 +29,16 @@ struct GPUDisplayGUIWrapperObjects; class GPUDisplayGUIWrapper { public: - GPUDisplayGUIWrapper(); + explicit GPUDisplayGUIWrapper(GPUDisplayGUIChannel& channel); // Starts the GUI thread, which owns the QApplication ~GPUDisplayGUIWrapper(); bool isRunning() const; - void UpdateTimer(); int32_t start(); int32_t stop(); - int32_t focus(); + int32_t focus(); // Bring the GUI window to the front private: + GPUDisplayGUIChannel& mChannel; std::unique_ptr mO; void guiThread(); diff --git a/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx b/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx index 537f511766595..b7c5c55cfdf22 100644 --- a/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx +++ b/GPU/GPUTracking/display/frontend/GPUDisplayKeys.cxx @@ -77,11 +77,11 @@ void GPUDisplay::PrintHelp() } } -void GPUDisplay::HandleKey(uint8_t key) +void GPUDisplay::HandleKey(uint8_t key, bool doNotHandleConfigChanges) { - GPUSettingsDisplayHeavy oldCfgH = mCfgH; - GPUSettingsDisplayLight oldCfgL = mCfgL; - GPUSettingsDisplayRenderer oldCfgR = mCfgR; + const GPUSettingsDisplayHeavy oldCfgH = mCfgH; + const GPUSettingsDisplayLight oldCfgL = mCfgL; + const GPUSettingsDisplayRenderer oldCfgR = mCfgR; if (key == 'n') { mFrontend->mDisplayControl = 1; SetInfo("Showing next event", 1); @@ -506,6 +506,13 @@ void GPUDisplay::HandleKey(uint8_t key) } */ + if (!doNotHandleConfigChanges) { + checkAndApplyConfigChanges(oldCfgH, oldCfgL, oldCfgR); + } +} + +void GPUDisplay::checkAndApplyConfigChanges(const GPUSettingsDisplayHeavy& oldCfgH, const GPUSettingsDisplayLight& oldCfgL, const GPUSettingsDisplayRenderer& oldCfgR) +{ if (memcmp((void*)&oldCfgH, (void*)&mCfgH, sizeof(mCfgH)) != 0) { mUpdateEventData = true; } @@ -545,7 +552,7 @@ void GPUDisplay::HandleExternalGUIKey(int32_t key) } bool oldShift = mFrontend->mKeysShift[press]; mFrontend->mKeysShift[press] = shifted; - HandleKey(key); + HandleKey(key, true); mFrontend->mKeysShift[press] = oldShift; } From ced3685d27322b667d7e386cf3669c8de134ef4b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 15 Oct 2026 22:28:28 +0200 Subject: [PATCH 3/4] GPU: clean up and split qconfig header --- GPU/GPUTracking/Base/GPUParam.cxx | 2 +- GPU/GPUTracking/DataTypes/GPUConfigDump.cxx | 2 +- .../Standalone/Benchmark/standalone.cxx | 6 +- GPU/GPUTracking/utils/qconfig.cxx | 42 +-- GPU/GPUTracking/utils/qconfig.h | 333 +----------------- GPU/GPUTracking/utils/qconfig_general.h | 40 +++ GPU/GPUTracking/utils/qconfig_internal.h | 273 ++++++++++++++ .../utils/qconfig_internal_helpers.h | 46 +++ .../utils/{qconfigrtc.h => qconfig_rtc.h} | 2 +- GPU/GPUTracking/utils/qconfig_wrapinclude.h | 86 +++++ 10 files changed, 461 insertions(+), 371 deletions(-) create mode 100644 GPU/GPUTracking/utils/qconfig_general.h create mode 100644 GPU/GPUTracking/utils/qconfig_internal.h create mode 100644 GPU/GPUTracking/utils/qconfig_internal_helpers.h rename GPU/GPUTracking/utils/{qconfigrtc.h => qconfig_rtc.h} (97%) create mode 100644 GPU/GPUTracking/utils/qconfig_wrapinclude.h diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index 7edfa8ffd41d5..6650248439626 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -28,7 +28,7 @@ using namespace o2::gpu; #include #include -#include "utils/qconfigrtc.h" +#include "utils/qconfig_rtc.h" void GPUParam::SetDefaults(float solenoidBz, bool assumeConstantBz) { diff --git a/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx b/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx index 56543d5f2e43d..9353e3664d05a 100644 --- a/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx +++ b/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx @@ -29,7 +29,7 @@ namespace GPUSettingsStandalone configStandalone; std::vector> qprint_global; #define QCONFIG_PRINT -#include "utils/qconfig.h" +#include "utils/qconfig_internal.h" #undef QCONFIG_PRINT } // namespace diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index f92413318542f..6c35a5651d45f 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -92,7 +92,7 @@ std::vector ioMemEvents; int32_t ReadConfiguration(int argc, char** argv) { - int32_t qcRet = qConfigParse(argc, (const char**)argv); + int32_t qcRet = qConfig::qConfigParse(argc, (const char**)argv); if (qcRet) { if (qcRet != qConfig::qcrHelp) { printf("Error parsing command line parameters\n"); @@ -107,7 +107,7 @@ int32_t ReadConfiguration(int argc, char** argv) } if (configStandalone.printSettings > 1) { printf("Config Dump before ReadConfiguration\n"); - qConfigPrint(); + qConfig::qConfigPrint(); } if (configStandalone.proc.debugLevel == -1) { configStandalone.proc.debugLevel = 0; @@ -295,7 +295,7 @@ int32_t ReadConfiguration(int argc, char** argv) } if (configStandalone.printSettings > 1) { printf("Config Dump after ReadConfiguration\n"); - qConfigPrint(); + qConfig::qConfigPrint(); } return (0); diff --git a/GPU/GPUTracking/utils/qconfig.cxx b/GPU/GPUTracking/utils/qconfig.cxx index 839954e52ded3..8a15a6ecdd9ef 100644 --- a/GPU/GPUTracking/utils/qconfig.cxx +++ b/GPU/GPUTracking/utils/qconfig.cxx @@ -22,39 +22,16 @@ #include #include "qconfig.h" #include "qconfig_helpers.h" +#include "qconfig_internal_helpers.h" // Create config instances #define QCONFIG_PARSER_CXX #define QCONFIG_INSTANCE -#include "qconfig.h" +#include "qconfig_internal.h" #undef QCONFIG_INSTANCE namespace qConfig { -#define QCONFIG_SETTING(name, type) \ - struct qon_mxcat3(q, name, _t) { \ - type v; \ - constexpr qon_mxcat3(q, name, _t)(type s) : v(s) {} \ - }; \ - constexpr qon_mxcat3(q, name, _t) name(type v) { return (qon_mxcat3(q, name, _t)(v)); } - -#define QCONFIG_SETTING_TEMPLATE(name) \ - template \ - struct qon_mxcat3(q, name, _t) { \ - T v; \ - constexpr qon_mxcat3(q, name, _t)(const T& s) : v(s) {} \ - }; \ - template \ - constexpr qon_mxcat3(q, name, _t) name(T v) \ - { \ - return (qon_mxcat3(q, name, _t) < T > (v)); \ - } - -QCONFIG_SETTING(message, const char*) -QCONFIG_SETTING_TEMPLATE(min) -QCONFIG_SETTING_TEMPLATE(max) -QCONFIG_SETTING_TEMPLATE(set) -QCONFIG_SETTING_TEMPLATE(def) static inline const char* getOptName(const char** argv, int32_t i) { @@ -477,7 +454,7 @@ static inline void qConfigHelp(const char* subConfig = nullptr, int32_t followSu printf("Usage Info:"); } #define QCONFIG_HELP -#include "qconfig.h" +#include "qconfig_internal.h" #undef QCONFIG_HELP if (followSub < 2) { printf("\n"); @@ -485,14 +462,14 @@ static inline void qConfigHelp(const char* subConfig = nullptr, int32_t followSu } // Create parser for configuration -static inline int32_t qConfigParse(int argc, const char** argv, const char* /*filename*/) +int32_t qConfigParse(int argc, const char** argv, const char* /*filename*/) { for (int32_t i = 1; i < argc; i++) { const char* thisoption = argv[i]; repeat: bool found = false; #define QCONFIG_PARSE -#include "qconfig.h" +#include "qconfig_internal.h" #undef QCONFIG_PARSE if (found == false) { printf("Invalid argument: %s\n", argv[i]); @@ -505,16 +482,13 @@ static inline int32_t qConfigParse(int argc, const char** argv, const char* /*fi std::vector> qprint_global; #define QCONFIG_PRINT -#include "qconfig.h" +#include "qconfig_internal.h" #undef QCONFIG_PRINT -} // end namespace qConfig - -// Main parse function called from outside -int32_t qConfigParse(int argc, const char** argv, const char* filename) { return (qConfig::qConfigParse(argc, argv, filename)); } void qConfigPrint() { - for (auto& f : qConfig::qprint_global) { + for (auto& f : qprint_global) { f(); } } +} // end namespace qConfig diff --git a/GPU/GPUTracking/utils/qconfig.h b/GPU/GPUTracking/utils/qconfig.h index a809cc69be501..87d837a083e94 100644 --- a/GPU/GPUTracking/utils/qconfig.h +++ b/GPU/GPUTracking/utils/qconfig.h @@ -12,27 +12,7 @@ /// \file qconfig.h /// \author David Rohr -#ifndef QCONFIG_H_GENERAL -#define QCONFIG_H_GENERAL -#ifndef GPUCA_GPUCODE_DEVICE -#include -#endif - -extern int32_t qConfigParse(int argc, const char** argv, const char* filename = nullptr); -extern void qConfigPrint(); -namespace qConfig -{ -enum qConfigRetVal { qcrOK = 0, - qcrError = 1, - qcrMinFailure = 2, - qcrMaxFailure = 3, - qcrHelp = 4, - qcrCmd = 5, - qcrArgMissing = 6, - qcrArgIncomplete = 7, - qcrArrayOverflow = 8 }; -} -#endif +#include "qconfig_general.h" #if !defined(QCONFIG_HEADER_GUARD_NO_INCLUDE) || defined(QCONFIG_GENRTC) @@ -41,244 +21,7 @@ enum qConfigRetVal { qcrOK = 0, __VA_ARGS__ \ } -#ifdef QCONFIG_PARSE - -#define QCONFIG_COMPARE(name, optname, optnameshort) \ - (thisoption[0] == '-' && ((thisoption[1] == '-' && optname[0] != 0 && strcmp(&thisoption[2], optname) == 0) || \ - (preoptshort == 0 && thisoption[1] == optnameshort && thisoption[2] == 0) || (thisoption[1] == '-' && strlen(preopt) == 0 && strcmp(&thisoption[2], name) == 0) || \ - (preoptshort != 0 && thisoption[1] == preoptshort && thisoption[2] == optnameshort && thisoption[3] == 0) || (thisoption[1] == '-' && strlen(preopt) && strncmp(&thisoption[2], preopt, strlen(preopt)) == 0 && strcmp(&thisoption[2 + strlen(preopt)], name) == 0))) - -#define AddOption(name, type, default, optname, optnameshort, ...) \ - else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ - { \ - int32_t retVal = qConfigType::qAddOption(tmp.name, i, argv, argc, default, __VA_ARGS__); \ - if (retVal) { \ - return (retVal); \ - } \ - } - -#define AddOptionSet(name, type, value, optname, optnameshort, ...) \ - else if (QCONFIG_COMPARE(optname, "", optnameshort)) \ - { \ - int32_t retVal = qConfigType::qAddOption(tmp.name, i, nullptr, 0, value, __VA_ARGS__, set(value)); \ - if (retVal) { \ - return (retVal); \ - } \ - } - -#define AddOptionVec(name, type, optname, optnameshort, ...) \ - else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ - { \ - int32_t retVal = qConfigType::qAddOptionVec(tmp.name, i, argv, argc, __VA_ARGS__); \ - if (retVal) { \ - return (retVal); \ - } \ - } - -#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ - else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ - { \ - int32_t retVal = qConfigType::qAddOptionArray(tmp.name, count, i, argv, argc, __VA_ARGS__); \ - if (retVal) { \ - return (retVal); \ - } \ - } - -#define AddSubConfig(name, instance) - -#define BeginConfig(name, instance) \ - { \ - constexpr const char* preopt = ""; \ - constexpr const char preoptshort = 0; \ - name& tmp = instance; \ - bool tmpfound = true; \ - if (found) { \ - } - -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ - { \ - [[maybe_unused]] constexpr const char* preopt = preoptname; \ - [[maybe_unused]] constexpr const char preoptshort = preoptnameshort; \ - [[maybe_unused]] name& tmp = parent.instance; \ - bool tmpfound = true; \ - if (found) { \ - } - -#define BeginHiddenConfig(name, instance) \ - { \ - bool tmpfound; \ - if (0) { \ - } - -#define EndConfig() \ - else { tmpfound = false; } \ - if (tmpfound) { \ - found = true; \ - } \ - } - -#define AddHelp(cmd, cmdshort) \ - else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ - { \ - const char* arg = getArg(i, argv, argc); \ - qConfigHelp(arg ? arg : preopt); \ - return (qcrHelp); \ - } - -#define AddHelpAll(cmd, cmdshort) \ - else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ - { \ - const char* arg = getArg(i, argv, argc); \ - qConfigHelp(arg ? arg : "", true); \ - return (qcrHelp); \ - } - -#define AddCommand(cmd, cmdshort, command, help) \ - else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ - { \ - if (command) { \ - return (qcrCmd); \ - } \ - } - -#define AddShortcut(cmd, cmdshort, forward, help, ...) \ - else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ - { \ - const char* options[] = {"", __VA_ARGS__, nullptr}; \ - const int32_t nOptions = sizeof(options) / sizeof(options[0]) - 1; \ - qConfigParse(nOptions, options, nullptr); \ - thisoption = forward; \ - goto repeat; \ - } - -// End QCONFIG_PARSE -#elif defined(QCONFIG_HELP) -#define AddOption(name, type, default, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), qon_mxstr(default), optname, optnameshort, preopt, preoptshort, 0, __VA_ARGS__); -#define AddOptionSet(name, type, value, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), qon_mxstr(value), optname, optnameshort, preopt, preoptshort, 1, __VA_ARGS__); -#define AddOptionVec(name, type, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), nullptr, optname, optnameshort, preopt, preoptshort, 2, __VA_ARGS__); -#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type) "[" qon_mxstr(count) "]", nullptr, optname, optnameshort, preopt, preoptshort, 2, __VA_ARGS__); -#define AddSubConfig(name, instance) \ - printf("\t%s\n\n", qon_mxcat(qConfig_subconfig_, name)); \ - if (followSub) { \ - qConfigHelp(qon_mxstr(name), 2); \ - } -#define BeginConfig(name, instance) \ - if (subConfig == nullptr || *subConfig == 0) { \ - constexpr const char* preopt = ""; \ - constexpr const char preoptshort = 0; \ - printf("\n"); -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ - const char* qon_mxcat(qConfig_subconfig_, name) = preoptnameshort == 0 ? (qon_mxstr(name) ": --" preoptname "\n\t\t" descr) : (qon_mxstr(name) ": -" qon_mxstr('a') " (--" preoptname ")\n\t\t" descr); \ - (void)qon_mxcat(qConfig_subconfig_, name); \ - if (subConfig == nullptr || strcmp(subConfig, followSub == 2 ? qon_mxstr(name) : preoptname) == 0) { \ - [[maybe_unused]] constexpr const char* preopt = preoptname; \ - [[maybe_unused]] constexpr const char preoptshort = preoptnameshort; \ - char argBuffer[2] = {preoptnameshort, 0}; \ - printf("\n %s: (--%s%s%s)\n", descr, preoptname, preoptnameshort == 0 ? "" : " or -", argBuffer); -#define BeginHiddenConfig(name, instance) { -#define EndConfig() } -#define AddHelp(cmd, cmdshort) qConfigType::qConfigHelpOption("help", "help", nullptr, cmd, cmdshort, preopt, preoptshort, 3, "Show usage information"); -#define AddHelpAll(cmd, cmdshort) qConfigType::qConfigHelpOption("help all", "help all", nullptr, cmd, cmdshort, preopt, preoptshort, 3, "Show usage info including all subparameters"); -#define AddCommand(cmd, cmdshort, command, help) qConfigType::qConfigHelpOption("command", "command", nullptr, cmd, cmdshort, preopt, preoptshort, 4, help); -#define AddShortcut(cmd, cmdshort, forward, help, ...) qConfigType::qConfigHelpOption("shortcut", "shortcut", nullptr, cmd, cmdshort, preopt, preoptshort, 4, help); -#define AddHelpText(text) printf("\n " text ":\n"); - -// End QCONFIG_HELP -#elif defined(QCONFIG_PRINT) -#define AddOption(name, type, default, optname, optnameshort, ...) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(qconfig_tmp_object.name) << "\n"; -#define AddVariable(name, type, default) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << qConfig::print_type(qconfig_tmp_object.name) << "\n"; -#define AddOptionSet(name, type, value, optname, optnameshort, ...) -#define AddOptionVec(name, type, optname, optnameshort, ...) \ - { \ - std::cout << "\t" << blockName << qon_mxstr(name) << "[]: "; \ - for (uint32_t i = 0; i < qconfig_tmp_object.name.size(); i++) { \ - if (i) { \ - std::cout << ", "; \ - } \ - std::cout << qConfig::print_type(qconfig_tmp_object.name[i]); \ - } \ - std::cout << "\n"; \ - } -#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ - { \ - std::cout << "\t" << blockName << qon_mxstr(name) << "[" << count << "]: " << qConfig::print_type(qconfig_tmp_object.name[0]); \ - for (int32_t i = 1; i < count; i++) { \ - std::cout << ", " << qConfig::print_type(qconfig_tmp_object.name[i]); \ - } \ - std::cout << "\n"; \ - } -#define AddSubConfig(name, instance) qConfigPrint(qconfig_tmp_object.instance, blockName + qon_mxstr(instance.)); -#define AddHelpText(text) printf(" " text ":\n"); -#define BeginConfig(name, instance) \ - void qConfigPrint(const name& qconfig_tmp_object); \ - bool qon_mxcat(qprint_global_, instance) = []() { qprint_global.emplace_back([]() { qConfigPrint(instance); }); return true; }(); \ - void qConfigPrint(const name& qconfig_tmp_object) \ - { \ - std::string blockName = ""; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ - void qConfigPrint(const name& qconfig_tmp_object, std::string blockName = "") \ - { \ - std::cout << "\n\t" << qon_mxstr(name) << ":\n"; -#define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, x, x, x, x) - -#define EndConfig() } - -// End QCONFIG_PRINT -#elif defined(QCONFIG_INSTANCE) -#define BeginNamespace(name) \ - namespace name \ - { -#define EndNamespace() } -#define AddOption(name, type, default, optname, optnameshort, help, ...) -#define AddVariable(name, type, default) -#define AddOptionSet(name, type, value, optname, optnameshort, help, ...) -#define AddOptionVec(name, type, optname, optnameshort, help, ...) -#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) -#define AddSubConfig(name, instance) -#define BeginConfig(name, instance) name instance; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) -#define EndConfig() -// End QCONFIG_INSTANCE -#elif defined(QCONFIG_PRINT_RTC) -#define AddOption(name, type, default, optname, optnameshort, help, ...) out << qon_mxstr(type) << " " << qon_mxstr(name) << ";\n"; -#define AddVariable(name, type, default) out << qon_mxstr(type) << " " << qon_mxstr(name) << ";\n"; -#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) out << qon_mxstr(type) << " " << qon_mxstr(name) << "[" << qon_mxstr(count) << "];\n"; -#define AddOptionVec(name, type, optname, optnameshort, help, ...) out << "std::vector<" << qon_mxstr(type) << "> " << qon_mxstr(name) << ";\n"; -#define AddVariableRTC(name, type, default) \ - if (useConstexpr) { \ - out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << " = " << qConfig::print_type(std::get(tSrc)->name, true) << ";\n"; \ - out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ - } else { \ - AddOption(name, type, default, optname, optnameshort, help); \ - } -#define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) AddVariableRTC(name, type, default) -#define AddOptionArrayRTC(name, type, count, default, optname, optnameshort, help, ...) \ - if (useConstexpr) { \ - out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << "[" << count << "] = {" << qConfig::print_type(std::get(tSrc)->name[0]); \ - for (int32_t i = 1; i < count; i++) { \ - out << ", " << qConfig::print_type(std::get(tSrc)->name[i]); \ - } \ - out << "};\n"; \ - out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ - } else { \ - AddOptionArray(name, type, count, default, optname, optnameshort, help); \ - } -#define BeginConfig(name, instance) \ - { \ - using qConfigCurrentType = name; \ - out << "struct " << qon_mxstr(name) << " {\n"; -#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) BeginConfig(name, instance) -#define EndConfig() \ - out << "};"; \ - } -#define BeginNamespace(name) out << "namespace " << qon_mxstr(name) << " {\n"; -#define EndNamespace() out << "}\n"; -#define AddSubConfig(name, instance) out << qon_mxstr(name) << " " << qon_mxstr(instance) << ";"; -#define AddOptionSet(...) - -// End QCONFIG_PRINT_RTC -#else // Define structures #if defined(QCONFIG_HEADER_GUARD) && !defined(QCONFIG_GENRTC) #define QCONFIG_HEADER_GUARD_NO_INCLUDE #else @@ -329,79 +72,7 @@ enum qConfigRetVal { qcrOK = 0, ; #endif -#endif -#ifndef QCONFIG_HEADER_GUARD_NO_INCLUDE -#ifndef AddHelp -#define AddHelp(cmd, cmdshort) -#endif -#ifndef AddHelpAll -#define AddHelpAll(cmd, cmdshort) -#endif -#ifndef AddCommand -#define AddCommand(cmd, cmdshort, command) -#endif -#ifndef AddShortcut -#define AddShortcut(cmd, cmdshort, forward, help, ...) -#endif -#ifndef AddVariable -#define AddVariable(name, type, default) -#endif -#ifndef AddHelpText -#define AddHelpText(text) -#endif -#ifndef BeginNamespace -#define BeginNamespace(name) -#endif -#ifndef EndNamespace -#define EndNamespace() -#endif -#ifndef AddCustomCPP -#define AddCustomCPP(...) -#endif -#ifndef AddOptionRTC -#define AddOptionRTC(...) AddOption(__VA_ARGS__) -#endif -#ifndef AddVariableRTC -#define AddVariableRTC(...) AddVariable(__VA_ARGS__) -#endif -#ifndef AddOptionArrayRTC -#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) -#endif -#ifndef BeginHiddenConfig -#define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, , , , ) -#endif - -#include "qconfigoptions.h" - -#undef AddOption -#undef AddOptionRTC -#undef AddVariable -#undef AddVariableRTC -#undef AddOptionSet -#undef AddOptionVec -#undef AddOptionArray -#undef AddOptionArrayRTC -#undef AddArrayDefaults -#undef AddSubConfig -#undef BeginConfig -#undef BeginSubConfig -#undef BeginHiddenConfig -#undef EndConfig -#undef AddHelp -#undef AddHelpAll -#undef AddHelpText -#undef AddCommand -#undef AddShortcut -#undef BeginNamespace -#undef EndNamespace -#undef AddCustomCPP -#ifdef QCONFIG_COMPARE -#undef QCONFIG_COMPARE -#endif - -#else -#undef QCONFIG_HEADER_GUARD_NO_INCLUDE -#endif +#include "qconfig_wrapinclude.h" #endif // QCONFIG_HEADER_GUARD_NO_INCLUDE diff --git a/GPU/GPUTracking/utils/qconfig_general.h b/GPU/GPUTracking/utils/qconfig_general.h new file mode 100644 index 0000000000000..225808107a4cf --- /dev/null +++ b/GPU/GPUTracking/utils/qconfig_general.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfig_general.h +/// \author David Rohr + +#ifndef QCONFIG_H_GENERAL +#define QCONFIG_H_GENERAL +#ifndef GPUCA_GPUCODE_DEVICE +#include +#include +#endif + +namespace qConfig +{ +#ifndef GPUCA_GPUCODE_DEVICE +int32_t qConfigParse(int argc, const char** argv, const char* filename = nullptr); +void qConfigPrint(); // Print all settings +template +void qConfigPrint(const T& qconfig_tmp_object, const std::string& blockName = ""); // Print one sub config, specializations created in qconfig.cxx +#endif +enum qConfigRetVal { qcrOK = 0, + qcrError = 1, + qcrMinFailure = 2, + qcrMaxFailure = 3, + qcrHelp = 4, + qcrCmd = 5, + qcrArgMissing = 6, + qcrArgIncomplete = 7, + qcrArrayOverflow = 8 }; +} // namespace qConfig +#endif // QCONFIG_H_GENERAL diff --git a/GPU/GPUTracking/utils/qconfig_internal.h b/GPU/GPUTracking/utils/qconfig_internal.h new file mode 100644 index 0000000000000..e7bcbc80695c2 --- /dev/null +++ b/GPU/GPUTracking/utils/qconfig_internal.h @@ -0,0 +1,273 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfig_internal.h +/// \author David Rohr + +// For internal use by qconfig.cxx +// External usage is possible, but not fully supported + +#include "qconfig_general.h" +#include "qconfig_helpers.h" + +#if !defined(QCONFIG_HEADER_GUARD_NO_INCLUDE) || defined(QCONFIG_GENRTC) + +#define AddArrayDefaults(...) {__VA_ARGS__} + +#ifdef QCONFIG_PARSE + +#define QCONFIG_COMPARE(name, optname, optnameshort) \ + (thisoption[0] == '-' && ((thisoption[1] == '-' && optname[0] != 0 && strcmp(&thisoption[2], optname) == 0) || \ + (preoptshort == 0 && thisoption[1] == optnameshort && thisoption[2] == 0) || (thisoption[1] == '-' && strlen(preopt) == 0 && strcmp(&thisoption[2], name) == 0) || \ + (preoptshort != 0 && thisoption[1] == preoptshort && thisoption[2] == optnameshort && thisoption[3] == 0) || (thisoption[1] == '-' && strlen(preopt) && strncmp(&thisoption[2], preopt, strlen(preopt)) == 0 && strcmp(&thisoption[2 + strlen(preopt)], name) == 0))) + +#define AddOption(name, type, default, optname, optnameshort, ...) \ + else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ + { \ + int32_t retVal = qConfigType::qAddOption(tmp.name, i, argv, argc, default, __VA_ARGS__); \ + if (retVal) { \ + return (retVal); \ + } \ + } + +#define AddOptionSet(name, type, value, optname, optnameshort, ...) \ + else if (QCONFIG_COMPARE(optname, "", optnameshort)) \ + { \ + int32_t retVal = qConfigType::qAddOption(tmp.name, i, nullptr, 0, value, __VA_ARGS__, set(value)); \ + if (retVal) { \ + return (retVal); \ + } \ + } + +#define AddOptionVec(name, type, optname, optnameshort, ...) \ + else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ + { \ + int32_t retVal = qConfigType::qAddOptionVec(tmp.name, i, argv, argc, __VA_ARGS__); \ + if (retVal) { \ + return (retVal); \ + } \ + } + +#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ + else if (QCONFIG_COMPARE(#name, optname, optnameshort)) \ + { \ + int32_t retVal = qConfigType::qAddOptionArray(tmp.name, count, i, argv, argc, __VA_ARGS__); \ + if (retVal) { \ + return (retVal); \ + } \ + } + +#define AddSubConfig(name, instance) + +#define BeginConfig(name, instance) \ + { \ + constexpr const char* preopt = ""; \ + constexpr const char preoptshort = 0; \ + name& tmp = instance; \ + bool tmpfound = true; \ + if (found) { \ + } + +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ + { \ + [[maybe_unused]] constexpr const char* preopt = preoptname; \ + [[maybe_unused]] constexpr const char preoptshort = preoptnameshort; \ + [[maybe_unused]] name& tmp = parent.instance; \ + bool tmpfound = true; \ + if (found) { \ + } + +#define BeginHiddenConfig(name, instance) \ + { \ + bool tmpfound; \ + if (0) { \ + } + +#define EndConfig() \ + else { tmpfound = false; } \ + if (tmpfound) { \ + found = true; \ + } \ + } + +#define AddHelp(cmd, cmdshort) \ + else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ + { \ + const char* arg = getArg(i, argv, argc); \ + qConfigHelp(arg ? arg : preopt); \ + return (qcrHelp); \ + } + +#define AddHelpAll(cmd, cmdshort) \ + else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ + { \ + const char* arg = getArg(i, argv, argc); \ + qConfigHelp(arg ? arg : "", true); \ + return (qcrHelp); \ + } + +#define AddCommand(cmd, cmdshort, command, help) \ + else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ + { \ + if (command) { \ + return (qcrCmd); \ + } \ + } + +#define AddShortcut(cmd, cmdshort, forward, help, ...) \ + else if (QCONFIG_COMPARE(cmd, "", cmdshort)) \ + { \ + const char* options[] = {"", __VA_ARGS__, nullptr}; \ + const int32_t nOptions = sizeof(options) / sizeof(options[0]) - 1; \ + qConfigParse(nOptions, options, nullptr); \ + thisoption = forward; \ + goto repeat; \ + } + +// End QCONFIG_PARSE +#elif defined(QCONFIG_HELP) +#define AddOption(name, type, default, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), qon_mxstr(default), optname, optnameshort, preopt, preoptshort, 0, __VA_ARGS__); +#define AddOptionSet(name, type, value, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), qon_mxstr(value), optname, optnameshort, preopt, preoptshort, 1, __VA_ARGS__); +#define AddOptionVec(name, type, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type), nullptr, optname, optnameshort, preopt, preoptshort, 2, __VA_ARGS__); +#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) qConfigType::qConfigHelpOption(qon_mxstr(name), qon_mxstr(type) "[" qon_mxstr(count) "]", nullptr, optname, optnameshort, preopt, preoptshort, 2, __VA_ARGS__); +#define AddSubConfig(name, instance) \ + printf("\t%s\n\n", qon_mxcat(qConfig_subconfig_, name)); \ + if (followSub) { \ + qConfigHelp(qon_mxstr(name), 2); \ + } +#define BeginConfig(name, instance) \ + if (subConfig == nullptr || *subConfig == 0) { \ + constexpr const char* preopt = ""; \ + constexpr const char preoptshort = 0; \ + printf("\n"); +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ + const char* qon_mxcat(qConfig_subconfig_, name) = preoptnameshort == 0 ? (qon_mxstr(name) ": --" preoptname "\n\t\t" descr) : (qon_mxstr(name) ": -" qon_mxstr('a') " (--" preoptname ")\n\t\t" descr); \ + (void)qon_mxcat(qConfig_subconfig_, name); \ + if (subConfig == nullptr || strcmp(subConfig, followSub == 2 ? qon_mxstr(name) : preoptname) == 0) { \ + [[maybe_unused]] constexpr const char* preopt = preoptname; \ + [[maybe_unused]] constexpr const char preoptshort = preoptnameshort; \ + char argBuffer[2] = {preoptnameshort, 0}; \ + printf("\n %s: (--%s%s%s)\n", descr, preoptname, preoptnameshort == 0 ? "" : " or -", argBuffer); +#define BeginHiddenConfig(name, instance) { +#define EndConfig() } +#define AddHelp(cmd, cmdshort) qConfigType::qConfigHelpOption("help", "help", nullptr, cmd, cmdshort, preopt, preoptshort, 3, "Show usage information"); +#define AddHelpAll(cmd, cmdshort) qConfigType::qConfigHelpOption("help all", "help all", nullptr, cmd, cmdshort, preopt, preoptshort, 3, "Show usage info including all subparameters"); +#define AddCommand(cmd, cmdshort, command, help) qConfigType::qConfigHelpOption("command", "command", nullptr, cmd, cmdshort, preopt, preoptshort, 4, help); +#define AddShortcut(cmd, cmdshort, forward, help, ...) qConfigType::qConfigHelpOption("shortcut", "shortcut", nullptr, cmd, cmdshort, preopt, preoptshort, 4, help); +#define AddHelpText(text) printf("\n " text ":\n"); + +// End QCONFIG_HELP +#elif defined(QCONFIG_PRINT) +template +void qConfigPrint(const T& qconfig_tmp_object, const std::string& blockName); // (Re)declare in the namespace of the include for the specializations below, default argument only in qconfig_general.h +#define AddOption(name, type, default, optname, optnameshort, ...) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << ::qConfig::print_type(qconfig_tmp_object.name) << "\n"; +#define AddVariable(name, type, default) std::cout << "\t" << blockName << qon_mxstr(name) << ": " << ::qConfig::print_type(qconfig_tmp_object.name) << "\n"; +#define AddOptionSet(name, type, value, optname, optnameshort, ...) +#define AddOptionVec(name, type, optname, optnameshort, ...) \ + { \ + std::cout << "\t" << blockName << qon_mxstr(name) << "[]: "; \ + for (uint32_t i = 0; i < qconfig_tmp_object.name.size(); i++) { \ + if (i) { \ + std::cout << ", "; \ + } \ + std::cout << ::qConfig::print_type(qconfig_tmp_object.name[i]); \ + } \ + std::cout << "\n"; \ + } +#define AddOptionArray(name, type, count, default, optname, optnameshort, ...) \ + { \ + std::cout << "\t" << blockName << qon_mxstr(name) << "[" << count << "]: " << ::qConfig::print_type(qconfig_tmp_object.name[0]); \ + for (int32_t i = 1; i < count; i++) { \ + std::cout << ", " << ::qConfig::print_type(qconfig_tmp_object.name[i]); \ + } \ + std::cout << "\n"; \ + } +#define AddSubConfig(name, instance) qConfigPrint(qconfig_tmp_object.instance, blockName + qon_mxstr(instance.)); +#define AddHelpText(text) printf(" " text ":\n"); +#define BeginConfig(name, instance) \ + void qConfigPrint(const name& qconfig_tmp_object); \ + bool qon_mxcat(qprint_global_, instance) = []() { qprint_global.emplace_back([]() { qConfigPrint(instance); }); return true; }(); \ + void qConfigPrint(const name& qconfig_tmp_object) \ + { \ + std::string blockName = ""; +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) \ + template <> \ + void qConfigPrint(const name& qconfig_tmp_object, const std::string& blockName) \ + { \ + std::cout << "\n\t" << qon_mxstr(name) << ":\n"; +#define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, x, x, x, x) + +#define EndConfig() } + +// End QCONFIG_PRINT +#elif defined(QCONFIG_INSTANCE) +#define BeginNamespace(name) \ + namespace name \ + { +#define EndNamespace() } +#define AddOption(name, type, default, optname, optnameshort, help, ...) +#define AddVariable(name, type, default) +#define AddOptionSet(name, type, value, optname, optnameshort, help, ...) +#define AddOptionVec(name, type, optname, optnameshort, help, ...) +#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) +#define AddSubConfig(name, instance) +#define BeginConfig(name, instance) name instance; +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) +#define EndConfig() + +// End QCONFIG_INSTANCE +#elif defined(QCONFIG_PRINT_RTC) +#define AddOption(name, type, default, optname, optnameshort, help, ...) out << qon_mxstr(type) << " " << qon_mxstr(name) << ";\n"; +#define AddVariable(name, type, default) out << qon_mxstr(type) << " " << qon_mxstr(name) << ";\n"; +#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) out << qon_mxstr(type) << " " << qon_mxstr(name) << "[" << qon_mxstr(count) << "];\n"; +#define AddOptionVec(name, type, optname, optnameshort, help, ...) out << "std::vector<" << qon_mxstr(type) << "> " << qon_mxstr(name) << ";\n"; +#define AddVariableRTC(name, type, default) \ + if (useConstexpr) { \ + out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << " = " << ::qConfig::print_type(std::get(tSrc)->name, true) << ";\n"; \ + out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ + } else { \ + AddOption(name, type, default, optname, optnameshort, help); \ + } +#define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) AddVariableRTC(name, type, default) +#define AddOptionArrayRTC(name, type, count, default, optname, optnameshort, help, ...) \ + if (useConstexpr) { \ + out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << "[" << count << "] = {" << ::qConfig::print_type(std::get(tSrc)->name[0]); \ + for (int32_t i = 1; i < count; i++) { \ + out << ", " << qConfig::print_type(std::get(tSrc)->name[i]); \ + } \ + out << "};\n"; \ + out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ + } else { \ + AddOptionArray(name, type, count, default, optname, optnameshort, help); \ + } +#define BeginConfig(name, instance) \ + { \ + using qConfigCurrentType = name; \ + out << "struct " << qon_mxstr(name) << " {\n"; +#define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, ...) BeginConfig(name, instance) +#define EndConfig() \ + out << "};"; \ + } +#define BeginNamespace(name) out << "namespace " << qon_mxstr(name) << " {\n"; +#define EndNamespace() out << "}\n"; +#define AddSubConfig(name, instance) out << qon_mxstr(name) << " " << qon_mxstr(instance) << ";"; +#define AddOptionSet(...) + +// End QCONFIG_PRINT_RTC +#else // Define structures + +#error Internal error, qconfig_internal called with action type + +#endif + +#include "qconfig_wrapinclude.h" + +#endif // QCONFIG_HEADER_GUARD_NO_INCLUDE diff --git a/GPU/GPUTracking/utils/qconfig_internal_helpers.h b/GPU/GPUTracking/utils/qconfig_internal_helpers.h new file mode 100644 index 0000000000000..c3702e819256b --- /dev/null +++ b/GPU/GPUTracking/utils/qconfig_internal_helpers.h @@ -0,0 +1,46 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfig_internal_helpers.h +/// \author David Rohr + +#ifndef QCONFIG_INTERNAL_HELPERS_H +#define QCONFIG_INTERNAL_HELPERS_H + +namespace qConfig +{ +#define QCONFIG_SETTING(name, type) \ + struct qon_mxcat3(q, name, _t) { \ + type v; \ + constexpr qon_mxcat3(q, name, _t)(type s) : v(s) {} \ + }; \ + constexpr qon_mxcat3(q, name, _t) name(type v) { return (qon_mxcat3(q, name, _t)(v)); } + +#define QCONFIG_SETTING_TEMPLATE(name) \ + template \ + struct qon_mxcat3(q, name, _t) { \ + T v; \ + constexpr qon_mxcat3(q, name, _t)(const T& s) : v(s) {} \ + }; \ + template \ + constexpr qon_mxcat3(q, name, _t) name(T v) \ + { \ + return (qon_mxcat3(q, name, _t) < T > (v)); \ + } + +QCONFIG_SETTING(message, const char*) +QCONFIG_SETTING_TEMPLATE(min) +QCONFIG_SETTING_TEMPLATE(max) +QCONFIG_SETTING_TEMPLATE(set) +QCONFIG_SETTING_TEMPLATE(def) +} // namespace qConfig + +#endif diff --git a/GPU/GPUTracking/utils/qconfigrtc.h b/GPU/GPUTracking/utils/qconfig_rtc.h similarity index 97% rename from GPU/GPUTracking/utils/qconfigrtc.h rename to GPU/GPUTracking/utils/qconfig_rtc.h index 8d33ef0ac6355..70a1bfcd56229 100644 --- a/GPU/GPUTracking/utils/qconfigrtc.h +++ b/GPU/GPUTracking/utils/qconfig_rtc.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file qconfigrtc.h +/// \file qconfig_rtc.h /// \author David Rohr #ifndef QCONFIG_RTC_H diff --git a/GPU/GPUTracking/utils/qconfig_wrapinclude.h b/GPU/GPUTracking/utils/qconfig_wrapinclude.h new file mode 100644 index 0000000000000..d06c9ade018fc --- /dev/null +++ b/GPU/GPUTracking/utils/qconfig_wrapinclude.h @@ -0,0 +1,86 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file qconfig_wrapinclude.h +/// \author David Rohr + +#ifndef QCONFIG_HEADER_GUARD_NO_INCLUDE +#ifndef AddHelp +#define AddHelp(cmd, cmdshort) +#endif +#ifndef AddHelpAll +#define AddHelpAll(cmd, cmdshort) +#endif +#ifndef AddCommand +#define AddCommand(cmd, cmdshort, command) +#endif +#ifndef AddShortcut +#define AddShortcut(cmd, cmdshort, forward, help, ...) +#endif +#ifndef AddVariable +#define AddVariable(name, type, default) +#endif +#ifndef AddHelpText +#define AddHelpText(text) +#endif +#ifndef BeginNamespace +#define BeginNamespace(name) +#endif +#ifndef EndNamespace +#define EndNamespace() +#endif +#ifndef AddCustomCPP +#define AddCustomCPP(...) +#endif +#ifndef AddOptionRTC +#define AddOptionRTC(...) AddOption(__VA_ARGS__) +#endif +#ifndef AddVariableRTC +#define AddVariableRTC(...) AddVariable(__VA_ARGS__) +#endif +#ifndef AddOptionArrayRTC +#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) +#endif +#ifndef BeginHiddenConfig +#define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, , , , ) +#endif + +#include "qconfigoptions.h" + +#undef AddOption +#undef AddOptionRTC +#undef AddVariable +#undef AddVariableRTC +#undef AddOptionSet +#undef AddOptionVec +#undef AddOptionArray +#undef AddOptionArrayRTC +#undef AddArrayDefaults +#undef AddSubConfig +#undef BeginConfig +#undef BeginSubConfig +#undef BeginHiddenConfig +#undef EndConfig +#undef AddHelp +#undef AddHelpAll +#undef AddHelpText +#undef AddCommand +#undef AddShortcut +#undef BeginNamespace +#undef EndNamespace +#undef AddCustomCPP +#ifdef QCONFIG_COMPARE +#undef QCONFIG_COMPARE +#endif + +#else +#undef QCONFIG_HEADER_GUARD_NO_INCLUDE +#endif From 600f9b316d4794d4bf713a08a7100e87982fab94 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 15 Oct 2026 22:04:30 +0000 Subject: [PATCH 4/4] Please consider the following formatting changes --- GPU/GPUTracking/utils/qconfig.h | 1 - GPU/GPUTracking/utils/qconfig_internal.h | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GPUTracking/utils/qconfig.h b/GPU/GPUTracking/utils/qconfig.h index 87d837a083e94..729e1d51292bb 100644 --- a/GPU/GPUTracking/utils/qconfig.h +++ b/GPU/GPUTracking/utils/qconfig.h @@ -21,7 +21,6 @@ __VA_ARGS__ \ } - #if defined(QCONFIG_HEADER_GUARD) && !defined(QCONFIG_GENRTC) #define QCONFIG_HEADER_GUARD_NO_INCLUDE #else diff --git a/GPU/GPUTracking/utils/qconfig_internal.h b/GPU/GPUTracking/utils/qconfig_internal.h index e7bcbc80695c2..01ac20e9f5d57 100644 --- a/GPU/GPUTracking/utils/qconfig_internal.h +++ b/GPU/GPUTracking/utils/qconfig_internal.h @@ -91,11 +91,14 @@ if (0) { \ } -#define EndConfig() \ - else { tmpfound = false; } \ - if (tmpfound) { \ - found = true; \ - } \ +#define EndConfig() \ + else \ + { \ + tmpfound = false; \ + } \ + if (tmpfound) { \ + found = true; \ + } \ } #define AddHelp(cmd, cmdshort) \