Project
Loading...
Searching...
No Matches
GPUDisplayFrontendGlfw.cxx
Go to the documentation of this file.
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
14
18#include "GPULogging.h"
19
20#ifdef GPUCA_O2_LIB
21#undef GPUCA_O2_LIB
22#endif
23
24#if defined(GPUCA_O2_LIB) && !defined(GPUCA_DISPLAY_GL3W) // Hack: we have to define this in order to initialize gl3w, cannot include the header as it clashes with glew
25extern "C" int32_t gl3wInit();
26#endif
27
28#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
29#define GLFW_INCLUDE_VULKAN
30#endif
31#include <GLFW/glfw3.h>
32
33#include <cstdio>
34#include <cstring>
35#include <unistd.h>
36#include <pthread.h>
37
38#ifdef GPUCA_O2_LIB
39#if __has_include("../src/imgui.h")
40#include "../src/imgui.h"
41#include "../src/imgui_impl_glfw_gl3.h"
42#else
43#include "DebugGUI/imgui.h"
44#include "DebugGUI/imgui_impl_glfw_gl3.h"
45#endif
46#include <DebugGUI/DebugGUI.h>
47#endif
48
49using namespace o2::gpu;
50
56
57static GPUDisplayFrontendGlfw* me = nullptr;
58
59int32_t GPUDisplayFrontendGlfw::GetKey(int32_t key)
60{
61 if (key == GLFW_KEY_KP_SUBTRACT) {
62 return ('-');
63 }
64 if (key == GLFW_KEY_KP_ADD) {
65 return ('+');
66 }
67 if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) {
68 return (KEY_SHIFT);
69 }
70 if (key == GLFW_KEY_LEFT_ALT) {
71 return (KEY_ALT);
72 }
73 if (key == GLFW_KEY_RIGHT_ALT) {
74 return (KEY_RALT);
75 }
76 if (key == GLFW_KEY_LEFT_CONTROL) {
77 return (KEY_CTRL);
78 }
79 if (key == GLFW_KEY_RIGHT_CONTROL) {
80 return (KEY_RCTRL);
81 }
82 if (key == GLFW_KEY_UP) {
83 return (KEY_UP);
84 }
85 if (key == GLFW_KEY_DOWN) {
86 return (KEY_DOWN);
87 }
88 if (key == GLFW_KEY_LEFT) {
89 return (KEY_LEFT);
90 }
91 if (key == GLFW_KEY_RIGHT) {
92 return (KEY_RIGHT);
93 }
94 if (key == GLFW_KEY_PAGE_UP) {
95 return (KEY_PAGEUP);
96 }
97 if (key == GLFW_KEY_PAGE_DOWN) {
98 return (KEY_PAGEDOWN);
99 }
100 if (key == GLFW_KEY_ESCAPE) {
101 return (KEY_ESCAPE);
102 }
103 if (key == GLFW_KEY_SPACE) {
104 return (KEY_SPACE);
105 }
106 if (key == GLFW_KEY_HOME) {
107 return (KEY_HOME);
108 }
109 if (key == GLFW_KEY_END) {
110 return (KEY_END);
111 }
112 if (key == GLFW_KEY_INSERT) {
113 return (KEY_INSERT);
114 }
115 if (key == GLFW_KEY_ENTER) {
116 return (KEY_ENTER);
117 }
118 if (key == GLFW_KEY_F1) {
119 return (KEY_F1);
120 }
121 if (key == GLFW_KEY_F2) {
122 return (KEY_F2);
123 }
124 if (key == GLFW_KEY_F3) {
125 return (KEY_F3);
126 }
127 if (key == GLFW_KEY_F4) {
128 return (KEY_F4);
129 }
130 if (key == GLFW_KEY_F5) {
131 return (KEY_F5);
132 }
133 if (key == GLFW_KEY_F6) {
134 return (KEY_F6);
135 }
136 if (key == GLFW_KEY_F7) {
137 return (KEY_F7);
138 }
139 if (key == GLFW_KEY_F8) {
140 return (KEY_F8);
141 }
142 if (key == GLFW_KEY_F9) {
143 return (KEY_F9);
144 }
145 if (key == GLFW_KEY_F10) {
146 return (KEY_F10);
147 }
148 if (key == GLFW_KEY_F11) {
149 return (KEY_F11);
150 }
151 if (key == GLFW_KEY_F12) {
152 return (KEY_F12);
153 }
154 return (0);
155}
156
157void GPUDisplayFrontendGlfw::GetKey(int32_t key, int32_t scancode, int32_t mods, int32_t& keyOut, int32_t& keyPressOut)
158{
159 int32_t specialKey = GetKey(key);
160 const char* str = glfwGetKeyName(key, scancode);
161 char localeKey = str ? str[0] : 0;
162 if ((mods & GLFW_MOD_SHIFT) && localeKey >= 'a' && localeKey <= 'z') {
163 localeKey += 'A' - 'a';
164 }
165 // GPUInfo("Key: key %d (%c) scancode %d -> %d (%c) special %d (%c)", key, (char)key, scancode, (int32_t)localeKey, localeKey, specialKey, (char)specialKey);
166
167 if (specialKey) {
168 keyOut = keyPressOut = specialKey;
169 } else {
170 keyOut = keyPressOut = (uint8_t)localeKey;
171 if (keyPressOut >= 'a' && keyPressOut <= 'z') {
172 keyPressOut += 'A' - 'a';
173 }
174 }
175}
176
177void GPUDisplayFrontendGlfw::error_callback(int32_t error, const char* description) { fprintf(stderr, "Error: %s\n", description); }
178
179void GPUDisplayFrontendGlfw::key_callback(GLFWwindow* window, int32_t key, int32_t scancode, int32_t action, int32_t mods)
180{
181 int32_t handleKey = 0, keyPress = 0;
182 GetKey(key, scancode, mods, handleKey, keyPress);
183 if (handleKey < 32) {
184 if (action == GLFW_PRESS) {
185 me->mKeys[keyPress] = true;
186 me->mKeysShift[keyPress] = mods & GLFW_MOD_SHIFT;
187 me->HandleKey(handleKey);
188 } else if (action == GLFW_RELEASE) {
189 me->mKeys[keyPress] = false;
190 me->mKeysShift[keyPress] = false;
191 }
192 } else if (handleKey < 256) {
193 if (action == GLFW_PRESS) {
194 me->mLastKeyDown = handleKey;
195 } else if (action == GLFW_RELEASE) {
196 keyPress = (uint8_t)me->mKeyDownMap[handleKey];
197 me->mKeys[keyPress] = false;
198 me->mKeysShift[keyPress] = false;
199 }
200 }
201}
202
203void GPUDisplayFrontendGlfw::char_callback(GLFWwindow* window, uint32_t codepoint)
204{
205 // GPUInfo("Key (char callback): %d %c - key: %d", codepoint, (char)codepoint, (int32_t)me->mLastKeyDown);
206 if (codepoint < 256) {
207 uint8_t keyPress = codepoint;
208 if (keyPress >= 'a' && keyPress <= 'z') {
209 keyPress += 'A' - 'a';
210 }
211 me->mKeyDownMap[me->mLastKeyDown] = keyPress;
212 me->mKeys[keyPress] = true;
213 me->mKeysShift[keyPress] = me->mKeys[KEY_SHIFT];
214 me->HandleKey(codepoint);
215 }
216}
217
218void GPUDisplayFrontendGlfw::mouseButton_callback(GLFWwindow* window, int32_t button, int32_t action, int32_t mods)
219{
220 if (action == GLFW_PRESS) {
221 if (button == 0) {
222 me->mMouseDn = true;
223 } else if (button == 1) {
224 me->mMouseDnR = true;
225 }
226 me->mMouseDnX = me->mMouseMvX;
227 me->mMouseDnY = me->mMouseMvY;
228 } else if (action == GLFW_RELEASE) {
229 if (button == 0) {
230 me->mMouseDn = false;
231 } else if (button == 1) {
232 me->mMouseDnR = false;
233 }
234 }
235}
236
237void GPUDisplayFrontendGlfw::scroll_callback(GLFWwindow* window, double x, double y) { me->mMouseWheel += y * 100; }
238
239void GPUDisplayFrontendGlfw::cursorPos_callback(GLFWwindow* window, double x, double y)
240{
241 me->mMouseMvX = x;
242 me->mMouseMvY = y;
243}
244
245void GPUDisplayFrontendGlfw::resize_callback(GLFWwindow* window, int32_t width, int32_t height) { me->ResizeScene(width, height); }
246
247#ifdef GPUCA_O2_LIB
248void GPUDisplayFrontendGlfw::DisplayLoop()
249{
250 ImGui::SetNextWindowPos(ImVec2(0, 0));
251 ImGui::SetNextWindowSize(ImVec2(me->mDisplayWidth, me->mDisplayHeight));
252 ImGui::SetNextWindowBgAlpha(0.f);
253 ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
254 me->DrawGLScene();
255 ImGui::End();
256}
257#endif
258
259int32_t GPUDisplayFrontendGlfw::FrontendMain()
260{
261 me = this;
262
263 if (!glfwInit()) {
264 fprintf(stderr, "Error initializing glfw\n");
265 return (-1);
266 }
267 glfwSetErrorCallback(error_callback);
268
269 glfwWindowHint(GLFW_MAXIMIZED, 1);
270 if (backend()->backendType() == GPUDisplayBackend::TYPE_VULKAN) {
271 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
272 }
273 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
274 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GL_MIN_VERSION_MAJOR);
275 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GL_MIN_VERSION_MINOR);
276 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 0);
277 glfwWindowHint(GLFW_OPENGL_PROFILE, mBackend->CoreProfile() ? GLFW_OPENGL_CORE_PROFILE : GLFW_OPENGL_COMPAT_PROFILE);
278#ifdef GPUCA_O2_LIB
279 mUseIMGui = true;
280#endif
281 }
282 mWindow = glfwCreateWindow(INIT_WIDTH, INIT_HEIGHT, DISPLAY_WINDOW_NAME, nullptr, nullptr);
283 if (!mWindow) {
284 fprintf(stderr, "Error creating glfw window\n");
285 glfwTerminate();
286 return (-1);
287 }
288 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
289 glfwMakeContextCurrent(mWindow);
290 }
291
292 glfwSetKeyCallback(mWindow, key_callback);
293 glfwSetCharCallback(mWindow, char_callback);
294 glfwSetMouseButtonCallback(mWindow, mouseButton_callback);
295 glfwSetScrollCallback(mWindow, scroll_callback);
296 glfwSetCursorPosCallback(mWindow, cursorPos_callback);
297 glfwSetWindowSizeCallback(mWindow, resize_callback);
298 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
299 glfwSwapInterval(1);
300 }
301
302 pthread_mutex_lock(&mSemLockExit);
303 mGlfwRunning = true;
304 pthread_mutex_unlock(&mSemLockExit);
305
306 if (mBackend->ExtInit()) {
307 fprintf(stderr, "Error initializing GL extension wrapper\n");
308 return (-1);
309 }
310
311#if defined(GPUCA_O2_LIB) && !defined(GPUCA_DISPLAY_GL3W)
312 if (mUseIMGui && gl3wInit()) {
313 fprintf(stderr, "Error initializing gl3w (2)\n");
314 return (-1); // Hack: We have to initialize gl3w as well, as the DebugGUI uses it.
315 }
316#endif
317
318#ifdef GPUCA_O2_LIB
319 if (mUseIMGui) {
320 mCanDrawText = 2;
321 if (drawTextFontSize() == 0) {
322 drawTextFontSize() = 12;
323 }
324 }
325#endif
326
327 if (InitDisplay()) {
328 fprintf(stderr, "Error in GLFW display initialization\n");
329 return (1);
330 }
331
332#ifdef GPUCA_O2_LIB
333 if (mUseIMGui) {
334 ImGui_ImplGlfwGL3_Init(mWindow, false);
335 while (o2::framework::pollGUI(mWindow, DisplayLoop)) {
336 }
337 } else
338#endif
339 {
340 while (!glfwWindowShouldClose(mWindow)) {
342 if (DrawGLScene()) {
343 fprintf(stderr, "Error drawing GL scene\n");
344 return (1);
345 }
346 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
347 glfwSwapBuffers(mWindow);
348 }
349 glfwPollEvents();
350 }
351 }
352
353 ExitDisplay();
354 mDisplayControl = 2;
355 pthread_mutex_lock(&mSemLockExit);
356#ifdef GPUCA_O2_LIB
357 if (mUseIMGui) {
358 ImGui_ImplGlfwGL3_Shutdown();
359 }
360#endif
361 glfwDestroyWindow(mWindow);
362 glfwTerminate();
363 mGlfwRunning = false;
364 pthread_mutex_unlock(&mSemLockExit);
365
366 return 0;
367}
368
370{
371 pthread_mutex_lock(&mSemLockExit);
372 if (mGlfwRunning) {
373 glfwSetWindowShouldClose(mWindow, true);
374 }
375 pthread_mutex_unlock(&mSemLockExit);
376 while (mGlfwRunning) {
377 usleep(10000);
378 }
379}
380
381void GPUDisplayFrontendGlfw::OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton)
382{
383#ifdef GPUCA_O2_LIB
384 if (mUseIMGui) {
385 if (fromBotton) {
386 y = ImGui::GetWindowHeight() - y;
387 }
388 y -= 20;
389 ImGui::SetCursorPos(ImVec2(x, y));
390 ImGui::TextColored(ImVec4(r, g, b, a), "%s", s);
391 }
392#endif
393}
394
396{
397 GPUInfo("Setting Full Screen %d", (int32_t)set);
398 if (set) {
399 glfwGetWindowPos(mWindow, &mWindowX, &mWindowY);
400 glfwGetWindowSize(mWindow, &mWindowWidth, &mWindowHeight);
401 GLFWmonitor* primary = glfwGetPrimaryMonitor();
402 const GLFWvidmode* mode = glfwGetVideoMode(primary);
403 glfwSetWindowMonitor(mWindow, primary, 0, 0, mode->width, mode->height, mode->refreshRate);
404 } else {
405 glfwSetWindowMonitor(mWindow, nullptr, mWindowX, mWindowY, mWindowWidth, mWindowHeight, GLFW_DONT_CARE);
406 }
407}
408
410{
411 if (set) {
412 glfwMaximizeWindow(mWindow);
413 } else {
414 glfwRestoreWindow(mWindow);
415 }
416}
417
418void GPUDisplayFrontendGlfw::SetVSync(bool enable) { glfwSwapInterval(enable); }
419
421{
422 static pthread_t hThread;
423 if (pthread_create(&hThread, nullptr, FrontendThreadWrapper, this)) {
424 GPUError("Coult not Create GL Thread...");
425 return (1);
426 }
427 return (0);
428}
429
431{
432#ifdef GPUCA_O2_LIB
433 return false;
434#else
435 return true;
436#endif
437}
438
440{
441 glfwGetFramebufferSize(mWindow, &width, &height);
442}
443
444int32_t GPUDisplayFrontendGlfw::getVulkanSurface(void* instance, void* surface)
445{
446#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
447 return glfwCreateWindowSurface(*(VkInstance*)instance, mWindow, nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
448#else
449 return 1;
450#endif
451}
452
454{
455 uint32_t glfwExtensionCount = 0;
456#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
457 p = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
458#endif
459 return glfwExtensionCount;
460}
StringRef key
void getSize(int32_t &width, int32_t &height) override
void OpenGLPrint(const char *s, float x, float y, float r, float g, float b, float a, bool fromBotton=true) override
uint32_t getReqVulkanExtensions(const char **&p) override
int32_t getVulkanSurface(void *instance, void *surface) override
static constexpr int32_t KEY_F9
static constexpr int32_t KEY_F2
static void * FrontendThreadWrapper(void *)
static constexpr int32_t KEY_ALT
static constexpr int32_t KEY_F12
static constexpr int32_t KEY_F7
static constexpr int32_t KEY_END
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_RALT
static constexpr int32_t KEY_F10
static constexpr int32_t KEY_F4
static constexpr int32_t KEY_LEFT
static constexpr int32_t KEY_ENTER
static constexpr int32_t KEY_F6
static constexpr int32_t KEY_CTRL
static constexpr int32_t KEY_F1
static constexpr const char * DISPLAY_WINDOW_NAME
static constexpr int32_t INIT_WIDTH
static constexpr int32_t GL_MIN_VERSION_MAJOR
static constexpr int32_t KEY_SHIFT
static constexpr int32_t KEY_F3
static constexpr int32_t KEY_INSERT
static constexpr int32_t KEY_F11
static constexpr int32_t KEY_SPACE
static constexpr int32_t KEY_F5
static constexpr int32_t KEY_PAGEUP
static constexpr int32_t KEY_HOME
static constexpr int32_t GL_MIN_VERSION_MINOR
int32_t InitDisplay(bool initFailure=false)
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t KEY_F8
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_RCTRL
static constexpr int32_t KEY_ESCAPE
int gl3wInit(void)
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum mode
Definition glcorearb.h:266
GLint GLsizei GLsizei height
Definition glcorearb.h:270
GLint GLsizei width
Definition glcorearb.h:270
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
GLboolean GLboolean g
Definition glcorearb.h:1233
GLboolean enable
Definition glcorearb.h:3991
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
uint8_t itsSharedClusterMap uint8_t
constexpr value_T me
Definition TrackUtils.h:128
const std::string str