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_BUILD_EVENT_DISPLAY_VULKAN
21#define GLFW_INCLUDE_VULKAN
22#endif
23#include <GLFW/glfw3.h>
24
25#include <cstdio>
26#include <cstring>
27#include <unistd.h>
28
29using namespace o2::gpu;
30
36
37static GPUDisplayFrontendGlfw* me = nullptr;
38
39int32_t GPUDisplayFrontendGlfw::GetKey(int32_t key)
40{
41 if (key == GLFW_KEY_KP_SUBTRACT) {
42 return ('-');
43 }
44 if (key == GLFW_KEY_KP_ADD) {
45 return ('+');
46 }
47 if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) {
48 return (KEY_SHIFT);
49 }
50 if (key == GLFW_KEY_LEFT_ALT) {
51 return (KEY_ALT);
52 }
53 if (key == GLFW_KEY_RIGHT_ALT) {
54 return (KEY_RALT);
55 }
56 if (key == GLFW_KEY_LEFT_CONTROL) {
57 return (KEY_CTRL);
58 }
59 if (key == GLFW_KEY_RIGHT_CONTROL) {
60 return (KEY_RCTRL);
61 }
62 if (key == GLFW_KEY_UP) {
63 return (KEY_UP);
64 }
65 if (key == GLFW_KEY_DOWN) {
66 return (KEY_DOWN);
67 }
68 if (key == GLFW_KEY_LEFT) {
69 return (KEY_LEFT);
70 }
71 if (key == GLFW_KEY_RIGHT) {
72 return (KEY_RIGHT);
73 }
74 if (key == GLFW_KEY_PAGE_UP) {
75 return (KEY_PAGEUP);
76 }
77 if (key == GLFW_KEY_PAGE_DOWN) {
78 return (KEY_PAGEDOWN);
79 }
80 if (key == GLFW_KEY_ESCAPE) {
81 return (KEY_ESCAPE);
82 }
83 if (key == GLFW_KEY_SPACE) {
84 return (KEY_SPACE);
85 }
86 if (key == GLFW_KEY_HOME) {
87 return (KEY_HOME);
88 }
89 if (key == GLFW_KEY_END) {
90 return (KEY_END);
91 }
92 if (key == GLFW_KEY_INSERT) {
93 return (KEY_INSERT);
94 }
95 if (key == GLFW_KEY_ENTER) {
96 return (KEY_ENTER);
97 }
98 if (key == GLFW_KEY_F1) {
99 return (KEY_F1);
100 }
101 if (key == GLFW_KEY_F2) {
102 return (KEY_F2);
103 }
104 if (key == GLFW_KEY_F3) {
105 return (KEY_F3);
106 }
107 if (key == GLFW_KEY_F4) {
108 return (KEY_F4);
109 }
110 if (key == GLFW_KEY_F5) {
111 return (KEY_F5);
112 }
113 if (key == GLFW_KEY_F6) {
114 return (KEY_F6);
115 }
116 if (key == GLFW_KEY_F7) {
117 return (KEY_F7);
118 }
119 if (key == GLFW_KEY_F8) {
120 return (KEY_F8);
121 }
122 if (key == GLFW_KEY_F9) {
123 return (KEY_F9);
124 }
125 if (key == GLFW_KEY_F10) {
126 return (KEY_F10);
127 }
128 if (key == GLFW_KEY_F11) {
129 return (KEY_F11);
130 }
131 if (key == GLFW_KEY_F12) {
132 return (KEY_F12);
133 }
134 return (0);
135}
136
137void GPUDisplayFrontendGlfw::GetKey(int32_t key, int32_t scancode, int32_t mods, int32_t& keyOut, int32_t& keyPressOut)
138{
139 int32_t specialKey = GetKey(key);
140 const char* str = glfwGetKeyName(key, scancode);
141 char localeKey = str ? str[0] : 0;
142 if ((mods & GLFW_MOD_SHIFT) && localeKey >= 'a' && localeKey <= 'z') {
143 localeKey += 'A' - 'a';
144 }
145 // GPUInfo("Key: key %d (%c) scancode %d -> %d (%c) special %d (%c)", key, (char)key, scancode, (int32_t)localeKey, localeKey, specialKey, (char)specialKey);
146
147 if (specialKey) {
148 keyOut = keyPressOut = specialKey;
149 } else {
150 keyOut = keyPressOut = (uint8_t)localeKey;
151 if (keyPressOut >= 'a' && keyPressOut <= 'z') {
152 keyPressOut += 'A' - 'a';
153 }
154 }
155}
156
157void GPUDisplayFrontendGlfw::error_callback(int32_t error, const char* description) { fprintf(stderr, "Error: %s\n", description); }
158
159void GPUDisplayFrontendGlfw::key_callback(GLFWwindow* window, int32_t key, int32_t scancode, int32_t action, int32_t mods)
160{
161 int32_t handleKey = 0, keyPress = 0;
162 GetKey(key, scancode, mods, handleKey, keyPress);
163 if (handleKey < 32) {
164 if (action == GLFW_PRESS) {
165 me->mKeys[keyPress] = true;
166 me->mKeysShift[keyPress] = mods & GLFW_MOD_SHIFT;
167 me->HandleKey(handleKey);
168 } else if (action == GLFW_RELEASE) {
169 me->mKeys[keyPress] = false;
170 me->mKeysShift[keyPress] = false;
171 }
172 } else if (handleKey < 256) {
173 if (action == GLFW_PRESS) {
174 me->mLastKeyDown = handleKey;
175 } else if (action == GLFW_RELEASE) {
176 keyPress = (uint8_t)me->mKeyDownMap[handleKey];
177 me->mKeys[keyPress] = false;
178 me->mKeysShift[keyPress] = false;
179 }
180 }
181}
182
183void GPUDisplayFrontendGlfw::char_callback(GLFWwindow* window, uint32_t codepoint)
184{
185 // GPUInfo("Key (char callback): %d %c - key: %d", codepoint, (char)codepoint, (int32_t)me->mLastKeyDown);
186 if (codepoint < 256) {
187 uint8_t keyPress = codepoint;
188 if (keyPress >= 'a' && keyPress <= 'z') {
189 keyPress += 'A' - 'a';
190 }
191 me->mKeyDownMap[me->mLastKeyDown] = keyPress;
192 me->mKeys[keyPress] = true;
193 me->mKeysShift[keyPress] = me->mKeys[KEY_SHIFT];
194 me->HandleKey(codepoint);
195 }
196}
197
198void GPUDisplayFrontendGlfw::mouseButton_callback(GLFWwindow* window, int32_t button, int32_t action, int32_t mods)
199{
200 if (action == GLFW_PRESS) {
201 if (button == 0) {
202 me->mMouseDn = true;
203 } else if (button == 1) {
204 me->mMouseDnR = true;
205 } else if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
206 me->mMouseDnM = true;
207 }
208 me->mMouseDnX = me->mMouseMvX;
209 me->mMouseDnY = me->mMouseMvY;
210 } else if (action == GLFW_RELEASE) {
211 if (button == 0) {
212 me->mMouseDn = false;
213 } else if (button == 1) {
214 me->mMouseDnR = false;
215 } else if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
216 me->mMouseDnM = false;
217 }
218 }
219}
220
221void GPUDisplayFrontendGlfw::scroll_callback(GLFWwindow* window, double x, double y) { me->mMouseWheel += y * 100; }
222
223void GPUDisplayFrontendGlfw::cursorPos_callback(GLFWwindow* window, double x, double y)
224{
225 me->mMouseMvX = x * me->mPixelRatio; // Window coordinates to framebuffer pixels
226 me->mMouseMvY = y * me->mPixelRatio;
227}
228
229void GPUDisplayFrontendGlfw::resize_callback(GLFWwindow* window, int32_t width, int32_t height) // Framebuffer size in pixels
230{
231 int32_t windowWidth, windowHeight;
232 glfwGetWindowSize(window, &windowWidth, &windowHeight);
233 me->mPixelRatio = windowWidth ? (double)width / windowWidth : 1.;
234 me->ResizeScene(width, height);
235}
236
237void GPUDisplayFrontendGlfw::focus_callback(GLFWwindow* window, int32_t focused)
238{
239 if (!focused) {
240 me->focusLost();
241 }
242}
243
244void GPUDisplayFrontendGlfw::contentScale_callback(GLFWwindow* window, float xscale, float yscale)
245{
246 me->mScale = xscale;
247}
248
249void GPUDisplayFrontendGlfw::maximize_callback(GLFWwindow* window, int32_t maximized)
250{
251 me->setWindowState(glfwGetWindowMonitor(window) != nullptr, maximized);
252 if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) { // Called before the resize. GLFW keeps the maximized size if the compositor leaves the size to the client when unmaximizing, so restore the last windowed size
253 if (maximized) {
254 glfwGetWindowSize(window, &me->mWindowedWidth, &me->mWindowedHeight);
255 } else {
256 me->mRestoreWindowedSize = true; // Must be applied after GLFW has processed the configure event, otherwise GLFW resizes to the pending maximized size again
257 }
258 }
259}
260
261int32_t GPUDisplayFrontendGlfw::FrontendMain()
262{
263 me = this;
264
265 if (!glfwInit()) {
266 fprintf(stderr, "Error initializing glfw\n");
267 return (-1);
268 }
269 glfwSetErrorCallback(error_callback);
270
271 if (backend()->backendType() == GPUDisplayBackend::TYPE_VULKAN) {
272 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
273 }
274 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
275 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GL_MIN_VERSION_MAJOR);
276 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GL_MIN_VERSION_MINOR);
277 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 0);
278 glfwWindowHint(GLFW_OPENGL_PROFILE, mBackend->CoreProfile() ? GLFW_OPENGL_CORE_PROFILE : GLFW_OPENGL_COMPAT_PROFILE);
279 }
280 glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Initial size scaled by the content scale on X11 / Win32
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 glfwSetFramebufferSizeCallback(mWindow, resize_callback);
297 glfwSetWindowMaximizeCallback(mWindow, maximize_callback);
298 glfwSetWindowFocusCallback(mWindow, focus_callback);
299 float xscale, yscale;
300 glfwGetWindowContentScale(mWindow, &xscale, &yscale);
301 contentScale_callback(mWindow, xscale, yscale);
302 glfwSetWindowContentScaleCallback(mWindow, contentScale_callback);
303 const float limitScale = (glfwGetPlatform() == GLFW_PLATFORM_X11 || glfwGetPlatform() == GLFW_PLATFORM_WIN32) ? mScale : 1.f; // Window coordinates are pixels on X11 / Win32, logical on Wayland / macOS
304 glfwSetWindowSizeLimits(mWindow, MIN_WIDTH * limitScale, MIN_HEIGHT * limitScale, GLFW_DONT_CARE, GLFW_DONT_CARE);
305 int32_t fbWidth, fbHeight, windowWidth, windowHeight;
306 glfwGetFramebufferSize(mWindow, &fbWidth, &fbHeight);
307 glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
308 mPixelRatio = windowWidth ? (double)fbWidth / windowWidth : 1.; // Updated in resize_callback, which must not be called before InitDisplay
311
312 if (mBackend->ExtInit()) {
313 fprintf(stderr, "Error initializing GL extension wrapper\n");
314 return (-1);
315 }
316
317 if (InitDisplay()) {
318 fprintf(stderr, "Error in GLFW display initialization\n");
319 return (1);
320 }
321
322 {
323 std::lock_guard lock(mExitStateMutex);
324 mDisplayRunning = true; // Only after successful initialization, StopDisplay waits for it to become false again
325 }
326
327 int32_t retVal = 0;
328 while (!glfwWindowShouldClose(mWindow)) {
330 if (DrawGLScene()) {
331 fprintf(stderr, "Error drawing GL scene\n");
332 retVal = 1;
333 break; // Cleanup below
334 }
335 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
336 glfwSwapBuffers(mWindow);
337 }
339 glfwPollEvents();
340 if (mRestoreWindowedSize) {
341 mRestoreWindowedSize = false;
342 if (mWindowedWidth > 0 && mWindowedHeight > 0 && !glfwGetWindowAttrib(mWindow, GLFW_MAXIMIZED)) {
343 glfwSetWindowSize(mWindow, mWindowedWidth, mWindowedHeight);
344 }
345 }
346 }
347
348 ExitDisplay();
349 {
350 std::lock_guard lock(mExitStateMutex);
351 mDisplayControl = 2;
352 glfwDestroyWindow(mWindow);
353 glfwTerminate();
354 mDisplayRunning = false;
355 }
356
357 return retVal;
358}
359
361{
362 glfwSetWindowShouldClose(mWindow, true);
363}
364
365void GPUDisplayFrontendGlfw::OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton)
366{
367}
368
370{
371 GPUInfo("Setting Full Screen %d", (int32_t)set);
372 if (set) {
373 glfwGetWindowPos(mWindow, &mWindowX, &mWindowY);
374 glfwGetWindowSize(mWindow, &mWindowWidth, &mWindowHeight);
375 GLFWmonitor* primary = glfwGetPrimaryMonitor();
376 const GLFWvidmode* mode = glfwGetVideoMode(primary);
377 glfwSetWindowMonitor(mWindow, primary, 0, 0, mode->width, mode->height, mode->refreshRate);
378 } else {
379 glfwSetWindowMonitor(mWindow, nullptr, mWindowX, mWindowY, mWindowWidth, mWindowHeight, GLFW_DONT_CARE);
380 }
381}
382
384{
385 if (set) {
386 glfwMaximizeWindow(mWindow);
387 } else {
388 glfwRestoreWindow(mWindow);
389 }
390}
391
393{
394 if (canSetVSync()) { // No GL context with Vulkan
395 glfwSwapInterval(enable);
396 }
397}
398
400
402{
403 GLFWmonitor* monitor = glfwGetWindowMonitor(mWindow) ? glfwGetWindowMonitor(mWindow) : glfwGetPrimaryMonitor(); // Monitor of a windowed window is not known, use the primary one
404 const GLFWvidmode* mode = monitor ? glfwGetVideoMode(monitor) : nullptr;
405 return mode ? mode->refreshRate : 0.f;
406}
407
409{
410 glfwGetFramebufferSize(mWindow, &width, &height);
411}
412
414{
415#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
416 return glfwCreateWindowSurface(*(VkInstance*)instance, mWindow, nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
417#else
418 return 1;
419#endif
420}
421
423{
424 uint32_t glfwExtensionCount = 0;
425#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
426 p = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
427#endif
428 return glfwExtensionCount;
429}
header::DataDescription description
int32_t retVal
char error[CURL_ERROR_SIZE]
const Acts::Surface * surface
StringRef key
backendTypes backendType() const
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 MIN_WIDTH
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_RCTRL
static constexpr int32_t MIN_HEIGHT
static constexpr int32_t KEY_ESCAPE
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