Atlas - SDL_openvrvideo.c
Home / ext / SDL / src / video / openvr Lines: 1 | Size: 59374 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 2022 Charles Lohr <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_OPENVR 24 25#if 0 26#define DEBUG_OPENVR 27#endif 28 29#include "../../events/SDL_mouse_c.h" 30#include "../../events/SDL_keyboard_c.h" 31#include "../../events/SDL_events_c.h" 32#include "../SDL_sysvideo.h" 33#include "../SDL_pixels_c.h" 34#include "../SDL_egl_c.h" 35#include "SDL_openvrvideo.h" 36 37#include <SDL3/SDL_opengl.h> 38 39#ifdef SDL_VIDEO_DRIVER_WINDOWS 40#include "../windows/SDL_windowsopengles.h" 41#include "../windows/SDL_windowsopengl.h" 42#include "../windows/SDL_windowsvulkan.h" 43#define DEFAULT_OPENGL "OPENGL32.DLL" 44static bool OPENVR_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path); 45static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); 46 47struct SDL_GLContextState 48{ 49 HGLRC hglrc; 50}; 51 52#else 53#include <SDL3/SDL_opengles2_gl2.h> 54#endif 55 56#ifdef SDL_PLATFORM_WINDOWS 57#define SDL_OPENVR_DRIVER_DYNAMIC "openvr_api.dll" 58#else 59#define SDL_OPENVR_DRIVER_DYNAMIC "openvr_api.so" 60#endif 61 62SDL_ELF_NOTE_DLOPEN( 63 "video-openvr", 64 "Support for OpenVR video", 65 SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, 66 SDL_OPENVR_DRIVER_DYNAMIC 67) 68 69#define MARKER_ID 0 70#define MARKER_STR "vr-marker,frame_end,type,application" 71 72#undef EXTERN_C 73 74// For access to functions that don't get the video data context. 75SDL_VideoData * global_openvr_driver; 76 77static void InitializeMouseFunctions(void); 78 79struct SDL_CursorData 80{ 81 unsigned texture_id_handle; 82 int hot_x, hot_y; 83 int w, h; 84}; 85 86// GL Extensions for functions we will be using. 87static void (APIENTRY *ov_glGenFramebuffers)(GLsizei n, GLuint *framebuffers); 88static void (APIENTRY *ov_glGenRenderbuffers)(GLsizei n, GLuint *renderbuffers); 89static void (APIENTRY *ov_glBindFramebuffer)(GLenum target, GLuint framebuffer); 90static void (APIENTRY *ov_glBindRenderbuffer)(GLenum target, GLuint renderbuffer); 91static void (APIENTRY *ov_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); 92static void (APIENTRY *ov_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); 93static void (APIENTRY *ov_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); 94static GLenum (APIENTRY *ov_glCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target); 95static GLenum (APIENTRY *ov_glGetError)(void); 96static void (APIENTRY *ov_glFlush)(void); 97static void (APIENTRY *ov_glFinish)(void); 98static void (APIENTRY *ov_glGenTextures)(GLsizei n, GLuint *textures); 99static void (APIENTRY *ov_glDeleteTextures)(GLsizei n, GLuint *textures); 100static void (APIENTRY *ov_glTexParameterf)(GLenum target, GLenum pname, GLfloat param); 101static void (APIENTRY *ov_glTexParameteri)(GLenum target, GLenum pname, GLenum param); 102static void (APIENTRY *ov_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *data); 103static void (APIENTRY *ov_glBindTexture)(GLenum target, GLuint texture); 104static void (APIENTRY *ov_glDrawBuffers)(GLsizei n, const GLenum *bufs); 105static void (APIENTRY *ov_glGetIntegerv)(GLenum pname, GLint * data); 106static const GLubyte *(APIENTRY *ov_glGetStringi)(GLenum name, GLuint index); 107static void (APIENTRY *ov_glClear)(GLbitfield mask); 108static void (APIENTRY *ov_glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); 109static void (APIENTRY *ov_glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); 110static void (APIENTRY *ov_glDebugMessageInsert)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message); 111 112#ifdef SDL_VIDEO_DRIVER_WINDOWS 113static PROC (*ov_wglGetProcAddress)(LPCSTR); 114static HGLRC (*ov_wglCreateContext)(HDC); 115static BOOL (*ov_wglDeleteContext)(HGLRC); 116static BOOL (*ov_wglMakeCurrent)(HDC, HGLRC); 117//static HGLRC (*ov_wglGetCurrentContext)(void); 118#endif 119 120 121#define OPENVR_DEFAULT_WIDTH 1920 122#define OPENVR_DEFAULT_HEIGHT 1080 123 124#define OPENVR_SetupProc(proc) { proc = (void *)SDL_GL_GetProcAddress((#proc)+3); if (!proc) { failed_extension = (#proc)+3; } } 125 126static bool OPENVR_InitExtensions(SDL_VideoDevice *_this) 127{ 128 if (!ov_glGetError) { 129 const char * failed_extension = 0; 130 OPENVR_SetupProc(ov_glGenFramebuffers); 131 OPENVR_SetupProc(ov_glGenRenderbuffers); 132 OPENVR_SetupProc(ov_glBindFramebuffer); 133 OPENVR_SetupProc(ov_glBindRenderbuffer); 134 OPENVR_SetupProc(ov_glRenderbufferStorage); 135 OPENVR_SetupProc(ov_glFramebufferRenderbuffer); 136 OPENVR_SetupProc(ov_glFramebufferTexture2D); 137 OPENVR_SetupProc(ov_glCheckNamedFramebufferStatus); 138 OPENVR_SetupProc(ov_glGetError); 139 OPENVR_SetupProc(ov_glFlush); 140 OPENVR_SetupProc(ov_glFinish); 141 OPENVR_SetupProc(ov_glGenTextures); 142 OPENVR_SetupProc(ov_glDeleteTextures); 143 OPENVR_SetupProc(ov_glTexParameterf); 144 OPENVR_SetupProc(ov_glTexParameteri); 145 OPENVR_SetupProc(ov_glTexImage2D); 146 OPENVR_SetupProc(ov_glBindTexture); 147 OPENVR_SetupProc(ov_glDrawBuffers); 148 OPENVR_SetupProc(ov_glClear); 149 OPENVR_SetupProc(ov_glClearColor); 150 OPENVR_SetupProc(ov_glColorMask); 151 OPENVR_SetupProc(ov_glGetStringi); 152 OPENVR_SetupProc(ov_glGetIntegerv); 153 OPENVR_SetupProc(ov_glDebugMessageInsert); 154 if (failed_extension) { 155 return SDL_SetError("Error loading GL extension for %s", failed_extension); 156 } 157 } 158 return true; 159} 160 161static bool OPENVR_SetOverlayError(EVROverlayError e) 162{ 163 switch (e) { 164#define CASE(X) case EVROverlayError_VROverlayError_##X: return SDL_SetError("VROverlayError %s", #X) 165 CASE(UnknownOverlay); 166 CASE(InvalidHandle); 167 CASE(PermissionDenied); 168 CASE(OverlayLimitExceeded); 169 CASE(WrongVisibilityType); 170 CASE(KeyTooLong); 171 CASE(NameTooLong); 172 CASE(KeyInUse); 173 CASE(WrongTransformType); 174 CASE(InvalidTrackedDevice); 175 CASE(InvalidParameter); 176 CASE(ThumbnailCantBeDestroyed); 177 CASE(ArrayTooSmall); 178 CASE(RequestFailed); 179 CASE(InvalidTexture); 180 CASE(UnableToLoadFile); 181 CASE(KeyboardAlreadyInUse); 182 CASE(NoNeighbor); 183 CASE(TooManyMaskPrimitives); 184 CASE(BadMaskPrimitive); 185 CASE(TextureAlreadyLocked); 186 CASE(TextureLockCapacityReached); 187 CASE(TextureNotLocked); 188 CASE(TimedOut); 189#undef CASE 190 default: 191 return SDL_SetError("Unknown VROverlayError %d", e); 192 } 193} 194 195static bool OPENVR_InitializeOverlay(SDL_VideoDevice *_this, SDL_Window *window); 196 197static bool OPENVR_VideoInit(SDL_VideoDevice *_this) 198{ 199 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 200 201 const char * hintWidth = SDL_GetHint("SDL_DEFAULT_WIDTH"); 202 const char * hintHeight = SDL_GetHint("SDL_DEFAULT_HEIGHT"); 203 const char * hintFPS = SDL_GetHint("SDL_DEFAULT_FPS"); 204 int width = hintWidth ? SDL_atoi(hintWidth) : 0; 205 int height = hintHeight ? SDL_atoi(hintHeight) : 0; 206 int fps = hintFPS ? SDL_atoi(hintFPS) : 0; 207 208 SDL_VideoDisplay display; 209 SDL_zero(display); 210 display.desktop_mode.format = SDL_PIXELFORMAT_RGBA32; 211 display.desktop_mode.w = OPENVR_DEFAULT_WIDTH; 212 display.desktop_mode.h = OPENVR_DEFAULT_HEIGHT; 213 display.natural_orientation = SDL_ORIENTATION_LANDSCAPE; 214 display.current_orientation = SDL_ORIENTATION_LANDSCAPE; 215 display.content_scale = 1.0f; 216 if (height > 0 && width > 0) { 217 display.desktop_mode.w = width; 218 display.desktop_mode.h = height; 219 } 220 if (fps) { 221 display.desktop_mode.refresh_rate = fps; 222 } else { 223 display.desktop_mode.refresh_rate = data->oSystem->GetFloatTrackedDeviceProperty(k_unTrackedDeviceIndex_Hmd, ETrackedDeviceProperty_Prop_DisplayFrequency_Float, 0); 224 } 225 display.name = (char *)"OpenVRDisplay"; 226 SDL_AddVideoDisplay(&display, false); 227 228 return true; 229} 230 231static void OPENVR_VideoQuit(SDL_VideoDevice *_this) 232{ 233 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 234 if (videodata->bDidCreateOverlay && videodata->overlayID != 0) { 235 videodata->oOverlay->DestroyOverlay(videodata->overlayID); 236 } 237} 238 239static void OPENVR_Destroy(SDL_VideoDevice *device) 240{ 241 SDL_VideoData *data = device->internal; 242 243#ifdef SDL_PLATFORM_WINDOWS 244 SDL_UnregisterApp(); 245#endif 246 247 if (data) { 248 if (data->openVRLIB) { 249 SDL_UnloadObject(data->openVRLIB); 250 } 251 } 252 SDL_free(device->internal); 253 SDL_free(device); 254} 255 256static uint32_t *ImageSDLToOpenVRGL(SDL_Surface * surf, bool bFlipY) 257{ 258 int w = surf->w; 259 int h = surf->h; 260 int pitch = surf->pitch; 261 int x, y; 262 uint32_t * pxd = SDL_malloc(4 * surf->w * surf->h); 263 for(y = 0; y < h; y++) { 264 uint32_t * iline = (uint32_t *)&(((uint8_t *)surf->pixels)[y * pitch]); 265 uint32_t * oline = &pxd[(bFlipY?(h-y-1):y)*w]; 266 for(x = 0; x < w; x++) 267 { 268 uint32_t pr = iline[x]; 269 oline[x] = (pr & 0xff00ff00) | ((pr & 0xff) << 16) | ((pr & 0xff0000)>>16); 270 } 271 } 272 return pxd; 273} 274 275static bool OPENVR_CheckRenderbuffer(SDL_VideoDevice *_this) 276{ 277 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 278 279 if (videodata->targw == 0 || videodata->targh == 0) { 280 videodata->targw = OPENVR_DEFAULT_WIDTH; 281 videodata->targh = OPENVR_DEFAULT_HEIGHT; 282 } 283 284 if (videodata->targh != videodata->last_targh 285 || videodata->targw != videodata->last_targw) { 286 287 struct HmdVector2_t ms; 288 int status; 289 290 if (videodata->fbo <= 0) { 291 ov_glGenFramebuffers(1, &videodata->fbo); 292 ov_glGenRenderbuffers(1, &videodata->rbo); 293 ov_glGenTextures(1, &videodata->overlaytexture); 294 } 295 296 // Generate the OpenGL Backing buffers/etc. 297 ov_glBindFramebuffer(GL_FRAMEBUFFER, videodata->fbo); 298 ov_glBindRenderbuffer(GL_RENDERBUFFER, videodata->rbo); 299 ov_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, videodata->targw, videodata->targh); 300 ov_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, videodata->rbo); 301 ov_glBindTexture(GL_TEXTURE_2D, videodata->overlaytexture); 302 ov_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 303 ov_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 304 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videodata->targw, videodata->targh, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 305 ov_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, videodata->overlaytexture, 0); 306 status = ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER); 307 if (status != GL_FRAMEBUFFER_COMPLETE) { 308 return SDL_SetError("OPENVR: Can't generate overlay buffer"); 309 } 310 ov_glBindFramebuffer(GL_FRAMEBUFFER, 0); 311 312 ms.v[0] = (float)videodata->targw; 313 ms.v[1] = (float)videodata->targh; 314 videodata->oOverlay->SetOverlayMouseScale(videodata->overlayID, &ms); 315 316 videodata->last_targh = videodata->targh; 317 videodata->last_targw = videodata->targw; 318 } 319 return true; 320} 321 322static bool OPENVR_VirtualControllerRumble(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 323{ 324 // On XBOX Controllers Low/High maps to Left/Right 325 SDL_VideoData *videodata = (SDL_VideoData *)userdata; 326 327 const float k_flIntensity = 320.f; // Maximum frequency 328 float flLeftFrequency = (float)low_frequency_rumble * k_flIntensity / 65535.f; 329 float flRightFrequency = (float)high_frequency_rumble * k_flIntensity / 65535.f; 330 float flDurationSeconds = 2.f; 331 float flAmplitude = 1.f; 332 333 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[0], 0, flDurationSeconds, flLeftFrequency, flAmplitude, 0); 334 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[1], 0, flDurationSeconds, flRightFrequency, flAmplitude, 0); 335 336 return true; 337} 338 339static bool OPENVR_VirtualControllerRumbleTriggers(void *userdata, Uint16 left_rumble, Uint16 right_rumble) 340{ 341 SDL_VideoData *videodata = (SDL_VideoData *)userdata; 342 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[0], 0, 0.1f, left_rumble, 1.0, 0); 343 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[1], 0, 0.1f, right_rumble, 1.0, 0); 344 return true; 345} 346 347static void OPENVR_VirtualControllerUpdate(void *userdata) 348{ 349 SDL_VideoData *videodata = (SDL_VideoData *)userdata; 350 SDL_Joystick * joystick = videodata->virtual_joystick; 351 InputDigitalActionData_t digital_input_action; 352 InputAnalogActionData_t analog_input_action; 353 EVRInputError e; 354#ifdef DEBUG_OPENVR 355 //char cts[10240]; 356 //char * ctsx = cts; 357#endif 358 VRActiveActionSet_t actionSet = { 0 }; 359 actionSet.ulActionSet = videodata->input_action_set; 360 e = videodata->oInput->UpdateActionState(&actionSet, sizeof(actionSet), 1); 361 if (e) 362 { 363#ifdef DEBUG_OPENVR 364 SDL_Log("ERROR: Failed to update action state"); 365#endif 366 return; 367 } 368 369 for (int d = 0; d < videodata->input_action_handles_buttons_count; d++) 370 { 371 if (videodata->input_action_handles_buttons[d] == k_ulInvalidActionHandle) 372 continue; 373 e = videodata->oInput->GetDigitalActionData(videodata->input_action_handles_buttons[d], &digital_input_action, sizeof(digital_input_action), k_ulInvalidInputValueHandle); 374 if (e) 375 { 376#ifdef DEBUG_OPENVR 377 SDL_Log("ERROR: Failed to get digital action data: %d", d); 378#endif 379 return; 380 } 381 SDL_SetJoystickVirtualButton(joystick, d, digital_input_action.bState); 382#ifdef DEBUG_OPENVR 383 //ctsx+=sprintf(ctsx,"%d", digital_input_action.bState); 384#endif 385 } 386 387 // Left Stick 388 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[0], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle); 389 if (e) 390 { 391#ifdef DEBUG_OPENVR 392 SDL_Log("ERROR: Failed to get analog action data: left stick"); 393#endif 394 return; 395 } 396 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFTX, (Sint16)(analog_input_action.x * SDL_JOYSTICK_AXIS_MAX)); 397 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFTY, (Sint16)(-analog_input_action.y * SDL_JOYSTICK_AXIS_MAX)); 398 399 // Right Stick 400 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[1], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle); 401 if (e) 402 { 403#ifdef DEBUG_OPENVR 404 SDL_Log("ERROR: Failed to get analog action data: right stick"); 405#endif 406 return; 407 } 408 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHTX, (Sint16)(analog_input_action.x * SDL_JOYSTICK_AXIS_MAX)); 409 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHTY, (Sint16)(-analog_input_action.y * SDL_JOYSTICK_AXIS_MAX)); 410 411 // Left Trigger 412 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[2], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle); 413 if (e) 414 { 415#ifdef DEBUG_OPENVR 416 SDL_Log("ERROR: Failed to get analog action data: left trigger"); 417#endif 418 return; 419 } 420 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (Sint16)((analog_input_action.x * 2.0f - 1.0f) * SDL_JOYSTICK_AXIS_MAX)); 421 422 // Right Trigger 423 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[3], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle); 424 if (e) 425 { 426#ifdef DEBUG_OPENVR 427 SDL_Log("ERROR: Failed to get analog action data: right trigger"); 428#endif 429 return; 430 } 431 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (Sint16)((analog_input_action.x * 2.0f - 1.0f) * SDL_JOYSTICK_AXIS_MAX)); 432 433#if 0 434 for (a = 0; a < videodata->input_action_handles_axes_count; a++) 435 { 436 float xval = 0.0f; 437 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[a], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle); 438 if (e) goto updatefail; 439 xval = analog_input_action.x; 440 if (a == SDL_CONTROLLER_AXIS_LEFTY || a == SDL_CONTROLLER_AXIS_RIGHTY) 441 xval *= -1.0f; 442 if (a == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || a == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) 443 xval = xval * 2.0f - 1.0f; 444 //SDL_SetJoystickVirtualAxis(joystick, a, analog_input_action.x * 32767); 445 xval *= SDL_JOYSTICK_AXIS_MAX; 446 SDL_SetJoystickVirtualAxis(joystick, a, xval); 447#ifdef DEBUG_OPENVR 448 //ctsx+=sprintf(ctsx,"[%f]", analog_input_action.x); 449#endif 450 } 451#endif 452#ifdef DEBUG_OPENVR 453 //SDL_Log("Debug Input States: %s", cts); 454#endif 455 return; 456} 457 458static bool OPENVR_SetupJoystickBasedOnLoadedActionManifest(SDL_VideoData * videodata) 459{ 460 SDL_VirtualJoystickDesc desc; 461 SDL_JoystickID virtual_id; 462 463 EVRInputError e = 0; 464 465 char * k_pchBooleanActionPaths[SDL_GAMEPAD_BUTTON_COUNT] = { 466 "/actions/virtualgamepad/in/a", 467 "/actions/virtualgamepad/in/b", 468 "/actions/virtualgamepad/in/x", 469 "/actions/virtualgamepad/in/y", 470 "/actions/virtualgamepad/in/back", 471 "/actions/virtualgamepad/in/guide", 472 "/actions/virtualgamepad/in/start", 473 "/actions/virtualgamepad/in/stick_click_left", 474 "/actions/virtualgamepad/in/stick_click_right", 475 "/actions/virtualgamepad/in/shoulder_left", 476 "/actions/virtualgamepad/in/shoulder_right", 477 "/actions/virtualgamepad/in/dpad_up", 478 "/actions/virtualgamepad/in/dpad_down", 479 "/actions/virtualgamepad/in/dpad_left", 480 "/actions/virtualgamepad/in/dpad_right", 481 "/actions/virtualgamepad/in/misc_1", 482 "/actions/virtualgamepad/in/paddle_1", 483 "/actions/virtualgamepad/in/paddle_2", 484 "/actions/virtualgamepad/in/paddle_3", 485 "/actions/virtualgamepad/in/paddle_4", 486 "/actions/virtualgamepad/in/touchpad_click", 487 "/actions/virtualgamepad/in/misc_2", 488 "/actions/virtualgamepad/in/misc_3", 489 "/actions/virtualgamepad/in/misc_4", 490 "/actions/virtualgamepad/in/misc_5", 491 "/actions/virtualgamepad/in/misc_6", 492 }; 493 char * k_pchAnalogActionPaths[4] = { 494 "/actions/virtualgamepad/in/stick_left", 495 "/actions/virtualgamepad/in/stick_right", 496 "/actions/virtualgamepad/in/trigger_left", 497 "/actions/virtualgamepad/in/trigger_right", 498 }; 499 500 if ((e = videodata->oInput->GetActionSetHandle("/actions/virtualgamepad", &videodata->input_action_set)) != EVRInputError_VRInputError_None) 501 { 502#ifdef DEBUG_OPENVR 503 SDL_Log("ERROR: Failed to get action set handle: %d", e); 504#endif 505 return SDL_SetError("Failed to get action set handle"); 506 } 507 508 videodata->input_action_handles_buttons_count = SDL_arraysize(k_pchBooleanActionPaths); 509 videodata->input_action_handles_buttons = SDL_malloc(videodata->input_action_handles_buttons_count * sizeof(VRActionHandle_t)); 510 511 for (int i = 0; i < videodata->input_action_handles_buttons_count; i++) 512 { 513 e = videodata->oInput->GetActionHandle(k_pchBooleanActionPaths[i], &videodata->input_action_handles_buttons[i]); 514 if (e) 515 { 516 SDL_Log("ERROR: Failed to get button action %d ('%s')", i, k_pchBooleanActionPaths[i]); 517 return SDL_SetError("ERROR: Failed to get button action"); 518 } 519 } 520 521 videodata->input_action_handles_axes_count = SDL_arraysize(k_pchAnalogActionPaths); 522 videodata->input_action_handles_axes = SDL_malloc(videodata->input_action_handles_axes_count * sizeof(VRActionHandle_t)); 523 524 for (int i = 0; i < videodata->input_action_handles_axes_count; i++) 525 { 526 e = videodata->oInput->GetActionHandle(k_pchAnalogActionPaths[i], &videodata->input_action_handles_axes[i]); 527 if (e) 528 { 529 SDL_Log("ERROR: Failed to get analog action %d ('%s')", i, k_pchAnalogActionPaths[i]); 530 return SDL_SetError("ERROR: Failed to get analog action"); 531 } 532 } 533 534 e = videodata->oInput->GetActionHandle("/actions/virtualgamepad/out/haptic_left", &videodata->input_action_handles_haptics[0]); 535 e |= videodata->oInput->GetActionHandle("/actions/virtualgamepad/out/haptic_right", &videodata->input_action_handles_haptics[1]); 536 if (e) 537 { 538#ifdef DEBUG_OPENVR 539 SDL_Log("ERROR: Failed to get haptics action"); 540#endif 541 return SDL_SetError("ERROR: Failed to get haptics action"); 542 } 543 544 // Create a virtual joystick. 545 SDL_INIT_INTERFACE(&desc); 546 desc.type = SDL_JOYSTICK_TYPE_GAMEPAD; 547 desc.naxes = SDL_GAMEPAD_AXIS_COUNT; 548 desc.nbuttons = SDL_GAMEPAD_BUTTON_COUNT; 549 desc.Rumble = OPENVR_VirtualControllerRumble; 550 desc.RumbleTriggers = OPENVR_VirtualControllerRumbleTriggers; 551 desc.Update = OPENVR_VirtualControllerUpdate; 552 desc.userdata = videodata; 553 virtual_id = SDL_AttachVirtualJoystick(&desc); 554 555 if (!virtual_id) { 556 return SDL_SetError("OPENVR: Couldn't attach virtual joystick device: %s", SDL_GetError()); 557 } 558 559 videodata->virtual_joystick = SDL_OpenJoystick(virtual_id); 560 if (!videodata->virtual_joystick) { 561 return SDL_SetError("OPENVR: Couldn't open virtual joystick device: %s", SDL_GetError()); 562 } 563 564#ifdef DEBUG_OPENVR 565 SDL_Log("Loaded virtual joystick with %d buttons and %d axes", videodata->input_action_handles_buttons_count, videodata->input_action_handles_axes_count); 566#endif 567 568 return true; 569} 570 571static bool OPENVR_InitializeOverlay(SDL_VideoDevice *_this, SDL_Window *window) 572{ 573 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 574 575 // Wait til here, to make sure we have our context setup correctly. 576 if (!OPENVR_InitExtensions(_this)) { 577 return false; 578 } 579 580 // Generate the overlay. 581 { 582 const char * hint = SDL_GetHint("SDL_OPENVR_OVERLAY_NAME"); 583 char * cursorname = 0; 584 if (!hint) { 585 hint = "sdl"; 586 } 587 588 SDL_asprintf(&videodata->sOverlayName, "%s-overlay",hint); 589 if (!videodata->sOverlayName) { 590 return false; 591 } 592 SDL_asprintf(&cursorname, "%s-cursor",hint); 593 if (!cursorname) { 594 return false; 595 } 596 597 EVROverlayError result = videodata->oOverlay->CreateDashboardOverlay(videodata->sOverlayName, 598 window->title, &videodata->overlayID, &videodata->thumbID); 599 if (result != EVROverlayError_VROverlayError_None) { 600 SDL_free(cursorname); 601 return SDL_SetError("Could not create dashboard overlay (%d)", result ); 602 } 603 result = videodata->oOverlay->CreateOverlay(cursorname, window->title, &videodata->cursorID); 604 if (result != EVROverlayError_VROverlayError_None) { 605 SDL_free(cursorname); 606 return SDL_SetError("Could not create cursor overlay (%d)", result ); 607 } 608 SDL_PropertiesID props = SDL_GetWindowProperties(window); 609 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_OPENVR_OVERLAY_ID_NUMBER, videodata->overlayID); 610 SDL_free(cursorname); 611 videodata->bHasShownOverlay = false; 612 } 613 { 614 Uint32 overlay_flags = 0; 615 616 const char *hint = SDL_GetHint("SDL_OPENVR_OVERLAY_FLAGS"); 617 if (hint && *hint) { 618 overlay_flags = SDL_atoi(hint); 619 } else { 620 overlay_flags |= (1 << 23); //vr::VROverlayFlags_EnableControlBar 621 overlay_flags |= (1 << 24); //vr::VROverlayFlags_EnableControlBarKeyboard 622 overlay_flags |= (1 << 25); //vr::VROverlayFlags_EnableControlBarClose 623#if 0 624 /* OpenVR overlays assume unpremultiplied alpha by default, set this flag to tag the source buffer as premultiplied. 625 * Note that (as of 2025) OpenVR overlay composition is higher quality when premultiplied buffers are provided, 626 * as texture samplers that blend energy (such as bilinear) do not yield sensical results when operating on natively 627 * unpremultiplied textures. It is thus preferable to hand openvr natively premultiplied buffers when accurate 628 * sampling / composition is required. */ 629 overlay_flags |= (1 << 21); // vr::VROverlayFlags_IsPremultiplied 630#endif 631 } 632 633 for (int i = 0; i < sizeof(overlay_flags) * 8; ++i) { 634 if (overlay_flags & (1 << i)) { 635 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, (VROverlayFlags)(1 << i), true); 636 } 637 } 638 } 639 { 640 const char * hint = SDL_GetHint("SDL_OPENVR_OVERLAY_PANEL_WIDTH"); 641 float fWidth = hint ? (float)SDL_atof(hint) : 1.0f; 642 videodata->oOverlay->SetOverlayWidthInMeters(videodata->overlayID, fWidth); 643 } 644 { 645 const char * hint = SDL_GetHint("SDL_OPENVR_CURSOR_WIDTH"); 646 // Default is what SteamVR Does 647 float fCursorWidth = hint ? (float)SDL_atof(hint) : 0.06f; 648 videodata->oOverlay->SetOverlayWidthInMeters(videodata->cursorID, fCursorWidth * 0.5f); 649 } 650 { 651 const char * hint = SDL_GetHint("SDL_OPENVR_WINDOW_ICON_FILE"); 652 videodata->bIconOverridden = false; 653 if (hint) { 654 char * tmpcopy = SDL_strdup(hint); 655 EVROverlayError err = videodata->oOverlay->SetOverlayFromFile(videodata->thumbID, tmpcopy); 656 SDL_free(tmpcopy); 657 if (err == EVROverlayError_VROverlayError_None) { 658 videodata->bIconOverridden = SDL_GetHintBoolean("SDL_OPENVR_WINDOW_ICON_OVERRIDE", false); 659 } 660 } 661 } 662 { 663 VRTextureBounds_t bounds; 664 bounds.uMin = 0; 665 bounds.uMax = 1; 666 bounds.vMin = 0; 667 bounds.vMax = 1; 668 videodata->oOverlay->SetOverlayTextureBounds(videodata->overlayID, &bounds); 669 } 670 671 if (!OPENVR_CheckRenderbuffer(_this)) { 672 return false; 673 } 674 675 global_openvr_driver = videodata; 676 InitializeMouseFunctions(); 677 678 // Actually show the overlay. 679 videodata->oOverlay->SetOverlayName(videodata->overlayID, window->title); 680 681 videodata->bDidCreateOverlay = true; 682 videodata->window = window; 683 684 return true; 685} 686 687 688static bool OPENVR_SetupFrame(SDL_VideoDevice *_this, SDL_Window *window) 689{ 690 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 691 static const GLenum buffers[8] = { GL_COLOR_ATTACHMENT0_EXT }; 692 693 videodata->is_buffer_rendering = true; 694 695#ifdef DEBUG_OPENVR 696 { 697 int error = ov_glGetError(); 698 if (error) 699 SDL_Log("Found GL Error before beginning frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); 700 } 701#endif 702 703 ov_glBindFramebuffer(GL_FRAMEBUFFER, videodata->fbo); 704 ov_glDrawBuffers(1, buffers); 705 706 // Set the alpha channel for non-transparent windows 707 if (!(window->flags & SDL_WINDOW_TRANSPARENT)) { 708 ov_glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 709 ov_glColorMask(false, false, false, true); 710 ov_glClear(GL_COLOR_BUFFER_BIT); 711 ov_glColorMask(true, true, true, true); 712 } 713 714 ov_glBindTexture( GL_TEXTURE_2D, videodata->saved_texture_state ); 715 716 return true; 717} 718 719static bool OPENVR_ReleaseFrame(SDL_VideoDevice *_this) 720{ 721 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 722 ov_glGetIntegerv(GL_TEXTURE_BINDING_2D, &videodata->saved_texture_state); 723 724 if (!ov_glGetError) { 725 return true; 726 } 727 728 if (!videodata->is_buffer_rendering) { 729 return true; 730 } 731 732#ifdef DEBUG_OPENVR 733 { 734 int error = ov_glGetError(); 735 if (error) { 736 SDL_Log("Found GL Error before release frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); 737 } 738 } 739#endif 740 741 videodata->is_buffer_rendering = false; 742 743 ov_glBindFramebuffer(GL_FRAMEBUFFER, 0); 744 745 if (videodata->overlaytexture != 0 && 746 videodata->targh == videodata->last_targh && 747 videodata->targw == videodata->last_targw) { 748 // Only submit frames to OpenVR if the texture exists. 749 struct Texture_t tex; 750 751 // Setup a Texture_t object to send in the texture. 752 tex.eColorSpace = EColorSpace_ColorSpace_Auto; 753 tex.eType = ETextureType_TextureType_OpenGL; 754 tex.handle = (void *)(intptr_t)videodata->overlaytexture; 755 756 // Send texture into OpenVR as the overlay. 757 videodata->oOverlay->SetOverlayTexture(videodata->overlayID, &tex); 758 } 759 760 if (!videodata->bHasShownOverlay && videodata->bDidCreateOverlay) { 761 videodata->oOverlay->ShowDashboard(videodata->sOverlayName); 762 videodata->bHasShownOverlay = true; 763 } 764 765 if (videodata->renderdoc_debugmarker_frame_end) { 766 ov_glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, 767 GL_DEBUG_TYPE_MARKER, MARKER_ID, GL_DEBUG_SEVERITY_NOTIFICATION, -1, 768 MARKER_STR); 769 } 770 771 return OPENVR_CheckRenderbuffer(_this); 772} 773 774static void OPENVR_HandleResize(SDL_VideoDevice *_this, int w, int h) 775{ 776 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 777 data->targw = w; 778 data->targh = h; 779} 780 781static bool OPENVR_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) 782{ 783 return true; 784} 785 786 787#ifdef SDL_VIDEO_DRIVER_WINDOWS 788static LRESULT CALLBACK OpenVRVideoWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 789{ 790 switch (msg) { 791 case WM_DESTROY: 792 return 0; 793 } 794 return DefWindowProc(hwnd, msg, wParam, lParam); 795} 796 797static bool OPENVR_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path) 798{ 799 if (path == NULL) { 800 path = SDL_GetHint(SDL_HINT_OPENGL_LIBRARY); 801 } 802 803 if (path == NULL) { 804 path = DEFAULT_OPENGL; 805 } 806 _this->gl_config.dll_handle = SDL_LoadObject(path); 807 if (!_this->gl_config.dll_handle) { 808 return false; 809 } 810 SDL_strlcpy(_this->gl_config.driver_path, path, 811 SDL_arraysize(_this->gl_config.driver_path)); 812 813 // Allocate OpenGL memory 814 _this->gl_data = (struct SDL_GLDriverData *)SDL_calloc(1, sizeof(struct SDL_GLDriverData)); 815 if (!_this->gl_data) { 816 return false; 817 } 818 _this->gl_config.driver_loaded = true; 819 820 return true; 821} 822 823static SDL_FunctionPointer OPENVR_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) 824{ 825 SDL_FunctionPointer result = NULL; 826 if (ov_wglGetProcAddress) { 827 result = (SDL_FunctionPointer)ov_wglGetProcAddress(proc); 828 if (result) { 829 return result; 830 } 831 } 832 833 return SDL_LoadFunction(_this->gl_config.dll_handle, proc); 834} 835 836static void OPENVR_GL_UnloadLibrary(SDL_VideoDevice *_this) 837{ 838 SDL_GL_UnloadLibrary(); 839} 840 841static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) 842{ 843 GLint numExtensions; 844 int i; 845 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 846 if (!videodata->hglrc) { 847 // Create a surfaceless EGL Context 848 HWND hwnd; 849 850 WNDCLASSA wnd; 851 wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 852 wnd.lpfnWndProc = OpenVRVideoWndProc; 853 wnd.cbClsExtra = 0; 854 wnd.cbWndExtra = 0; 855 wnd.hInstance = GetModuleHandle(NULL); 856 wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); 857 wnd.hCursor = LoadCursor(NULL, IDC_ARROW); 858 wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); 859 wnd.lpszMenuName = NULL; 860 wnd.lpszClassName = "SDL_openvrvideo_classname"; 861 RegisterClassA(&wnd); 862 hwnd = CreateWindowA("SDL_openvrvideo_classname", "SDL_openvrvideo_windowname", (WS_OVERLAPPEDWINDOW), 0, 0, 863 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL); 864 865 MSG msg; 866 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 867 TranslateMessage(&msg); 868 DispatchMessage(&msg); 869 } 870 871 videodata->hdc = GetDC(hwnd); 872 873 static PIXELFORMATDESCRIPTOR pfd = 874 { 875 sizeof(PIXELFORMATDESCRIPTOR), 876 1, 877 PFD_DRAW_TO_WINDOW | 878 PFD_SUPPORT_OPENGL | 879 PFD_DOUBLEBUFFER, 880 PFD_TYPE_RGBA, 881 24, 882 8, 0, 8, 8, 8, 16, 883 8, 884 24, 885 32, 886 8, 8, 8, 8, 887 16, 888 0, 889 0, 890 PFD_MAIN_PLANE, 891 0, 892 0, 0, 0 893 }; 894 GLuint PixelFormat = ChoosePixelFormat(videodata->hdc, &pfd); 895 if (!SetPixelFormat(videodata->hdc, PixelFormat, &pfd)) { 896 SDL_SetError( "Could not set pixel format" ); 897 return NULL; 898 } 899 HMODULE opengl = GetModuleHandleA(DEFAULT_OPENGL); 900 if (!opengl) { 901 SDL_SetError("Could not open OpenGL Library %s", DEFAULT_OPENGL); 902 return NULL; 903 } 904 905 ov_wglMakeCurrent = (BOOL(*)(HDC, HGLRC))GetProcAddress(opengl, "wglMakeCurrent"); 906 ov_wglCreateContext = (HGLRC(*)(HDC))GetProcAddress(opengl, "wglCreateContext"); 907 ov_wglGetProcAddress = (PROC(*)(LPCSTR))GetProcAddress(opengl, "wglGetProcAddress"); 908 ov_wglDeleteContext = (BOOL(*)(HGLRC))GetProcAddress(opengl, "wglDeleteContext"); 909 if (!ov_wglMakeCurrent || !ov_wglCreateContext) { 910 SDL_SetError("Cannot get wgl context procs(%p, %p)", ov_wglMakeCurrent, ov_wglCreateContext); 911 return NULL; 912 } 913 914 videodata->hglrc = ov_wglCreateContext(videodata->hdc); 915 if (!videodata->hglrc || !ov_wglMakeCurrent(videodata->hdc, videodata->hglrc)) { 916 SDL_SetError("Could not make current OpenGL context."); 917 return NULL; 918 } 919 } 920 921 i = OPENVR_InitExtensions(_this); 922 if (i == 0) { 923 return NULL; 924 } 925 926 videodata->renderdoc_debugmarker_frame_end = false; 927 928 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 929 for (i = 0; i < numExtensions; i++) { 930 const char *ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i); 931 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { 932#ifdef DEBUG_OPENVR 933 SDL_Log("Found renderdoc debug extension."); 934#endif 935 videodata->renderdoc_debugmarker_frame_end = true; 936 } 937 } 938 939 if (!videodata->bDidCreateOverlay) { 940 if (!OPENVR_InitializeOverlay(_this, window)) { 941 return NULL; 942 } 943 } 944 945 OPENVR_CheckRenderbuffer(_this); 946 947 OPENVR_SetupFrame(_this, window); 948 949 SDL_GLContext result = SDL_malloc(sizeof(struct SDL_GLContextState)); 950 if (!result) { 951 return NULL; 952 } 953 result->hglrc = videodata->hglrc; 954 return result; 955} 956 957static bool OPENVR_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *wnd, SDL_GLContext context) 958{ 959 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 960 ov_wglMakeCurrent(videodata->hdc, videodata->hglrc); 961 return true; 962} 963 964static bool OPENVR_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 965{ 966 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 967 videodata->swap_interval = interval; 968 return true; 969} 970 971static bool OPENVR_GL_GetSwapInterval(SDL_VideoDevice *_this, int *swapInterval) 972{ 973 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 974 if (swapInterval) 975 *swapInterval = videodata->swap_interval; 976 else 977 return SDL_SetError("OPENVR: null passed in for GetSwapInterval"); 978 return true; 979} 980 981static bool OPENVR_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 982{ 983 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 984 ov_wglMakeCurrent(videodata->hdc, NULL); 985 ov_wglDeleteContext(videodata->hglrc); 986 return true; 987} 988 989 990#else 991 992static EGLint context_attribs[] = { 993 EGL_CONTEXT_CLIENT_VERSION, 2, 994 EGL_NONE 995}; 996 997static bool SDL_EGL_InitInternal(SDL_VideoData * vd) 998{ 999 // Create a surfaceless EGL Context 1000 EGLint major, minor; 1001 EGLConfig eglCfg=NULL; 1002 EGLBoolean b; 1003 1004 vd->eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 1005#ifdef DEBUG_OPENVR 1006 SDL_Log("EGL Display: %p", vd->eglDpy); 1007#endif 1008 1009 if (vd->eglDpy == 0) { 1010 return SDL_SetError("No EGL Display"); 1011 } 1012 1013 b = eglInitialize(vd->eglDpy, &major, &minor); 1014 if (!b) { 1015 return SDL_SetError("eglInitialize failed"); 1016 } 1017 1018 eglBindAPI(EGL_OPENGL_API); 1019#ifdef DEBUG_OPENVR 1020 SDL_Log("EGL Major Minor: %d %d = %d", major, minor, b); 1021#endif 1022 1023 vd->eglCtx = eglCreateContext(vd->eglDpy, eglCfg, EGL_NO_CONTEXT, context_attribs); 1024 1025#ifdef DEBUG_OPENVR 1026 { 1027 int err = eglGetError(); 1028 if (err != EGL_SUCCESS) { 1029 return SDL_SetError("EGL Error after eglCreateContext %d", err); 1030 } 1031 } 1032#endif 1033 1034 if (!vd->eglCtx) { 1035 return SDL_SetError("No EGL context available"); 1036 } 1037 1038 eglMakeCurrent(vd->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, vd->eglCtx); 1039 1040 return true; 1041} 1042 1043// Linux, EGL, etc. 1044static bool OVR_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *path) 1045{ 1046 return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY); 1047} 1048 1049static SDL_FunctionPointer OVR_EGL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) 1050{ 1051 return SDL_EGL_GetProcAddress(proc); 1052} 1053static void OVR_EGL_UnloadLibrary(SDL_VideoDevice *_this) 1054{ 1055 SDL_EGL_UnloadLibrary(_this); 1056} 1057static SDL_GLContext OVR_EGL_CreateContext(SDL_VideoDevice *_this, SDL_Window * window) 1058{ 1059 GLint numExtensions; 1060 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1061 if (!videodata->eglCtx) { 1062 if (!SDL_EGL_InitInternal(videodata)) { 1063 return NULL; 1064 } 1065 } 1066 1067 if (!OPENVR_InitExtensions(_this)) { 1068 return NULL; 1069 } 1070 1071 videodata->renderdoc_debugmarker_frame_end = false; 1072 1073 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 1074 for(int i = 0; i < numExtensions; i++) { 1075 const char * ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i); 1076 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { 1077#ifdef DEBUG_OPENVR 1078 SDL_Log("Found renderdoc debug extension."); 1079#endif 1080 videodata->renderdoc_debugmarker_frame_end = true; 1081 } 1082 } 1083 1084 if (!videodata->bDidCreateOverlay) { 1085 if (!OPENVR_InitializeOverlay(_this, window)) { 1086 return NULL; 1087 } 1088 } 1089 1090 OPENVR_CheckRenderbuffer(_this); 1091 1092 OPENVR_SetupFrame(_this, window); 1093 1094 return videodata->eglCtx; 1095} 1096 1097static bool OVR_EGL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window * wnd, SDL_GLContext context) 1098{ 1099 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1100 eglMakeCurrent(videodata->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, videodata->eglCtx); 1101 return true; 1102} 1103 1104static bool OVR_EGL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 1105{ 1106 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1107 videodata->swap_interval = interval; 1108 return true; 1109} 1110 1111static bool OVR_EGL_GetSwapInterval(SDL_VideoDevice *_this, int * swapInterval) 1112{ 1113 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1114 if (swapInterval) 1115 *swapInterval = videodata->swap_interval; 1116 else 1117 return SDL_SetError("OPENVR: null passed in for GetSwapInterval"); 1118 return true; 1119} 1120 1121static bool OVR_EGL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 1122{ 1123 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1124 if (videodata->eglDpy) { 1125 eglTerminate(videodata->eglDpy); 1126 } 1127 return true; 1128} 1129 1130#endif 1131 1132static bool OPENVR_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) 1133{ 1134 SDL_WindowData *data; 1135 1136 // Allocate window internal data 1137 data = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); 1138 if (data == NULL) { 1139 return SDL_OutOfMemory(); 1140 } 1141 1142 window->max_w = 4096; 1143 window->max_h = 4096; 1144 window->min_w = 1; 1145 window->min_h = 1; 1146 1147 // Setup driver data for this window 1148 window->internal = data; 1149 return true; 1150} 1151 1152 1153static void OPENVR_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) 1154{ 1155 SDL_WindowData *data; 1156 1157 data = window->internal; 1158 SDL_free(data); 1159 window->internal = NULL; 1160} 1161 1162static void OPENVR_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) 1163{ 1164 SDL_VideoData * data = (SDL_VideoData *)_this->internal; 1165 if (data->bDidCreateOverlay) { 1166 data->oOverlay->SetOverlayName(data->overlayID, window->title); 1167 } 1168} 1169 1170static void OPENVR_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) 1171{ 1172 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1173 1174 if (window->pending.w != window->w) { 1175 window->w = window->pending.w; 1176 } 1177 1178 if (window->pending.h != window->h) { 1179 window->h = window->pending.h; 1180 } 1181 1182 if (data->targh != window->h || data->targw != window->w) { 1183 OPENVR_HandleResize(_this, window->w, window->h); 1184 } 1185 1186 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->w, window->h); 1187} 1188 1189static void OPENVR_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h) 1190{ 1191 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1192 *w = data->targw; 1193 *h = data->targh; 1194} 1195 1196static void OPENVR_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) 1197{ 1198 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1199 if (data->targh != window->h || data->targw != window->w) { 1200 OPENVR_HandleResize(_this, window->w, window->h); 1201 } 1202 1203 data->oOverlay->ShowDashboard(data->sOverlayName); 1204 1205 window->flags |= (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS); 1206 SDL_SetKeyboardFocus(window); 1207} 1208 1209static void OPENVR_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) 1210{ 1211 return; 1212} 1213 1214static bool OPENVR_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) 1215{ 1216 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1217 1218 // This is a little weird. On Windows, we don't necessarily call the normal 1219 // context creation function, and we might get here without having our buffers 1220 // initialized. 1221 if (!videodata->bDidCreateOverlay) { 1222 if (!OPENVR_InitializeOverlay(_this, window)) { 1223 return false; 1224 } 1225 } 1226 1227 if (!OPENVR_ReleaseFrame(_this)) { 1228 return false; 1229 } 1230 1231 // If swap_interval is nonzero (i.e. -1 or 1) we want to wait for vsync on the compositor. 1232 if (videodata->swap_interval != 0) { 1233 videodata->oOverlay->WaitFrameSync(100); 1234 } 1235 1236 if (!OPENVR_SetupFrame(_this, window)) { 1237 return false; 1238 } 1239 1240 return true; 1241} 1242 1243static void OPENVR_HandleMouse(float x, float y, int btn, int evt) 1244{ 1245 if (evt == 2) { 1246 SDL_SendMouseMotion(0, NULL, SDL_GLOBAL_MOUSE_ID, false, x, y); 1247 } else { 1248 const Uint8 button = SDL_BUTTON_LEFT + btn; 1249 const bool down = (evt != 0); 1250 SDL_SendMouseButton(0, NULL, SDL_GLOBAL_MOUSE_ID, button, down); 1251 } 1252} 1253 1254 1255static bool OPENVR_HasScreenKeyboardSupport(SDL_VideoDevice *_this) 1256{ 1257 return true; 1258} 1259 1260static void OPENVR_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) 1261{ 1262 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1263 if (!videodata || 1264 videodata->oOverlay == 0 || 1265 videodata->overlayID == 0) { 1266 return; 1267 } 1268 EGamepadTextInputMode input_mode; 1269 switch (SDL_GetTextInputType(props)) { 1270 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN: 1271 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: 1272 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModePassword; 1273 break; 1274 default: 1275 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModeNormal; 1276 break; 1277 } 1278 EGamepadTextInputLineMode line_mode; 1279 if (SDL_GetTextInputMultiline(props)) { 1280 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeMultipleLines; 1281 } else { 1282 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeSingleLine; 1283 } 1284 videodata->oOverlay->ShowKeyboardForOverlay(videodata->overlayID, 1285 input_mode, line_mode, 1286 EKeyboardFlags_KeyboardFlag_Minimal, "Virtual Keyboard", 128, "", 0); 1287 SDL_SendScreenKeyboardShown(); 1288} 1289 1290static void OPENVR_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window) 1291{ 1292 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1293 videodata->oOverlay->HideKeyboard(); 1294 SDL_SendScreenKeyboardHidden(); 1295} 1296 1297static SDL_Cursor *OPENVR_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) 1298{ 1299 SDL_Cursor *result = SDL_calloc(1, sizeof(SDL_Cursor)); 1300 if (!result) { 1301 return NULL; 1302 } 1303 1304 uint32_t * pixels = ImageSDLToOpenVRGL(surface, false); 1305 SDL_CursorData *ovrc = (SDL_CursorData *)SDL_calloc(1, sizeof(*ovrc)); 1306 if (!ovrc) { 1307 SDL_free(result); 1308 return NULL; 1309 } 1310 result->internal = ovrc; 1311 1312 ov_glGenTextures(1, &ovrc->texture_id_handle); 1313 ov_glBindTexture(GL_TEXTURE_2D, ovrc->texture_id_handle); 1314 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 1315 SDL_free(pixels); 1316 ov_glBindTexture(GL_TEXTURE_2D, 0); 1317 1318 ovrc->hot_x = hot_x; 1319 ovrc->hot_y = hot_y; 1320 ovrc->w = surface->w; 1321 ovrc->h = surface->h; 1322 1323 return result; 1324} 1325 1326static bool OPENVR_ShowCursor(SDL_Cursor * cursor) 1327{ 1328 SDL_CursorData * ovrc; 1329 EVROverlayError e; 1330 Texture_t texture; 1331 HmdVector2_t hotspot; 1332 VRTextureBounds_t tb; 1333 1334 if (!cursor) { 1335 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, true); 1336 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, k_ulOverlayHandleInvalid); 1337 if (e != EVROverlayError_VROverlayError_None) { 1338 return OPENVR_SetOverlayError(e); 1339 } 1340 return true; 1341 } 1342 1343 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, false); 1344 1345 ovrc = cursor->internal; 1346 1347 if (!ovrc) { 1348 // Sometimes at boot there is a race condition where this is not ready. 1349 return true; 1350 } 1351 1352 hotspot.v[0] = (float)ovrc->hot_x / (float)ovrc->w; 1353 hotspot.v[1] = (float)ovrc->hot_y / (float)ovrc->h; 1354 1355 texture.handle = (void *)(intptr_t)(ovrc->texture_id_handle); 1356 texture.eType = ETextureType_TextureType_OpenGL; 1357 texture.eColorSpace = EColorSpace_ColorSpace_Auto; 1358 1359 tb.uMin = 0; 1360 tb.uMax = 1; 1361 tb.vMin = 1; 1362 tb.vMax = 0; 1363 1364 e = global_openvr_driver->oOverlay->SetOverlayTextureBounds(global_openvr_driver->cursorID, &tb); 1365 if (e != EVROverlayError_VROverlayError_None) { 1366 return OPENVR_SetOverlayError(e); 1367 } 1368 1369 e = global_openvr_driver->oOverlay->SetOverlayTransformCursor(global_openvr_driver->cursorID, &hotspot); 1370 if (e != EVROverlayError_VROverlayError_None) { 1371 return OPENVR_SetOverlayError(e); 1372 } 1373 1374 e = global_openvr_driver->oOverlay->SetOverlayTexture(global_openvr_driver->cursorID, &texture); 1375 if (e != EVROverlayError_VROverlayError_None) { 1376 return OPENVR_SetOverlayError(e); 1377 } 1378 1379 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, global_openvr_driver->cursorID); 1380 if (e != EVROverlayError_VROverlayError_None) { 1381 return OPENVR_SetOverlayError(e); 1382 } 1383 1384 return true; 1385} 1386 1387static void OPENVR_FreeCursor(SDL_Cursor * cursor) 1388{ 1389 if (cursor) { 1390 SDL_CursorData *ovrc = cursor->internal; 1391 if (ovrc) { 1392 ov_glDeleteTextures(1, &ovrc->texture_id_handle); 1393 SDL_free(ovrc); 1394 } 1395 SDL_free(cursor); 1396 } 1397} 1398 1399 1400static bool OPENVR_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window * window, SDL_Surface * icon) 1401{ 1402 if (!global_openvr_driver) { 1403 return SDL_SetError("OpenVR Overlay not initialized"); 1404 } 1405 1406 unsigned texture_id_handle; 1407 EVROverlayError e; 1408 Texture_t texture; 1409 uint32_t * pixels; 1410 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1411 if (videodata->bIconOverridden) { 1412 return SDL_SetError("OpenVR Icon is overridden."); 1413 } 1414 1415 pixels = ImageSDLToOpenVRGL(icon, true); 1416 1417 ov_glGenTextures(1, &texture_id_handle); 1418 ov_glBindTexture(GL_TEXTURE_2D, texture_id_handle); 1419 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, icon->w, icon->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 1420 SDL_free(pixels); 1421 ov_glBindTexture(GL_TEXTURE_2D, 0); 1422 1423 texture.handle = (void *)(intptr_t)(texture_id_handle); 1424 texture.eType = ETextureType_TextureType_OpenGL; 1425 texture.eColorSpace = EColorSpace_ColorSpace_Auto; 1426 1427 e = global_openvr_driver->oOverlay->SetOverlayTexture(videodata->thumbID, &texture); 1428 if (e != EVROverlayError_VROverlayError_None) { 1429 return OPENVR_SetOverlayError(e); 1430 } 1431 return true; 1432} 1433 1434static bool OPENVR_ShowMessageBox(SDL_VideoDevice *_this,const SDL_MessageBoxData *messageboxdata, int *buttonid) 1435{ 1436 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1437 char empty = 0; 1438 char * message = SDL_strdup(messageboxdata->message?messageboxdata->message:""); 1439 char * title = SDL_strdup(messageboxdata->message?messageboxdata->message:""); 1440 char * ok = SDL_strdup("Ok"); 1441 videodata->oOverlay->ShowMessageOverlay(message, title, ok, &empty, &empty, &empty); 1442 SDL_free(ok); 1443 SDL_free(title); 1444 SDL_free(message); 1445 return true; 1446} 1447 1448static void InitializeMouseFunctions(void) 1449{ 1450 SDL_Mouse *mouse = SDL_GetMouse(); 1451 mouse->CreateCursor = OPENVR_CreateCursor; 1452 mouse->ShowCursor = OPENVR_ShowCursor; 1453 mouse->FreeCursor = OPENVR_FreeCursor; 1454} 1455 1456static void OPENVR_PumpEvents(SDL_VideoDevice *_this) 1457{ 1458 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1459 struct VREvent_t nEvent; 1460 if (videodata->overlayID) { 1461 while (videodata->oOverlay->PollNextOverlayEvent(videodata->overlayID, &nEvent, sizeof(nEvent))) { 1462 switch (nEvent.eventType) { 1463 case EVREventType_VREvent_ButtonPress: 1464 case EVREventType_VREvent_ButtonUnpress: 1465 break; 1466 case EVREventType_VREvent_MouseMove: 1467 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, nEvent.data.mouse.button, 2); 1468 break; 1469 case EVREventType_VREvent_MouseButtonDown: 1470 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 1); 1471 break; 1472 case EVREventType_VREvent_MouseButtonUp: 1473 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 0); 1474 break; 1475 case EVREventType_VREvent_KeyboardCharInput: 1476 SDL_SendKeyboardUnicodeKey(SDL_GetTicksNS(), nEvent.data.keyboard.cNewInput[0]); 1477 break; 1478 case EVREventType_VREvent_OverlayShown: 1479 SDL_SetKeyboardFocus(videodata->window); 1480 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_RESTORED, 0, 0); 1481 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_SHOWN, 0, 0); 1482 break; 1483 case EVREventType_VREvent_OverlayHidden: 1484 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_HIDDEN, 0, 0); 1485 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); 1486 SDL_SetKeyboardFocus(NULL); 1487 break; 1488 case EVREventType_VREvent_OverlayClosed: 1489 case EVREventType_VREvent_Quit: 1490 SDL_Quit(); 1491 break; 1492 } 1493 } 1494 } 1495} 1496 1497 1498static SDL_VideoDevice *OPENVR_CreateDevice(void) 1499{ 1500 SDL_VideoDevice *device; 1501 SDL_VideoData *data; 1502 const char *hint; 1503 1504#ifdef SDL_PLATFORM_WINDOWS 1505 SDL_RegisterApp(NULL, 0, NULL); 1506#endif 1507 1508 // Initialize all variables that we clean on shutdown 1509 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 1510 if (device) { 1511 data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); 1512 } else { 1513 data = NULL; 1514 } 1515 if (!data) { 1516#ifdef SDL_PLATFORM_WINDOWS 1517 SDL_UnregisterApp(); 1518#endif 1519 SDL_free(device); 1520 return NULL; 1521 } 1522 device->internal = data; 1523 1524 hint = SDL_GetHint(SDL_HINT_OPENVR_LIBRARY); 1525 if (hint) { 1526 data->openVRLIB = SDL_LoadObject(hint); 1527 } 1528 if (!data->openVRLIB) { 1529 data->openVRLIB = SDL_LoadObject(SDL_OPENVR_DRIVER_DYNAMIC); 1530 } 1531 if (!data->openVRLIB) { 1532 SDL_SetError("Could not open OpenVR API Library"); 1533 goto error; 1534 } 1535 1536 data->FN_VR_InitInternal = (intptr_t(*)(EVRInitError * peError, EVRApplicationType eType))SDL_LoadFunction(data->openVRLIB, "VR_InitInternal"); 1537 data->FN_VR_GetVRInitErrorAsEnglishDescription = (const char *(*)(EVRInitError error))SDL_LoadFunction(data->openVRLIB, "VR_GetVRInitErrorAsEnglishDescription"); 1538 data->FN_VR_GetGenericInterface = (intptr_t (*)(const char *pchInterfaceVersion, EVRInitError * peError))SDL_LoadFunction(data->openVRLIB, "VR_GetGenericInterface"); 1539 if (!data->FN_VR_InitInternal || !data->FN_VR_GetVRInitErrorAsEnglishDescription || !data->FN_VR_GetGenericInterface) { 1540 goto error; 1541 } 1542 1543 char fnname[128]; 1544 EVRInitError e; 1545 data->vrtoken = data->FN_VR_InitInternal(&e, EVRApplicationType_VRApplication_Overlay); 1546 if (!data->vrtoken) { 1547 const char *err = "Can't get english description"; 1548 if (data->FN_VR_GetVRInitErrorAsEnglishDescription != NULL) 1549 err = data->FN_VR_GetVRInitErrorAsEnglishDescription(e); 1550 SDL_SetError("Could not generate OpenVR Context (%s)", err); 1551 goto error; 1552 } 1553 1554 SDL_snprintf(fnname, 127, "FnTable:%s", IVRSystem_Version); 1555 data->oSystem = (struct VR_IVRSystem_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1556 SDL_snprintf(fnname, 127, "FnTable:%s", IVROverlay_Version); 1557 data->oOverlay = (struct VR_IVROverlay_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1558 SDL_snprintf(fnname, 127, "FnTable:%s", IVRInput_Version); 1559 data->oInput = (struct VR_IVRInput_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1560 1561 if (!data->oOverlay || !data->oSystem || !data->oInput) { 1562 SDL_SetError("Could not get interfaces for the OpenVR System (%s), Overlay (%s) and Input (%s) versions", IVRSystem_Version, IVROverlay_Version, IVRInput_Version); 1563 } 1564 1565 hint = SDL_GetHint("SDL_OPENVR_INPUT_PROFILE"); 1566 char *loadpath = 0; 1567 EVRInputError err; 1568 1569 if (hint) { 1570 SDL_asprintf(&loadpath, "%s", hint); 1571 } else { 1572 const char *basepath = SDL_GetBasePath(); 1573 SDL_asprintf(&loadpath, "%ssdloverlay_actions.json", basepath); 1574 } 1575 if (!loadpath) { 1576 goto error; 1577 } 1578 1579 err = data->oInput->SetActionManifestPath(loadpath); 1580#ifdef DEBUG_OPENVR 1581 SDL_Log("Loaded action manifest at %s (%d)", loadpath, err); 1582#endif 1583 SDL_free(loadpath); 1584 if (err != EVRInputError_VRInputError_None) { 1585 // I know we don't normally log, but this _really_ should be percolated 1586 // up as far as we can. 1587 SDL_Log("Could not load action manifest path"); 1588 // If we didn't have a hint, this is a soft fail. 1589 // If we did have the hint, then it's a hard fail. 1590 if (hint) { 1591 goto error; 1592 } 1593 } else { 1594 if(!OPENVR_SetupJoystickBasedOnLoadedActionManifest(data)) { 1595 goto error; 1596 } 1597 } 1598 1599 // Setup amount of available displays 1600 device->num_displays = 0; 1601 1602 // Set device free function 1603 device->free = OPENVR_Destroy; 1604 1605 // Setup all functions which we can handle 1606 device->VideoInit = OPENVR_VideoInit; 1607 device->VideoQuit = OPENVR_VideoQuit; 1608 device->SetDisplayMode = OPENVR_SetDisplayMode; 1609 device->CreateSDLWindow = OPENVR_CreateWindow; 1610 device->SetWindowTitle = OPENVR_SetWindowTitle; 1611 device->SetWindowSize = OPENVR_SetWindowSize; 1612 device->GetWindowSizeInPixels = OPENVR_GetWindowSizeInPixels; 1613 device->ShowWindow = OPENVR_ShowWindow; 1614 device->HideWindow = OPENVR_HideWindow; 1615 device->DestroyWindow = OPENVR_DestroyWindow; 1616 device->ShowMessageBox = OPENVR_ShowMessageBox; 1617 1618#ifdef SDL_VIDEO_DRIVER_WINDOWS 1619#ifdef SDL_VIDEO_OPENGL_WGL 1620 device->GL_LoadLibrary = OPENVR_GL_LoadLibrary; 1621 device->GL_GetProcAddress = OPENVR_GL_GetProcAddress; 1622 device->GL_UnloadLibrary = OPENVR_GL_UnloadLibrary; 1623 device->GL_CreateContext = OPENVR_GL_CreateContext; 1624 device->GL_MakeCurrent = OPENVR_GL_MakeCurrent; 1625 device->GL_SetSwapInterval = OPENVR_GL_SetSwapInterval; 1626 device->GL_GetSwapInterval = OPENVR_GL_GetSwapInterval; 1627 device->GL_SwapWindow = OPENVR_GL_SwapWindow; 1628 device->GL_DestroyContext = OPENVR_GL_DestroyContext; 1629#elif SDL_VIDEO_OPENGL_EGL 1630 device->GL_LoadLibrary = WIN_GLES_LoadLibrary; 1631 device->GL_GetProcAddress = WIN_GLES_GetProcAddress; 1632 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary; 1633 device->GL_CreateContext = WIN_GLES_CreateContext; 1634 device->GL_MakeCurrent = WIN_GLES_MakeCurrent; 1635 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval; 1636 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval; 1637 device->GL_SwapWindow = WIN_GLES_SwapWindow; 1638 device->GL_DestroyContext = WIN_GLES_DestroyContext; 1639#endif 1640#else 1641 device->GL_LoadLibrary = OVR_EGL_LoadLibrary; 1642 device->GL_GetProcAddress = OVR_EGL_GetProcAddress; 1643 device->GL_UnloadLibrary = OVR_EGL_UnloadLibrary; 1644 device->GL_CreateContext = OVR_EGL_CreateContext; 1645 device->GL_MakeCurrent = OVR_EGL_MakeCurrent; 1646 device->GL_SetSwapInterval = OVR_EGL_SetSwapInterval; 1647 device->GL_GetSwapInterval = OVR_EGL_GetSwapInterval; 1648 device->GL_DestroyContext = OVR_EGL_DestroyContext; 1649 device->GL_SwapWindow = OPENVR_GL_SwapWindow; 1650#endif 1651 1652#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS) 1653 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary; 1654 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary; 1655 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions; 1656 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface; 1657#else 1658 device->Vulkan_LoadLibrary = 0; 1659 device->Vulkan_UnloadLibrary = 0; 1660 device->Vulkan_GetInstanceExtensions = 0; 1661 device->Vulkan_CreateSurface = 0; 1662#endif 1663 1664 device->PumpEvents = OPENVR_PumpEvents; 1665 device->VideoInit = OPENVR_VideoInit; 1666 device->VideoQuit = OPENVR_VideoQuit; 1667 1668 device->HasScreenKeyboardSupport = OPENVR_HasScreenKeyboardSupport; 1669 device->ShowScreenKeyboard = OPENVR_ShowScreenKeyboard; 1670 device->HideScreenKeyboard = OPENVR_HideScreenKeyboard; 1671 device->SetWindowIcon = OPENVR_SetWindowIcon; 1672 1673 return device; 1674 1675error: 1676 OPENVR_Destroy(device); 1677 return NULL; 1678} 1679 1680VideoBootStrap OPENVR_bootstrap = { 1681 "openvr", "SDL OpenVR video driver", OPENVR_CreateDevice, NULL, false 1682}; 1683 1684#endif // SDL_VIDEO_DRIVER_OPENVR 1685 1686[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.