Atlas - SDL_openvrvideo.c
Home / ext / SDL / src / video / openvr Lines: 1 | Size: 59070 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(); 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)(); 96static void (APIENTRY *ov_glFlush)(); 97static void (APIENTRY *ov_glFinish)(); 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 = sizeof(k_pchBooleanActionPaths) / sizeof(k_pchBooleanActionPaths[0]); 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 = sizeof(k_pchAnalogActionPaths) / sizeof(k_pchAnalogActionPaths[0]); 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 const char * hint = SDL_GetHint("SDL_OPENVR_OVERLAY_PANEL_WIDTH"); 615 float fWidth = hint ? (float)SDL_atof(hint) : 1.0f; 616 videodata->oOverlay->SetOverlayWidthInMeters(videodata->overlayID, fWidth); 617 } 618 { 619 const char * hint = SDL_GetHint("SDL_OPENVR_CURSOR_WIDTH"); 620 // Default is what SteamVR Does 621 float fCursorWidth = hint ? (float)SDL_atof(hint) : 0.06f; 622 videodata->oOverlay->SetOverlayWidthInMeters(videodata->cursorID, fCursorWidth * 0.5f); 623 } 624 { 625 const char * hint = SDL_GetHint("SDL_OPENVR_WINDOW_ICON_FILE"); 626 videodata->bIconOverridden = false; 627 if (hint) { 628 char * tmpcopy = SDL_strdup(hint); 629 EVROverlayError err = videodata->oOverlay->SetOverlayFromFile(videodata->thumbID, tmpcopy); 630 SDL_free(tmpcopy); 631 if (err == EVROverlayError_VROverlayError_None) { 632 videodata->bIconOverridden = SDL_GetHintBoolean("SDL_OPENVR_WINDOW_ICON_OVERRIDE",false); 633 } 634 } 635 } 636 { 637 VRTextureBounds_t bounds; 638 bounds.uMin = 0; 639 bounds.uMax = 1; 640 bounds.vMin = 0; 641 bounds.vMax = 1; 642 videodata->oOverlay->SetOverlayTextureBounds(videodata->overlayID, &bounds); 643 } 644 645 if (!OPENVR_CheckRenderbuffer(_this)) { 646 return false; 647 } 648 649 650 global_openvr_driver = videodata; 651 InitializeMouseFunctions(); 652 653 // Actually show the overlay. 654 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<23, true); //vr::VROverlayFlags_EnableControlBar 655 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<24, true); //vr::VROverlayFlags_EnableControlBarKeyboard 656 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<25, true); //vr::VROverlayFlags_EnableControlBarClose 657#if 0 658 /* OpenVR overlays assume unpremultiplied alpha by default, set this flag to tag the source buffer as premultiplied. 659 * Note that (as of 2025) OpenVR overlay composition is higher quality when premultiplied buffers are provided, 660 * as texture samplers that blend energy (such as bilinear) do not yield sensical results when operating on natively 661 * unpremultiplied textures. It is thus preferable to hand openvr natively premultiplied buffers when accurate 662 * sampling / composition is required. */ 663 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, VROverlayFlags_IsPremultiplied, true ); 664#endif 665 videodata->oOverlay->SetOverlayName(videodata->overlayID, window->title); 666 667 videodata->bDidCreateOverlay = true; 668 videodata->window = window; 669 670 return true; 671} 672 673 674static bool OPENVR_SetupFrame(SDL_VideoDevice *_this, SDL_Window *window) 675{ 676 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 677 static const GLenum buffers[8] = { GL_COLOR_ATTACHMENT0_EXT }; 678 679 videodata->is_buffer_rendering = true; 680 681#ifdef DEBUG_OPENVR 682 { 683 int error = ov_glGetError(); 684 if (error) 685 SDL_Log("Found GL Error before beginning frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); 686 } 687#endif 688 689 ov_glBindFramebuffer(GL_FRAMEBUFFER, videodata->fbo); 690 ov_glDrawBuffers(1, buffers); 691 692 // Set the alpha channel for non-transparent windows 693 if (!(window->flags & SDL_WINDOW_TRANSPARENT)) { 694 ov_glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 695 ov_glColorMask(false, false, false, true); 696 ov_glClear(GL_COLOR_BUFFER_BIT); 697 ov_glColorMask(true, true, true, true); 698 } 699 700 ov_glBindTexture( GL_TEXTURE_2D, videodata->saved_texture_state ); 701 702 return true; 703} 704 705static bool OPENVR_ReleaseFrame(SDL_VideoDevice *_this) 706{ 707 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 708 ov_glGetIntegerv(GL_TEXTURE_BINDING_2D, &videodata->saved_texture_state); 709 710 if (!ov_glGetError) { 711 return true; 712 } 713 714 if (!videodata->is_buffer_rendering) { 715 return true; 716 } 717 718#ifdef DEBUG_OPENVR 719 { 720 int error = ov_glGetError(); 721 if (error) { 722 SDL_Log("Found GL Error before release frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER)); 723 } 724 } 725#endif 726 727 videodata->is_buffer_rendering = false; 728 729 ov_glBindFramebuffer(GL_FRAMEBUFFER, 0); 730 731 if (videodata->overlaytexture != 0 && 732 videodata->targh == videodata->last_targh && 733 videodata->targw == videodata->last_targw) { 734 // Only submit frames to OpenVR if the texture exists. 735 struct Texture_t tex; 736 737 // Setup a Texture_t object to send in the texture. 738 tex.eColorSpace = EColorSpace_ColorSpace_Auto; 739 tex.eType = ETextureType_TextureType_OpenGL; 740 tex.handle = (void *)(intptr_t)videodata->overlaytexture; 741 742 // Send texture into OpenVR as the overlay. 743 videodata->oOverlay->SetOverlayTexture(videodata->overlayID, &tex); 744 } 745 746 if (!videodata->bHasShownOverlay && videodata->bDidCreateOverlay) { 747 videodata->oOverlay->ShowDashboard(videodata->sOverlayName); 748 videodata->bHasShownOverlay = true; 749 } 750 751 if (videodata->renderdoc_debugmarker_frame_end) { 752 ov_glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, 753 GL_DEBUG_TYPE_MARKER, MARKER_ID, GL_DEBUG_SEVERITY_NOTIFICATION, -1, 754 MARKER_STR); 755 } 756 757 return OPENVR_CheckRenderbuffer(_this); 758} 759 760static void OPENVR_HandleResize(SDL_VideoDevice *_this, int w, int h) 761{ 762 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 763 data->targw = w; 764 data->targh = h; 765} 766 767static bool OPENVR_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) 768{ 769 return true; 770} 771 772 773#ifdef SDL_VIDEO_DRIVER_WINDOWS 774static LRESULT CALLBACK OpenVRVideoWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 775{ 776 switch (msg) { 777 case WM_DESTROY: 778 return 0; 779 } 780 return DefWindowProc(hwnd, msg, wParam, lParam); 781} 782 783static bool OPENVR_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path) 784{ 785 if (path == NULL) { 786 path = SDL_GetHint(SDL_HINT_OPENGL_LIBRARY); 787 } 788 789 if (path == NULL) { 790 path = DEFAULT_OPENGL; 791 } 792 _this->gl_config.dll_handle = SDL_LoadObject(path); 793 if (!_this->gl_config.dll_handle) { 794 return false; 795 } 796 SDL_strlcpy(_this->gl_config.driver_path, path, 797 SDL_arraysize(_this->gl_config.driver_path)); 798 799 // Allocate OpenGL memory 800 _this->gl_data = (struct SDL_GLDriverData *)SDL_calloc(1, sizeof(struct SDL_GLDriverData)); 801 if (!_this->gl_data) { 802 return false; 803 } 804 _this->gl_config.driver_loaded = true; 805 806 return true; 807} 808 809static SDL_FunctionPointer OPENVR_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) 810{ 811 SDL_FunctionPointer result = NULL; 812 if (ov_wglGetProcAddress) { 813 result = (SDL_FunctionPointer)ov_wglGetProcAddress(proc); 814 if (result) { 815 return result; 816 } 817 } 818 819 return SDL_LoadFunction(_this->gl_config.dll_handle, proc); 820} 821 822static void OPENVR_GL_UnloadLibrary(SDL_VideoDevice *_this) 823{ 824 SDL_GL_UnloadLibrary(); 825} 826 827static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) 828{ 829 GLint numExtensions; 830 int i; 831 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 832 if (!videodata->hglrc) { 833 // Crate a surfaceless EGL Context 834 HWND hwnd; 835 836 WNDCLASSA wnd; 837 wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 838 wnd.lpfnWndProc = OpenVRVideoWndProc; 839 wnd.cbClsExtra = 0; 840 wnd.cbWndExtra = 0; 841 wnd.hInstance = GetModuleHandle(NULL); 842 wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); 843 wnd.hCursor = LoadCursor(NULL, IDC_ARROW); 844 wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); 845 wnd.lpszMenuName = NULL; 846 wnd.lpszClassName = "SDL_openvrvideo_classname"; 847 RegisterClassA(&wnd); 848 hwnd = CreateWindowA("SDL_openvrvideo_classname", "SDL_openvrvideo_windowname", (WS_OVERLAPPEDWINDOW), 0, 0, 849 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL); 850 851 MSG msg; 852 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 853 TranslateMessage(&msg); 854 DispatchMessage(&msg); 855 } 856 857 videodata->hdc = GetDC(hwnd); 858 859 static PIXELFORMATDESCRIPTOR pfd = 860 { 861 sizeof(PIXELFORMATDESCRIPTOR), 862 1, 863 PFD_DRAW_TO_WINDOW | 864 PFD_SUPPORT_OPENGL | 865 PFD_DOUBLEBUFFER, 866 PFD_TYPE_RGBA, 867 24, 868 8, 0, 8, 8, 8, 16, 869 8, 870 24, 871 32, 872 8, 8, 8, 8, 873 16, 874 0, 875 0, 876 PFD_MAIN_PLANE, 877 0, 878 0, 0, 0 879 }; 880 GLuint PixelFormat = ChoosePixelFormat(videodata->hdc, &pfd); 881 if (!SetPixelFormat(videodata->hdc, PixelFormat, &pfd)) { 882 SDL_SetError( "Could not set pixel format" ); 883 return NULL; 884 } 885 HMODULE opengl = GetModuleHandleA(DEFAULT_OPENGL); 886 if (!opengl) { 887 SDL_SetError("Could not open OpenGL Library %s", DEFAULT_OPENGL); 888 return NULL; 889 } 890 891 ov_wglMakeCurrent = (BOOL(*)(HDC, HGLRC))GetProcAddress(opengl, "wglMakeCurrent"); 892 ov_wglCreateContext = (HGLRC(*)(HDC))GetProcAddress(opengl, "wglCreateContext"); 893 ov_wglGetProcAddress = (PROC(*)(LPCSTR))GetProcAddress(opengl, "wglGetProcAddress"); 894 ov_wglDeleteContext = (BOOL(*)(HGLRC))GetProcAddress(opengl, "wglDeleteContext"); 895 if (!ov_wglMakeCurrent || !ov_wglCreateContext) { 896 SDL_SetError("Cannot get wgl context procs(%p, %p)", ov_wglMakeCurrent, ov_wglCreateContext); 897 return NULL; 898 } 899 900 videodata->hglrc = ov_wglCreateContext(videodata->hdc); 901 if (!videodata->hglrc || !ov_wglMakeCurrent(videodata->hdc, videodata->hglrc)) { 902 SDL_SetError("Could not make current OpenGL context."); 903 return NULL; 904 } 905 } 906 907 i = OPENVR_InitExtensions(_this); 908 if (i == 0) { 909 return NULL; 910 } 911 912 videodata->renderdoc_debugmarker_frame_end = false; 913 914 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 915 for (i = 0; i < numExtensions; i++) { 916 const char *ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i); 917 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { 918#ifdef DEBUG_OPENVR 919 SDL_Log("Found renderdoc debug extension."); 920#endif 921 videodata->renderdoc_debugmarker_frame_end = true; 922 } 923 } 924 925 if (!videodata->bDidCreateOverlay) { 926 if (!OPENVR_InitializeOverlay(_this, window)) { 927 return NULL; 928 } 929 } 930 931 OPENVR_CheckRenderbuffer(_this); 932 933 OPENVR_SetupFrame(_this, window); 934 935 SDL_GLContext result = SDL_malloc(sizeof(struct SDL_GLContextState)); 936 if (!result) { 937 return NULL; 938 } 939 result->hglrc = videodata->hglrc; 940 return result; 941} 942 943static bool OPENVR_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *wnd, SDL_GLContext context) 944{ 945 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 946 ov_wglMakeCurrent(videodata->hdc, videodata->hglrc); 947 return true; 948} 949 950static bool OPENVR_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 951{ 952 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 953 videodata->swap_interval = interval; 954 return true; 955} 956 957static bool OPENVR_GL_GetSwapInterval(SDL_VideoDevice *_this, int *swapInterval) 958{ 959 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 960 if (swapInterval) 961 *swapInterval = videodata->swap_interval; 962 else 963 return SDL_SetError("OPENVR: null passed in for GetSwapInterval"); 964 return true; 965} 966 967static bool OPENVR_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 968{ 969 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 970 ov_wglMakeCurrent(videodata->hdc, NULL); 971 ov_wglDeleteContext(videodata->hglrc); 972 return true; 973} 974 975 976#else 977 978static EGLint context_attribs[] = { 979 EGL_CONTEXT_CLIENT_VERSION, 2, 980 EGL_NONE 981}; 982 983static bool SDL_EGL_InitInternal(SDL_VideoData * vd) 984{ 985 // Crate a surfaceless EGL Context 986 EGLint major, minor; 987 EGLConfig eglCfg=NULL; 988 EGLBoolean b; 989 990 vd->eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 991#ifdef DEBUG_OPENVR 992 SDL_Log("EGL Display: %p", vd->eglDpy); 993#endif 994 995 if (vd->eglDpy == 0) { 996 return SDL_SetError("No EGL Display"); 997 } 998 999 b = eglInitialize(vd->eglDpy, &major, &minor); 1000 if (!b) { 1001 return SDL_SetError("eglInitialize failed"); 1002 } 1003 1004 eglBindAPI(EGL_OPENGL_API); 1005#ifdef DEBUG_OPENVR 1006 SDL_Log("EGL Major Minor: %d %d = %d", major, minor, b); 1007#endif 1008 1009 vd->eglCtx = eglCreateContext(vd->eglDpy, eglCfg, EGL_NO_CONTEXT, context_attribs); 1010 1011#ifdef DEBUG_OPENVR 1012 { 1013 int err = eglGetError(); 1014 if (err != EGL_SUCCESS) { 1015 return SDL_SetError("EGL Error after eglCreateContext %d", err); 1016 } 1017 } 1018#endif 1019 1020 if (!vd->eglCtx) { 1021 return SDL_SetError("No EGL context available"); 1022 } 1023 1024 eglMakeCurrent(vd->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, vd->eglCtx); 1025 1026 return true; 1027} 1028 1029// Linux, EGL, etc. 1030static bool OVR_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *path) 1031{ 1032 return SDL_EGL_LoadLibrary(_this, path, /*displaydata->native_display*/0, 0); 1033} 1034 1035static SDL_FunctionPointer OVR_EGL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) 1036{ 1037 return SDL_EGL_GetProcAddress(proc); 1038} 1039static void OVR_EGL_UnloadLibrary(SDL_VideoDevice *_this) 1040{ 1041 return SDL_EGL_UnloadLibrary(_this); 1042} 1043static SDL_GLContext OVR_EGL_CreateContext(SDL_VideoDevice *_this, SDL_Window * window) 1044{ 1045 GLint numExtensions; 1046 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1047 if (!videodata->eglCtx) { 1048 if (!SDL_EGL_InitInternal(videodata)) { 1049 return NULL; 1050 } 1051 } 1052 1053 if (!OPENVR_InitExtensions(_this)) { 1054 return NULL; 1055 } 1056 1057 videodata->renderdoc_debugmarker_frame_end = false; 1058 1059 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); 1060 for(int i = 0; i < numExtensions; i++) { 1061 const char * ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i); 1062 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) { 1063#ifdef DEBUG_OPENVR 1064 SDL_Log("Found renderdoc debug extension."); 1065#endif 1066 videodata->renderdoc_debugmarker_frame_end = true; 1067 } 1068 } 1069 1070 if (!videodata->bDidCreateOverlay) { 1071 if (!OPENVR_InitializeOverlay(_this, window)) { 1072 return NULL; 1073 } 1074 } 1075 1076 OPENVR_CheckRenderbuffer(_this); 1077 1078 OPENVR_SetupFrame(_this, window); 1079 1080 return videodata->eglCtx; 1081} 1082 1083static bool OVR_EGL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window * wnd, SDL_GLContext context) 1084{ 1085 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1086 eglMakeCurrent(videodata->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, videodata->eglCtx); 1087 return true; 1088} 1089 1090static bool OVR_EGL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 1091{ 1092 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1093 videodata->swap_interval = interval; 1094 return true; 1095} 1096 1097static bool OVR_EGL_GetSwapInterval(SDL_VideoDevice *_this, int * swapInterval) 1098{ 1099 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1100 if (swapInterval) 1101 *swapInterval = videodata->swap_interval; 1102 else 1103 return SDL_SetError("OPENVR: null passed in for GetSwapInterval"); 1104 return true; 1105} 1106 1107static bool OVR_EGL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 1108{ 1109 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1110 if (videodata->eglDpy) { 1111 eglTerminate(videodata->eglDpy); 1112 } 1113 return true; 1114} 1115 1116#endif 1117 1118static bool OPENVR_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) 1119{ 1120 SDL_WindowData *data; 1121 1122 // Allocate window internal data 1123 data = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); 1124 if (data == NULL) { 1125 return SDL_OutOfMemory(); 1126 } 1127 1128 window->max_w = 4096; 1129 window->max_h = 4096; 1130 window->min_w = 1; 1131 window->min_h = 1; 1132 1133 // Setup driver data for this window 1134 window->internal = data; 1135 return true; 1136} 1137 1138 1139static void OPENVR_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) 1140{ 1141 SDL_WindowData *data; 1142 1143 data = window->internal; 1144 SDL_free(data); 1145 window->internal = NULL; 1146} 1147 1148static void OPENVR_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) 1149{ 1150 SDL_VideoData * data = (SDL_VideoData *)_this->internal; 1151 if (data->bDidCreateOverlay) { 1152 data->oOverlay->SetOverlayName(data->overlayID, window->title); 1153 } 1154} 1155 1156static void OPENVR_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) 1157{ 1158 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1159 1160 if (window->pending.w != window->w) { 1161 window->w = window->pending.w; 1162 } 1163 1164 if (window->pending.h != window->h) { 1165 window->h = window->pending.h; 1166 } 1167 1168 if (data->targh != window->h || data->targw != window->w) { 1169 OPENVR_HandleResize(_this, window->w, window->h); 1170 } 1171 1172 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->w, window->h); 1173} 1174 1175static void OPENVR_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h) 1176{ 1177 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1178 *w = data->targw; 1179 *h = data->targh; 1180} 1181 1182static void OPENVR_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) 1183{ 1184 SDL_VideoData *data = (SDL_VideoData *)_this->internal; 1185 if (data->targh != window->h || data->targw != window->w) { 1186 OPENVR_HandleResize(_this, window->w, window->h); 1187 } 1188 1189 data->oOverlay->ShowDashboard(data->sOverlayName); 1190 1191 window->flags |= (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS); 1192 SDL_SetKeyboardFocus(window); 1193} 1194 1195static void OPENVR_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) 1196{ 1197 return; 1198} 1199 1200static bool OPENVR_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) 1201{ 1202 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1203 1204 // This is a little weird. On Windows, we don't necessarily call the normal 1205 // context creation function, and we might get here without having our buffers 1206 // initialized. 1207 if (!videodata->bDidCreateOverlay) { 1208 if (!OPENVR_InitializeOverlay(_this, window)) { 1209 return false; 1210 } 1211 } 1212 1213 if (!OPENVR_ReleaseFrame(_this)) { 1214 return false; 1215 } 1216 1217 // If swap_interval is nonzero (i.e. -1 or 1) we want to wait for vsync on the compositor. 1218 if (videodata->swap_interval != 0) { 1219 videodata->oOverlay->WaitFrameSync(100); 1220 } 1221 1222 if (!OPENVR_SetupFrame(_this, window)) { 1223 return false; 1224 } 1225 1226 return true; 1227} 1228 1229static void OPENVR_HandleMouse(float x, float y, int btn, int evt) 1230{ 1231 if (evt == 2) { 1232 SDL_SendMouseMotion(0, NULL, SDL_GLOBAL_MOUSE_ID, false, x, y); 1233 } else { 1234 const Uint8 button = SDL_BUTTON_LEFT + btn; 1235 const bool down = (evt != 0); 1236 SDL_SendMouseButton(0, NULL, SDL_GLOBAL_MOUSE_ID, button, down); 1237 } 1238} 1239 1240 1241static bool OPENVR_HasScreenKeyboardSupport(SDL_VideoDevice *_this) 1242{ 1243 return true; 1244} 1245 1246static void OPENVR_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) 1247{ 1248 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1249 if (!videodata || 1250 videodata->oOverlay == 0 || 1251 videodata->overlayID == 0) { 1252 return; 1253 } 1254 EGamepadTextInputMode input_mode; 1255 switch (SDL_GetTextInputType(props)) { 1256 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN: 1257 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: 1258 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModePassword; 1259 break; 1260 default: 1261 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModeNormal; 1262 break; 1263 } 1264 EGamepadTextInputLineMode line_mode; 1265 if (SDL_GetTextInputMultiline(props)) { 1266 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeMultipleLines; 1267 } else { 1268 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeSingleLine; 1269 } 1270 videodata->oOverlay->ShowKeyboardForOverlay(videodata->overlayID, 1271 input_mode, line_mode, 1272 EKeyboardFlags_KeyboardFlag_Minimal, "Virtual Keyboard", 128, "", 0); 1273 SDL_SendScreenKeyboardShown(); 1274} 1275 1276static void OPENVR_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window) 1277{ 1278 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1279 videodata->oOverlay->HideKeyboard(); 1280 SDL_SendScreenKeyboardHidden(); 1281} 1282 1283static SDL_Cursor *OPENVR_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) 1284{ 1285 SDL_Cursor *result = SDL_calloc(1, sizeof(SDL_Cursor)); 1286 if (!result) { 1287 return NULL; 1288 } 1289 1290 uint32_t * pixels = ImageSDLToOpenVRGL(surface, false); 1291 SDL_CursorData *ovrc = (SDL_CursorData *)SDL_calloc(1, sizeof(*ovrc)); 1292 if (!ovrc) { 1293 SDL_free(result); 1294 return NULL; 1295 } 1296 result->internal = ovrc; 1297 1298 ov_glGenTextures(1, &ovrc->texture_id_handle); 1299 ov_glBindTexture(GL_TEXTURE_2D, ovrc->texture_id_handle); 1300 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 1301 SDL_free(pixels); 1302 ov_glBindTexture(GL_TEXTURE_2D, 0); 1303 1304 ovrc->hot_x = hot_x; 1305 ovrc->hot_y = hot_y; 1306 ovrc->w = surface->w; 1307 ovrc->h = surface->h; 1308 1309 return result; 1310} 1311 1312static bool OPENVR_ShowCursor(SDL_Cursor * cursor) 1313{ 1314 SDL_CursorData * ovrc; 1315 EVROverlayError e; 1316 Texture_t texture; 1317 HmdVector2_t hotspot; 1318 VRTextureBounds_t tb; 1319 1320 if (!cursor) { 1321 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, true); 1322 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, k_ulOverlayHandleInvalid); 1323 if (e != EVROverlayError_VROverlayError_None) { 1324 return OPENVR_SetOverlayError(e); 1325 } 1326 return true; 1327 } 1328 1329 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, false); 1330 1331 ovrc = cursor->internal; 1332 1333 if (!ovrc) { 1334 // Sometimes at boot there is a race condition where this is not ready. 1335 return true; 1336 } 1337 1338 hotspot.v[0] = (float)ovrc->hot_x / (float)ovrc->w; 1339 hotspot.v[1] = (float)ovrc->hot_y / (float)ovrc->h; 1340 1341 texture.handle = (void *)(intptr_t)(ovrc->texture_id_handle); 1342 texture.eType = ETextureType_TextureType_OpenGL; 1343 texture.eColorSpace = EColorSpace_ColorSpace_Auto; 1344 1345 tb.uMin = 0; 1346 tb.uMax = 1; 1347 tb.vMin = 1; 1348 tb.vMax = 0; 1349 1350 e = global_openvr_driver->oOverlay->SetOverlayTextureBounds(global_openvr_driver->cursorID, &tb); 1351 if (e != EVROverlayError_VROverlayError_None) { 1352 return OPENVR_SetOverlayError(e); 1353 } 1354 1355 e = global_openvr_driver->oOverlay->SetOverlayTransformCursor(global_openvr_driver->cursorID, &hotspot); 1356 if (e != EVROverlayError_VROverlayError_None) { 1357 return OPENVR_SetOverlayError(e); 1358 } 1359 1360 e = global_openvr_driver->oOverlay->SetOverlayTexture(global_openvr_driver->cursorID, &texture); 1361 if (e != EVROverlayError_VROverlayError_None) { 1362 return OPENVR_SetOverlayError(e); 1363 } 1364 1365 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, global_openvr_driver->cursorID); 1366 if (e != EVROverlayError_VROverlayError_None) { 1367 return OPENVR_SetOverlayError(e); 1368 } 1369 1370 return true; 1371} 1372 1373static void OPENVR_FreeCursor(SDL_Cursor * cursor) 1374{ 1375 if (cursor) { 1376 SDL_CursorData *ovrc = cursor->internal; 1377 if (ovrc) { 1378 ov_glDeleteTextures(1, &ovrc->texture_id_handle); 1379 SDL_free(ovrc); 1380 } 1381 SDL_free(cursor); 1382 } 1383} 1384 1385 1386static bool OPENVR_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window * window, SDL_Surface * icon) 1387{ 1388 if (!global_openvr_driver) { 1389 return SDL_SetError("OpenVR Overlay not initialized"); 1390 } 1391 1392 unsigned texture_id_handle; 1393 EVROverlayError e; 1394 Texture_t texture; 1395 uint32_t * pixels; 1396 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1397 if (videodata->bIconOverridden) { 1398 return SDL_SetError("OpenVR Icon is overridden."); 1399 } 1400 1401 pixels = ImageSDLToOpenVRGL(icon, true); 1402 1403 ov_glGenTextures(1, &texture_id_handle); 1404 ov_glBindTexture(GL_TEXTURE_2D, texture_id_handle); 1405 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, icon->w, icon->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 1406 SDL_free(pixels); 1407 ov_glBindTexture(GL_TEXTURE_2D, 0); 1408 1409 texture.handle = (void *)(intptr_t)(texture_id_handle); 1410 texture.eType = ETextureType_TextureType_OpenGL; 1411 texture.eColorSpace = EColorSpace_ColorSpace_Auto; 1412 1413 e = global_openvr_driver->oOverlay->SetOverlayTexture(videodata->thumbID, &texture); 1414 if (e != EVROverlayError_VROverlayError_None) { 1415 return OPENVR_SetOverlayError(e); 1416 } 1417 return true; 1418} 1419 1420static bool OPENVR_ShowMessageBox(SDL_VideoDevice *_this,const SDL_MessageBoxData *messageboxdata, int *buttonid) 1421{ 1422 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1423 char empty = 0; 1424 char * message = SDL_strdup(messageboxdata->message?messageboxdata->message:""); 1425 char * title = SDL_strdup(messageboxdata->message?messageboxdata->message:""); 1426 char * ok = SDL_strdup("Ok"); 1427 videodata->oOverlay->ShowMessageOverlay(message, title, ok, &empty, &empty, &empty); 1428 SDL_free(ok); 1429 SDL_free(title); 1430 SDL_free(message); 1431 return true; 1432} 1433 1434static void InitializeMouseFunctions() 1435{ 1436 SDL_Mouse *mouse = SDL_GetMouse(); 1437 mouse->CreateCursor = OPENVR_CreateCursor; 1438 mouse->ShowCursor = OPENVR_ShowCursor; 1439 mouse->FreeCursor = OPENVR_FreeCursor; 1440} 1441 1442static void OPENVR_PumpEvents(SDL_VideoDevice *_this) 1443{ 1444 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal; 1445 struct VREvent_t nEvent; 1446 if (videodata->overlayID) { 1447 while (videodata->oOverlay->PollNextOverlayEvent(videodata->overlayID, &nEvent, sizeof(nEvent))) { 1448 switch (nEvent.eventType) { 1449 case EVREventType_VREvent_ButtonPress: 1450 case EVREventType_VREvent_ButtonUnpress: 1451 break; 1452 case EVREventType_VREvent_MouseMove: 1453 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, nEvent.data.mouse.button, 2); 1454 break; 1455 case EVREventType_VREvent_MouseButtonDown: 1456 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 1); 1457 break; 1458 case EVREventType_VREvent_MouseButtonUp: 1459 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 0); 1460 break; 1461 case EVREventType_VREvent_KeyboardCharInput: 1462 SDL_SendKeyboardUnicodeKey(SDL_GetTicksNS(), nEvent.data.keyboard.cNewInput[0]); 1463 break; 1464 case EVREventType_VREvent_OverlayShown: 1465 SDL_SetKeyboardFocus(videodata->window); 1466 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_RESTORED, 0, 0); 1467 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_SHOWN, 0, 0); 1468 break; 1469 case EVREventType_VREvent_OverlayHidden: 1470 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_HIDDEN, 0, 0); 1471 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); 1472 SDL_SetKeyboardFocus(NULL); 1473 break; 1474 case EVREventType_VREvent_OverlayClosed: 1475 case EVREventType_VREvent_Quit: 1476 SDL_Quit(); 1477 break; 1478 } 1479 } 1480 } 1481} 1482 1483 1484static SDL_VideoDevice *OPENVR_CreateDevice(void) 1485{ 1486 SDL_VideoDevice *device; 1487 SDL_VideoData *data; 1488 const char *hint; 1489 1490#ifdef SDL_PLATFORM_WINDOWS 1491 SDL_RegisterApp(NULL, 0, NULL); 1492#endif 1493 1494 // Initialize all variables that we clean on shutdown 1495 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 1496 if (device) { 1497 data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); 1498 } else { 1499 data = NULL; 1500 } 1501 if (!data) { 1502#ifdef SDL_PLATFORM_WINDOWS 1503 SDL_UnregisterApp(); 1504#endif 1505 SDL_free(device); 1506 return NULL; 1507 } 1508 device->internal = data; 1509 1510 hint = SDL_GetHint(SDL_HINT_OPENVR_LIBRARY); 1511 if (hint) { 1512 data->openVRLIB = SDL_LoadObject(hint); 1513 } 1514 if (!data->openVRLIB) { 1515 data->openVRLIB = SDL_LoadObject(SDL_OPENVR_DRIVER_DYNAMIC); 1516 } 1517 if (!data->openVRLIB) { 1518 SDL_SetError("Could not open OpenVR API Library"); 1519 goto error; 1520 } 1521 1522 data->FN_VR_InitInternal = (intptr_t(*)(EVRInitError * peError, EVRApplicationType eType))SDL_LoadFunction(data->openVRLIB, "VR_InitInternal"); 1523 data->FN_VR_GetVRInitErrorAsEnglishDescription = (const char *(*)(EVRInitError error))SDL_LoadFunction(data->openVRLIB, "VR_GetVRInitErrorAsEnglishDescription"); 1524 data->FN_VR_GetGenericInterface = (intptr_t (*)(const char *pchInterfaceVersion, EVRInitError * peError))SDL_LoadFunction(data->openVRLIB, "VR_GetGenericInterface"); 1525 if (!data->FN_VR_InitInternal || !data->FN_VR_GetVRInitErrorAsEnglishDescription || !data->FN_VR_GetGenericInterface) { 1526 goto error; 1527 } 1528 1529 char fnname[128]; 1530 EVRInitError e; 1531 data->vrtoken = data->FN_VR_InitInternal(&e, EVRApplicationType_VRApplication_Overlay); 1532 if (!data->vrtoken) { 1533 const char *err = "Can't get english description"; 1534 if (data->FN_VR_GetVRInitErrorAsEnglishDescription != NULL) 1535 err = data->FN_VR_GetVRInitErrorAsEnglishDescription(e); 1536 SDL_SetError("Could not generate OpenVR Context (%s)", err); 1537 goto error; 1538 } 1539 1540 SDL_snprintf(fnname, 127, "FnTable:%s", IVRSystem_Version); 1541 data->oSystem = (struct VR_IVRSystem_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1542 SDL_snprintf(fnname, 127, "FnTable:%s", IVROverlay_Version); 1543 data->oOverlay = (struct VR_IVROverlay_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1544 SDL_snprintf(fnname, 127, "FnTable:%s", IVRInput_Version); 1545 data->oInput = (struct VR_IVRInput_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e); 1546 1547 if (!data->oOverlay || !data->oSystem || !data->oInput) { 1548 SDL_SetError("Could not get interfaces for the OpenVR System (%s), Overlay (%s) and Input (%s) versions", IVRSystem_Version, IVROverlay_Version, IVRInput_Version); 1549 } 1550 1551 hint = SDL_GetHint("SDL_OPENVR_INPUT_PROFILE"); 1552 char *loadpath = 0; 1553 EVRInputError err; 1554 1555 if (hint) { 1556 SDL_asprintf(&loadpath, "%s", hint); 1557 } else { 1558 const char *basepath = SDL_GetBasePath(); 1559 SDL_asprintf(&loadpath, "%ssdloverlay_actions.json", basepath); 1560 } 1561 if (!loadpath) { 1562 goto error; 1563 } 1564 1565 err = data->oInput->SetActionManifestPath(loadpath); 1566#ifdef DEBUG_OPENVR 1567 SDL_Log("Loaded action manifest at %s (%d)", loadpath, err); 1568#endif 1569 SDL_free(loadpath); 1570 if (err != EVRInputError_VRInputError_None) { 1571 // I know we don't normally log, but this _really_ should be percolated 1572 // up as far as we can. 1573 SDL_Log("Could not load action manifest path"); 1574 // If we didn't have a hint, this is a soft fail. 1575 // If we did have the hint, then it's a hard fail. 1576 if (hint) { 1577 goto error; 1578 } 1579 } else { 1580 if(!OPENVR_SetupJoystickBasedOnLoadedActionManifest(data)) { 1581 goto error; 1582 } 1583 } 1584 1585 // Setup amount of available displays 1586 device->num_displays = 0; 1587 1588 // Set device free function 1589 device->free = OPENVR_Destroy; 1590 1591 // Setup all functions which we can handle 1592 device->VideoInit = OPENVR_VideoInit; 1593 device->VideoQuit = OPENVR_VideoQuit; 1594 device->SetDisplayMode = OPENVR_SetDisplayMode; 1595 device->CreateSDLWindow = OPENVR_CreateWindow; 1596 device->SetWindowTitle = OPENVR_SetWindowTitle; 1597 device->SetWindowSize = OPENVR_SetWindowSize; 1598 device->GetWindowSizeInPixels = OPENVR_GetWindowSizeInPixels; 1599 device->ShowWindow = OPENVR_ShowWindow; 1600 device->HideWindow = OPENVR_HideWindow; 1601 device->DestroyWindow = OPENVR_DestroyWindow; 1602 device->ShowMessageBox = OPENVR_ShowMessageBox; 1603 1604#ifdef SDL_VIDEO_DRIVER_WINDOWS 1605#ifdef SDL_VIDEO_OPENGL_WGL 1606 device->GL_LoadLibrary = OPENVR_GL_LoadLibrary; 1607 device->GL_GetProcAddress = OPENVR_GL_GetProcAddress; 1608 device->GL_UnloadLibrary = OPENVR_GL_UnloadLibrary; 1609 device->GL_CreateContext = OPENVR_GL_CreateContext; 1610 device->GL_MakeCurrent = OPENVR_GL_MakeCurrent; 1611 device->GL_SetSwapInterval = OPENVR_GL_SetSwapInterval; 1612 device->GL_GetSwapInterval = OPENVR_GL_GetSwapInterval; 1613 device->GL_SwapWindow = OPENVR_GL_SwapWindow; 1614 device->GL_DestroyContext = OPENVR_GL_DestroyContext; 1615#elif SDL_VIDEO_OPENGL_EGL 1616 device->GL_LoadLibrary = WIN_GLES_LoadLibrary; 1617 device->GL_GetProcAddress = WIN_GLES_GetProcAddress; 1618 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary; 1619 device->GL_CreateContext = WIN_GLES_CreateContext; 1620 device->GL_MakeCurrent = WIN_GLES_MakeCurrent; 1621 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval; 1622 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval; 1623 device->GL_SwapWindow = WIN_GLES_SwapWindow; 1624 device->GL_DestroyContext = WIN_GLES_DestroyContext; 1625#endif 1626#else 1627 device->GL_LoadLibrary = OVR_EGL_LoadLibrary; 1628 device->GL_GetProcAddress = OVR_EGL_GetProcAddress; 1629 device->GL_UnloadLibrary = OVR_EGL_UnloadLibrary; 1630 device->GL_CreateContext = OVR_EGL_CreateContext; 1631 device->GL_MakeCurrent = OVR_EGL_MakeCurrent; 1632 device->GL_SetSwapInterval = OVR_EGL_SetSwapInterval; 1633 device->GL_GetSwapInterval = OVR_EGL_GetSwapInterval; 1634 device->GL_DestroyContext = OVR_EGL_DestroyContext; 1635 device->GL_SwapWindow = OPENVR_GL_SwapWindow; 1636#endif 1637 1638#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS) 1639 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary; 1640 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary; 1641 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions; 1642 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface; 1643#else 1644 device->Vulkan_LoadLibrary = 0; 1645 device->Vulkan_UnloadLibrary = 0; 1646 device->Vulkan_GetInstanceExtensions = 0; 1647 device->Vulkan_CreateSurface = 0; 1648#endif 1649 1650 device->PumpEvents = OPENVR_PumpEvents; 1651 device->VideoInit = OPENVR_VideoInit; 1652 device->VideoQuit = OPENVR_VideoQuit; 1653 1654 device->HasScreenKeyboardSupport = OPENVR_HasScreenKeyboardSupport; 1655 device->ShowScreenKeyboard = OPENVR_ShowScreenKeyboard; 1656 device->HideScreenKeyboard = OPENVR_HideScreenKeyboard; 1657 device->SetWindowIcon = OPENVR_SetWindowIcon; 1658 1659 return device; 1660 1661error: 1662 OPENVR_Destroy(device); 1663 return NULL; 1664} 1665 1666VideoBootStrap OPENVR_bootstrap = { 1667 "openvr", "SDL OpenVR video driver", OPENVR_CreateDevice, NULL, false 1668}; 1669 1670#endif // SDL_VIDEO_DRIVER_WINDOWS 1671 1672[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.