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