Skip to content

Commit cbf4d8b

Browse files
authored
DPL GUI: make some progress towards remote gui integration (#7338)
1 parent e3e4f48 commit cbf4d8b

6 files changed

Lines changed: 191 additions & 12 deletions

File tree

Framework/Core/include/Framework/DeviceMetricsHelper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
namespace o2::framework
2626
{
27+
struct DriverInfo;
2728

2829
struct DeviceMetricsHelper {
2930
/// Type of the callback which can be provided to be invoked every time a new
@@ -125,6 +126,8 @@ struct DeviceMetricsHelper {
125126
size_t metricIndex = bookNumericMetric<T>(metrics, name, newMetricsCallback);
126127
return getNumericMetricCursor<T>(metricIndex);
127128
}
129+
130+
static void updateMetricsNames(DriverInfo& driverInfo, std::vector<DeviceMetricsInfo> const& metricsInfos);
128131
};
129132

130133
} // namespace o2::framework

Framework/Core/src/DPLWebSocket.cxx

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "Framework/DevicesManager.h"
1717
#include "DriverServerContext.h"
1818
#include "DriverClientContext.h"
19+
#include "GuiCallbackContext.h"
1920
#include "HTTPParser.h"
2021
#include <algorithm>
2122
#include <atomic>
@@ -89,6 +90,91 @@ void ws_handshake_done_callback(uv_write_t* h, int status)
8990
uv_read_start((uv_stream_t*)h->handle, (uv_alloc_cb)my_alloc_cb, websocket_server_callback);
9091
}
9192

93+
enum struct GUIOpcodes : uint8_t {
94+
Mousepos = 1,
95+
Mouseclick = 2,
96+
Mousewheel = 3,
97+
Window = 4,
98+
Latency = 5,
99+
Keydown = 6,
100+
Keyup = 7,
101+
Charin = 8
102+
};
103+
104+
/// An handler for a websocket message stream.
105+
struct GUIWebSocketHandler : public WebSocketHandler {
106+
GUIWebSocketHandler(DriverServerContext& context, GuiRenderer* renderer)
107+
: mContext{context}, mRenderer{renderer}
108+
{
109+
}
110+
~GUIWebSocketHandler() override
111+
{
112+
mContext.gui->renderers.erase(mRenderer);
113+
uv_timer_stop(&(mRenderer->drawTimer));
114+
delete mRenderer;
115+
LOGP(INFO, "RemoteGUI disconnected, {} left", mContext.gui->renderers.size());
116+
}
117+
118+
void headers(std::map<std::string, std::string> const& headers) override {}
119+
void beginFragmentation() override {}
120+
void frame(char const* frame, size_t s) override
121+
{
122+
GUIOpcodes opcode = (GUIOpcodes) * (frame++);
123+
switch (opcode) {
124+
case GUIOpcodes::Mousepos: {
125+
float* positions = (float*)frame;
126+
mContext.gui->plugin->updateMousePos(positions[0], positions[1]);
127+
break;
128+
}
129+
case GUIOpcodes::Mouseclick: {
130+
char isClicked = *frame;
131+
mContext.gui->plugin->updateMouseButton(isClicked == 1);
132+
break;
133+
}
134+
case GUIOpcodes::Mousewheel: {
135+
int movement = *frame;
136+
mContext.gui->plugin->updateMouseWheel(movement);
137+
break;
138+
}
139+
case GUIOpcodes::Window: {
140+
int* size = (int*)frame;
141+
mContext.gui->plugin->updateWindowSize(size[0], size[1]);
142+
break;
143+
}
144+
case GUIOpcodes::Latency: {
145+
int lat = *((int*)frame);
146+
lat = lat < 20 ? 20 : lat;
147+
uv_timer_set_repeat(&(mRenderer->drawTimer), lat);
148+
break;
149+
}
150+
case GUIOpcodes::Keydown: {
151+
char key = *frame;
152+
mContext.gui->plugin->keyDown(key);
153+
break;
154+
}
155+
case GUIOpcodes::Keyup: {
156+
char key = *frame;
157+
mContext.gui->plugin->keyUp(key);
158+
break;
159+
}
160+
case GUIOpcodes::Charin: {
161+
char key = *frame;
162+
mContext.gui->plugin->charIn(key);
163+
break;
164+
}
165+
}
166+
}
167+
void endFragmentation() override{};
168+
void control(char const* frame, size_t s) override{};
169+
void beginChunk() override{};
170+
void endChunk() override{};
171+
172+
/// The driver context were we want to accumulate changes
173+
/// which we got from the websocket.
174+
DriverServerContext& mContext;
175+
GuiRenderer* mRenderer;
176+
};
177+
92178
WSDPLHandler::WSDPLHandler(uv_stream_t* s, DriverServerContext* context, std::unique_ptr<WebSocketHandler> h)
93179
: mStream{s},
94180
mServerContext{context},
@@ -123,6 +209,39 @@ void populateHeader(std::map<std::string, std::string>& headers, std::string_vie
123209
headers.insert(std::make_pair(kk, vv));
124210
}
125211

212+
void remoteGuiCallback(uv_timer_s* ctx)
213+
{
214+
GuiRenderer* renderer = reinterpret_cast<GuiRenderer*>(ctx->data);
215+
216+
void* frame = nullptr;
217+
void* draw_data = nullptr;
218+
int size;
219+
uint64_t frameStart = uv_hrtime();
220+
uint64_t frameLatency = frameStart - renderer->gui->frameLast;
221+
222+
// if less than 15ms have passed reuse old frame
223+
if (frameLatency / 1000000 > 15) {
224+
renderer->gui->plugin->pollGUIPreRender(renderer->gui->window, (float)frameLatency / 1000000000.0f);
225+
draw_data = renderer->gui->plugin->pollGUIRender(renderer->gui->callback);
226+
} else {
227+
draw_data = renderer->gui->lastFrame;
228+
}
229+
230+
renderer->gui->plugin->getFrameRaw(draw_data, &frame, &size);
231+
std::vector<uv_buf_t> outputs;
232+
encode_websocket_frames(outputs, (const char*)frame, size, WebSocketOpCode::Binary, 0);
233+
renderer->handler->write(outputs);
234+
free(frame);
235+
236+
if (frameLatency / 1000000 > 15) {
237+
uint64_t frameEnd = uv_hrtime();
238+
*(renderer->gui->frameCost) = (frameEnd - frameStart) / 1000000;
239+
*(renderer->gui->frameLatency) = frameLatency / 1000000;
240+
renderer->gui->frameLast = frameStart;
241+
renderer->gui->lastFrame = draw_data;
242+
}
243+
}
244+
126245
void WSDPLHandler::header(std::string_view const& k, std::string_view const& v)
127246
{
128247
populateHeader(mHeaders, k, v);

Framework/Core/src/DeviceMetricsHelper.cxx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// or submit itself to any jurisdiction.
1111

1212
#include "Framework/DeviceMetricsHelper.h"
13+
#include "Framework/DriverInfo.h"
1314
#include "Framework/RuntimeError.h"
1415
#include <cassert>
1516
#include <cinttypes>
@@ -21,6 +22,7 @@
2122
#include <tuple>
2223
#include <iostream>
2324
#include <limits>
25+
#include <unordered_set>
2426

2527
namespace o2::framework
2628
{
@@ -332,4 +334,21 @@ size_t DeviceMetricsHelper::metricIdxByName(const std::string& name, const Devic
332334
return i;
333335
}
334336

337+
void DeviceMetricsHelper::updateMetricsNames(DriverInfo& driverInfo, std::vector<DeviceMetricsInfo> const& metricsInfos)
338+
{
339+
// Calculate the unique set of metrics, as available in the metrics service
340+
static std::unordered_set<std::string> allMetricsNames;
341+
for (const auto& metricsInfo : metricsInfos) {
342+
for (const auto& labelsPairs : metricsInfo.metricLabels) {
343+
allMetricsNames.insert(std::string(labelsPairs.label));
344+
}
345+
}
346+
for (const auto& labelsPairs : driverInfo.metrics.metricLabels) {
347+
allMetricsNames.insert(std::string(labelsPairs.label));
348+
}
349+
std::vector<std::string> result(allMetricsNames.begin(), allMetricsNames.end());
350+
std::sort(result.begin(), result.end());
351+
driverInfo.availableMetrics.swap(result);
352+
}
353+
335354
} // namespace o2::framework

Framework/Core/src/DriverServerContext.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "Framework/DeviceControl.h"
1919
#include "Framework/DeviceMetricsInfo.h"
2020
#include "Framework/ServiceSpec.h"
21+
#include "GuiCallbackContext.h"
2122

2223
#include <uv.h>
2324
#include <vector>
@@ -26,6 +27,7 @@ namespace o2::framework
2627
{
2728
struct DriverInfo;
2829
struct ServiceRegistry;
30+
struct GuiCallbackContext;
2931

3032
struct DriverServerContext {
3133
uv_loop_t* loop;
@@ -34,8 +36,9 @@ struct DriverServerContext {
3436
std::vector<DeviceInfo>* infos = nullptr;
3537
std::vector<DeviceSpec>* specs = nullptr;
3638
std::vector<DeviceMetricsInfo>* metrics = nullptr;
37-
std::vector<ServiceMetricHandling>* metricProcessingCallbacks;
38-
DriverInfo* driver;
39+
std::vector<ServiceMetricHandling>* metricProcessingCallbacks = nullptr;
40+
DriverInfo* driver = nullptr;
41+
GuiCallbackContext* gui = nullptr;
3942
};
4043
} // namespace o2::framework
4144

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
/// Helper struct which holds all the lists the Driver needs to know about.
12+
#ifndef O2_FRAMEWORK_GUICALLBACKCONTEXT_H_
13+
#define O2_FRAMEWORK_GUICALLBACKCONTEXT_H_
14+
15+
#include "Framework/DebugGUI.h"
16+
#include "Framework/DeviceState.h"
17+
18+
#include <functional>
19+
20+
namespace o2::framework
21+
{
22+
23+
struct GuiCallbackContext;
24+
class WSDPLHandler;
25+
26+
struct GuiRenderer {
27+
uv_timer_t drawTimer;
28+
WSDPLHandler* handler;
29+
GuiCallbackContext* gui;
30+
};
31+
32+
struct GuiCallbackContext {
33+
uint64_t frameLast;
34+
float* frameLatency;
35+
float* frameCost;
36+
void* lastFrame;
37+
DebugGUI* plugin;
38+
void* window;
39+
bool* guiQuitRequested;
40+
std::function<void(void)> callback;
41+
std::set<GuiRenderer*> renderers;
42+
};
43+
} // namespace o2::framework
44+
45+
#endif // O2_FRAMEWORK_GUICALLBACKCONTEXT_H_

Framework/Core/src/runDataProcessing.cxx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,16 +1103,6 @@ struct WorkflowInfo {
11031103
std::vector<ConfigParamSpec> options;
11041104
};
11051105

1106-
struct GuiCallbackContext {
1107-
uint64_t frameLast;
1108-
float* frameLatency;
1109-
float* frameCost;
1110-
DebugGUI* plugin;
1111-
void* window;
1112-
bool* guiQuitRequested;
1113-
std::function<void(void)> callback;
1114-
};
1115-
11161106
void gui_callback(uv_timer_s* ctx)
11171107
{
11181108
GuiCallbackContext* gui = reinterpret_cast<GuiCallbackContext*>(ctx->data);

0 commit comments

Comments
 (0)