UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
openxr_gl.cpp File Reference
#include <chrono>
#include <thread>
#include <vector>
#include <condition_variable>
#include <queue>
#include <assert.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include "debug.h"
#include "host.h"
#include "keyboard_control.h"
#include "lib_common.h"
#include "messaging.h"
#include "module.h"
#include "video.h"
#include "video_display.h"
#include "video_display/splashscreen.h"
#include "opengl_utils.hpp"
#include "opengl_panorama.hpp"
#include "sdl_window.hpp"
#include "utils/profile_timer.hpp"
Include dependency graph for openxr_gl.cpp:

Go to the source code of this file.

Classes

class  Gl_interop_swapchain
 
class  Openxr_instance
 
class  Openxr_local_space
 
class  Openxr_session
 
struct  Openxr_state
 
class  Openxr_swapchain
 
struct  state_xrgl
 

Macros

#define MAX_BUFFER_SIZE   3
 

Functions

static video_frame * allocate_frame (state_xrgl *s)
 
static void delete_frame (video_frame *f)
 
static void display_xrgl_done (void *state)
 
static bool display_xrgl_get_property (void *state, int property, void *val, size_t *len)
 
static struct video_frame * display_xrgl_getf (void *state)
 
static void * display_xrgl_init (struct module *parent, const char *fmt, unsigned int flags)
 
static void display_xrgl_probe (struct device_info **available_cards, int *count, void(**deleter)(void *))
 
static bool display_xrgl_putf (void *state, struct video_frame *frame, long long nonblock)
 
static bool display_xrgl_reconfigure (void *state, struct video_desc desc)
 
static void display_xrgl_run (void *state)
 
static glm::mat4 get_proj_mat (const XrFovf &fov, float zNear, float zFar)
 
static std::vector< int64_t > get_swapchain_formats (XrSession session)
 
static std::vector< XrViewConfigurationView > get_views (Openxr_state &xr_state)
 
static void map_new_buffer (struct video_frame *f)
 
static void recycle_frame (video_frame *f)
 
 REGISTER_MODULE (openxr_gl, &openxr_gl_info, LIBRARY_CLASS_VIDEO_DISPLAY, VIDEO_DISPLAY_ABI_VERSION)
 
static int64_t select_swapchain_fmt (const std::vector< int64_t > &swapchain_formats)
 
static void worker (state_xrgl *s)
 

Variables

static const struct video_display_info openxr_gl_info
 

Detailed Description

Author
Martin Piatka piatk.nosp@m.a@ce.nosp@m.snet..nosp@m.cz

Definition in file openxr_gl.cpp.

Macro Definition Documentation

◆ MAX_BUFFER_SIZE

#define MAX_BUFFER_SIZE   3

Definition at line 83 of file openxr_gl.cpp.

Referenced by display_xrgl_init(), display_xrgl_putf(), and worker().

Function Documentation

◆ allocate_frame()

static video_frame * allocate_frame ( state_xrgl * s)
static

Definition at line 539 of file openxr_gl.cpp.

539 {
541 GlBuffer *pbo = new GlBuffer();
542 buffer->callbacks.dispose_udata = pbo;
543 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->get());
544
545 map_new_buffer(buffer);
546
547 return buffer;
548}
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
GLuint get()
static void map_new_buffer(struct video_frame *f)
video_desc current_desc
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct video_frame_callbacks callbacks
Definition types.h:324

References video_frame::callbacks, state_xrgl::current_desc, video_frame_callbacks::dispose_udata, GlBuffer::get(), map_new_buffer(), and vf_alloc_desc().

Referenced by worker().

Here is the call graph for this function:

◆ delete_frame()

static void delete_frame ( video_frame * f)
static

Definition at line 523 of file openxr_gl.cpp.

523 {
524 GlBuffer *pbo = static_cast<GlBuffer *>(f->callbacks.dispose_udata);
525 vf_free(f);
526
527 if(!pbo){
528 return;
529 }
530 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->get());
531 if(f->tiles[0].data){
532 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
533 }
534
535 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
536 delete pbo;
537}
void vf_free(struct video_frame *buf)
Frees video_frame structure.
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345

References video_frame::callbacks, tile::data, video_frame_callbacks::dispose_udata, GlBuffer::get(), video_frame::tiles, and vf_free().

Referenced by worker().

Here is the call graph for this function:

◆ display_xrgl_done()

static void display_xrgl_done ( void * state)
static

Definition at line 1003 of file openxr_gl.cpp.

1003 {
1004 state_xrgl *s = static_cast<state_xrgl *>(state);
1005
1006 delete s;
1007}
void ** state

References state.

◆ display_xrgl_get_property()

static bool display_xrgl_get_property ( void * state,
int property,
void * val,
size_t * len )
static

Definition at line 1065 of file openxr_gl.cpp.

1065 {
1066 auto s = static_cast<state_xrgl *>(state);
1067
1068 enum interlacing_t supported_il_modes[] = {PROGRESSIVE};
1069 int rgb_shift[] = {0, 8, 16};
1070
1071 switch (property) {
1073 auto codecs = s->scene.get_codecs();
1074 size_t codecs_size = codecs.size() * sizeof(codec_t);
1075 if(codecs_size <= *len) {
1076 memcpy(val, codecs.data(), codecs_size);
1077 } else {
1078 return false;
1079 }
1080
1081 *len = codecs_size;
1082 break;
1083 }
1085 if(sizeof(rgb_shift) > *len) {
1086 return false;
1087 }
1088 memcpy(val, rgb_shift, sizeof(rgb_shift));
1089 *len = sizeof(rgb_shift);
1090 break;
1092 *(int *) val = PITCH_DEFAULT;
1093 *len = sizeof(int);
1094 break;
1096 if(sizeof(supported_il_modes) <= *len) {
1097 memcpy(val, supported_il_modes, sizeof(supported_il_modes));
1098 } else {
1099 return false;
1100 }
1101 *len = sizeof(supported_il_modes);
1102 break;
1103 default:
1104 return false;
1105 }
1106 return true;
1107}
int void * val
int void size_t * len
int property
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
interlacing_t
Definition types.h:163
@ PROGRESSIVE
progressive frame
Definition types.h:164
codec_t
Definition types.h:65
static struct @76 codecs[]

References codecs, DISPLAY_PROPERTY_BUF_PITCH, DISPLAY_PROPERTY_CODECS, DISPLAY_PROPERTY_RGB_SHIFT, DISPLAY_PROPERTY_SUPPORTED_IL_MODES, len, PITCH_DEFAULT, PROGRESSIVE, property, state, and val.

◆ display_xrgl_getf()

static struct video_frame * display_xrgl_getf ( void * state)
static

Definition at line 1009 of file openxr_gl.cpp.

1009 {
1010 struct state_xrgl *s = static_cast<state_xrgl *>(state);
1011
1012 std::unique_lock<std::mutex> lock(s->lock);
1013
1014 while (true) {
1015 s->free_frame_ready_cv.wait(lock, [s]{return s->free_frame_pool.size() > 0;});
1016 struct video_frame *buffer = s->free_frame_pool.back();
1017 s->free_frame_pool.pop_back();
1019 return buffer;
1020 } else {
1021 s->dispose_frame_pool.push_back(buffer);
1022 s->new_frame_ready_cv.notify_one();
1023 }
1024 }
1025}
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
std::mutex lock
std::vector< video_frame * > free_frame_pool
std::condition_variable free_frame_ready_cv
std::vector< video_frame * > dispose_frame_pool
std::condition_variable new_frame_ready_cv
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.

References state_xrgl::current_desc, state_xrgl::dispose_frame_pool, state_xrgl::free_frame_pool, state_xrgl::free_frame_ready_cv, state_xrgl::lock, state_xrgl::new_frame_ready_cv, state, video_desc_eq(), and video_desc_from_frame().

Here is the call graph for this function:

◆ display_xrgl_init()

static void * display_xrgl_init ( struct module * parent,
const char * fmt,
unsigned int flags )
static

Definition at line 978 of file openxr_gl.cpp.

978 {
979 UNUSED(parent);
980 UNUSED(fmt);
981 UNUSED(flags);
982 state_xrgl *s = new state_xrgl();
983
984 XrSystemGetInfo system_get_info;
985 system_get_info.type = XR_TYPE_SYSTEM_GET_INFO;
986 system_get_info.next = nullptr;
987 system_get_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
988
989 XrResult result = xrGetSystem(s->xr_state.instance.get(),
990 &system_get_info,
991 &s->xr_state.system_id);
992
993 if(!XR_SUCCEEDED(result)){
994 throw std::runtime_error("No available device found!");
995 }
996
999
1000 return s;
1001}
#define UNUSED(x)
const char * fmt
const char unsigned int flags
XrInstance get()
#define MAX_BUFFER_SIZE
Definition openxr_gl.cpp:83
const char * parent
Definition settings.cpp:198
XrSystemId system_id
Openxr_instance instance
Openxr_state xr_state

References state_xrgl::dispose_frame_pool, flags, fmt, state_xrgl::free_frame_pool, Openxr_instance::get(), Openxr_state::instance, MAX_BUFFER_SIZE, parent, Openxr_state::system_id, UNUSED, and state_xrgl::xr_state.

Here is the call graph for this function:

◆ display_xrgl_probe()

static void display_xrgl_probe ( struct device_info ** available_cards,
int * count,
void(** deleter )(void *) )
static

Definition at line 1109 of file openxr_gl.cpp.

1109 {
1110 UNUSED(deleter);
1111 *count = 0;
1112 *available_cards = nullptr;
1113
1114 XrSystemGetInfo systemGetInfo;
1115 systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
1116 systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
1117 systemGetInfo.next = NULL;
1118
1119 XrSystemId systemId;
1120
1121 XrSystemProperties systemProperties;
1122 systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
1123 systemProperties.next = NULL;
1124 systemProperties.graphicsProperties = {};
1125 systemProperties.trackingProperties = {};
1126
1127 try{
1129
1130 XrResult result = xrGetSystem(instance.get(), &systemGetInfo, &systemId);
1131 if(!XR_SUCCEEDED(result)){
1132 return;
1133 }
1134
1135 result = xrGetSystemProperties(instance.get(), systemId, &systemProperties);
1136 if(!XR_SUCCEEDED(result)){
1137 return;
1138 }
1139 } catch(const std::exception& e){
1140 std::cout << e.what() << std::endl;
1141 return;
1142 }
1143
1144 *available_cards = (struct device_info *) calloc(1, sizeof(struct device_info));
1145 *count = 1;
1146 snprintf((*available_cards)[0].dev, sizeof((*available_cards)[0].dev), ":system=%lu", systemId);
1147 snprintf((*available_cards)[0].name, sizeof((*available_cards)[0].name), "OpenXr: %s", systemProperties.systemName);
1148 (*available_cards)[0].repeatable = false;
1149}
int void(** deleter)(void *))
int count
Definition hd-rum.c:44
const char * name
Definition settings.cpp:193
char dev[1024]
Definition types.h:383
static class worker_pool instance
Definition worker.cpp:250

References count, deleter, device_info::dev, instance, name, and UNUSED.

◆ display_xrgl_putf()

static bool display_xrgl_putf ( void * state,
struct video_frame * frame,
long long nonblock )
static

Definition at line 1027 of file openxr_gl.cpp.

1027 {
1028 struct state_xrgl *s = static_cast<state_xrgl *>(state);
1029
1030 std::unique_lock<std::mutex> lk(s->lock);
1031
1032 if(!frame) {
1033 s->frame_queue.push(frame);
1034 lk.unlock();
1035 s->new_frame_ready_cv.notify_one();
1036 return true;
1037 }
1038
1039 if (nonblock == PUTF_DISCARD) {
1040 s->dispose_frame_pool.push_back(frame);
1041 s->new_frame_ready_cv.notify_one();
1042 return true;
1043 }
1044 if (s->frame_queue.size() >= MAX_BUFFER_SIZE && nonblock != PUTF_BLOCKING) {
1045 s->dispose_frame_pool.push_back(frame);
1046 s->new_frame_ready_cv.notify_one();
1047 return false;
1048 }
1049 s->frame_consumed_cv.wait(lk, [s]{return s->frame_queue.size() < MAX_BUFFER_SIZE;});
1050 s->frame_queue.push(frame);
1051
1052 lk.unlock();
1053 s->new_frame_ready_cv.notify_one();
1054
1055 return true;
1056}
struct video_frame long long nonblock
struct video_frame * frame
#define PUTF_DISCARD
#define PUTF_BLOCKING
std::condition_variable frame_consumed_cv
std::queue< video_frame * > frame_queue

References state_xrgl::dispose_frame_pool, frame, state_xrgl::frame_consumed_cv, state_xrgl::frame_queue, state_xrgl::lock, MAX_BUFFER_SIZE, state_xrgl::new_frame_ready_cv, nonblock, PUTF_BLOCKING, PUTF_DISCARD, and state.

◆ display_xrgl_reconfigure()

static bool display_xrgl_reconfigure ( void * state,
struct video_desc desc )
static

Definition at line 1058 of file openxr_gl.cpp.

1058 {
1059 state_xrgl *s = static_cast<state_xrgl *>(state);
1060
1061 s->current_desc = desc;
1062 return true;
1063}
struct video_desc desc

References state_xrgl::current_desc, desc, and state.

◆ display_xrgl_run()

static void display_xrgl_run ( void * state)
static

Definition at line 609 of file openxr_gl.cpp.

609 {
611
612 state_xrgl *s = static_cast<state_xrgl *>(state);
613
614 //Make sure the worker context is initialized before starting worker
617
618 std::thread worker_thread(worker, s);
619
620#ifdef __linux__
621 XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl = {};
622 graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
623 graphics_binding_gl.xDisplay = nullptr;
624
625 s->window.getXlibHandles(&graphics_binding_gl.xDisplay,
626 &graphics_binding_gl.glxContext,
627 &graphics_binding_gl.glxDrawable);
628
629 Openxr_session session(s->xr_state.instance.get(),
631 &graphics_binding_gl);
632#elif defined _WIN32
633 XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl = {};
634 graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
635 graphics_binding_gl.next = nullptr;
636
638
639 graphics_binding_gl.hDC = wglGetCurrentDC();
640 graphics_binding_gl.hGLRC = wglGetCurrentContext();
641
642 Openxr_session session(s->xr_state.instance.get(),
644 &graphics_binding_gl);
645
646#else
647 //TODO: Implement GL OpenXR binding for other platforms
648 log_msg(LOG_LEVEL_ERROR, "OpenXR and OpenGL binding not implemented on this platform!\n");
649 return;
650#endif // defined __linux__
651
652 std::vector<XrViewConfigurationView> config_views = get_views(s->xr_state);
653
654 Openxr_local_space space(session.get());
655
656 session.begin();
657
658 std::vector<int64_t> swapchain_fmts = get_swapchain_formats(session.get());
659
660 int64_t selected_swapchain_fmt = select_swapchain_fmt(swapchain_fmts);
661
662 std::vector<Gl_interop_swapchain> swapchains;
663 for(const auto& view : config_views){
664 swapchains.emplace_back(session.get(),
665 selected_swapchain_fmt,
666 view.recommendedImageRectWidth,
667 view.recommendedImageRectHeight);
668 }
669
670 size_t view_count = config_views.size();
671 std::vector<XrCompositionLayerProjectionView> projection_views(view_count);
672
673
674 XrCompositionLayerProjection projection_layer;
675 projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
676 projection_layer.next = nullptr;
677 projection_layer.layerFlags = 0;
678 projection_layer.space = space.get();
679 projection_layer.viewCount = view_count;
680 projection_layer.views = projection_views.data();
681
682 std::vector<XrView> views(view_count);
683
684 for(auto& view : views){
685 view.type = XR_TYPE_VIEW;
686 view.next = nullptr;
687 }
688
689 for(unsigned i = 0; i < view_count; i++){
690 projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
691 projection_views[i].next = nullptr;
692 projection_views[i].subImage.swapchain = swapchains[i].get();
693 projection_views[i].subImage.imageArrayIndex = 0;
694 projection_views[i].subImage.imageRect.offset.x = 0;
695 projection_views[i].subImage.imageRect.offset.y = 0;
696 projection_views[i].subImage.imageRect.extent.width =
697 config_views[i].recommendedImageRectWidth;
698 projection_views[i].subImage.imageRect.extent.height =
699 config_views[i].recommendedImageRectHeight;
700
701 }
702
703 bool running = true;
704 if(selected_swapchain_fmt == GL_SRGB8_ALPHA8_EXT){
705 /* Convert to sRGB to correctly display on the HMD.
706 * This however breaks the preview window colors, because
707 * the framebuffer is directly copied into preview window
708 * using glBlitNamedFramebuffer
709 */
710 glEnable(GL_FRAMEBUFFER_SRGB);
711 }
712
713 glm::mat4 view_reset_rot = glm::mat4(1.0f);
714
715 while(running){
716 XrResult result;
717
718 XrFrameState frame_state{};
719 frame_state.type = XR_TYPE_FRAME_STATE;
720 frame_state.next = nullptr;
721
722 XrFrameWaitInfo frame_wait_info{};
723 frame_wait_info.type = XR_TYPE_FRAME_WAIT_INFO;
724 frame_wait_info.next = nullptr;
725
726 PROFILE_DETAIL("wait frame");
727 result = xrWaitFrame(session.get(), &frame_wait_info, &frame_state);
728 if (!XR_SUCCEEDED(result)){
729 log_msg(LOG_LEVEL_ERROR, "Failed to xrWaitFrame\n");
730 break;
731 }
732
733 bool reset_view = false;
734
735 SDL_Event event;
736 while(SDL_PollEvent(&event)){
737 switch(event.type){
738 case SDL_QUIT:
739 running = false;
740 break;
741 case SDL_WINDOWEVENT:
742 if(event.window.event == SDL_WINDOWEVENT_RESIZED){
743 s->window.width = event.window.data1;
744 s->window.height = event.window.data2;
745 }
746 break;
747 case SDL_KEYDOWN:
748 case SDL_KEYUP:
749 switch(event.key.keysym.sym){
750 case SDLK_q:
751 running = false;
752 break;
753 case SDLK_v:
754 if(event.type == SDL_KEYUP){
755 reset_view = true;
756 }
757 break;
758 }
759 break;
760 default:
761 break;
762 }
763 }
764
765 while(true){
766 XrEventDataBuffer xr_event{};
767 xr_event.type = XR_TYPE_EVENT_DATA_BUFFER;
768 xr_event.next = nullptr;
769
770 result = xrPollEvent(s->xr_state.instance.get(), &xr_event);
771 if(result != XR_SUCCESS){
772 break;
773 }
774
775 switch(xr_event.type){
776 case XR_TYPE_EVENT_DATA_EVENTS_LOST:
777 log_msg(LOG_LEVEL_WARNING, "OpenXR events lost!\n");
778 break;
779 case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
780 log_msg(LOG_LEVEL_WARNING, "OpenXR instance loss pending!\n");
781 running = false;
782 break;
783 case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
784 {
785 XrEventDataSessionStateChanged* event = (XrEventDataSessionStateChanged*) &xr_event;
786 if(event->state >= XR_SESSION_STATE_STOPPING){
787 log_msg(LOG_LEVEL_NOTICE, "Received event requesting stop\n");
788 running = false;
789 }
790 break;
791 }
792 default:
793 log_msg(LOG_LEVEL_NOTICE, "Unhandled event %d\n", xr_event.type);
794 break;
795 }
796
797 }
798
799 XrViewLocateInfo view_locate_info;
800 view_locate_info.type = XR_TYPE_VIEW_LOCATE_INFO;
801 view_locate_info.displayTime = frame_state.predictedDisplayTime;
802 view_locate_info.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; //Assuming stereo view exists. TODO: do it properly and enumerate types first
803 view_locate_info.space = space.get();
804
805 XrViewState view_state;
806 view_state.type = XR_TYPE_VIEW_STATE;
807 view_state.next = nullptr;
808
809 uint32_t located_views = 0;
810 result = xrLocateViews(session.get(),
811 &view_locate_info,
812 &view_state,
813 view_count,
814 &located_views,
815 views.data());
816
817 if (!XR_SUCCEEDED(result)){
818 log_msg(LOG_LEVEL_ERROR, "Failed to locate views!\n");
819 break;
820 }
821
822 /*
823 printf("View: %f %f %f %f, %f %f %f, fov = %f %f %f %f\n",
824 views[1].pose.orientation.x,
825 views[1].pose.orientation.y,
826 views[1].pose.orientation.z,
827 views[1].pose.orientation.w,
828 views[1].pose.position.x,
829 views[1].pose.position.y,
830 views[1].pose.position.z,
831 views[1].fov.angleLeft,
832 views[1].fov.angleRight,
833 views[1].fov.angleUp,
834 views[1].fov.angleDown);
835 */
836
837 XrFrameBeginInfo frame_begin_info;
838 frame_begin_info.type = XR_TYPE_FRAME_BEGIN_INFO;
839 frame_begin_info.next = nullptr;
840
841 PROFILE_DETAIL("begin frame");
842 result = xrBeginFrame(session.get(), &frame_begin_info);
843 if (!XR_SUCCEEDED(result)){
844 log_msg(LOG_LEVEL_ERROR, "Failed to begin frame!\n");
845 break;
846 }
847
848 for(unsigned i = 0; i < view_count; i++){
849 PROFILE_DETAIL("render view");
850
851 XrSwapchainImageAcquireInfo swapchain_image_acquire_info;
852 swapchain_image_acquire_info.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
853 swapchain_image_acquire_info.next = nullptr;
854
855 uint32_t buf_idx;
856 result = xrAcquireSwapchainImage(
857 swapchains[i].get(),
858 &swapchain_image_acquire_info,
859 &buf_idx);
860
861 if(!XR_SUCCEEDED(result)){
862 log_msg(LOG_LEVEL_ERROR, "Failed to acquire swapchain image!\n");
863 break;
864 }
865
866 XrSwapchainImageWaitInfo swapchain_image_wait_info;
867 swapchain_image_wait_info.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
868 swapchain_image_wait_info.next = nullptr;
869 swapchain_image_wait_info.timeout = 1000;
870
871 result = xrWaitSwapchainImage(swapchains[i].get(), &swapchain_image_wait_info);
872 if(!XR_SUCCEEDED(result)){
873 log_msg(LOG_LEVEL_ERROR, "failed to wait for swapchain image!\n");
874 break;
875 }
876
877 projection_views[i].pose = views[i].pose;
878 projection_views[i].fov = views[i].fov;
879 unsigned w = config_views[i].recommendedImageRectWidth;
880 unsigned h = config_views[i].recommendedImageRectHeight;
881
882 glm::mat4 projMat = get_proj_mat(views[i].fov, 0.05f, 100.f);
883 //glm::mat4 projMat = glm::perspective(glm::radians(70.f), (float) w /h, 0.1f, 300.f);
884 const auto& rot = views[i].pose.orientation;
885 glm::mat4 viewMat = glm::mat4_cast(glm::quat(rot.w, rot.x, rot.y, rot.z));
886 if(reset_view){
887 reset_view = false;
888 view_reset_rot = viewMat;
889 }
890 glm::mat4 pvMat = projMat * glm::inverse(viewMat) * view_reset_rot;
891
892 auto framebuffer = swapchains[i].get_framebuffer(buf_idx).get();
893 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
894 glClear(GL_COLOR_BUFFER_BIT);
895
896 s->scene.render(w, h, pvMat);
897
898 glBindFramebuffer(GL_FRAMEBUFFER, 0);
899
900 if(i % 2){
901 int dstX0;
902 int dstY0;
903 int dstX1;
904 int dstY1;
905 if(w * s->window.height > s->window.width * h){
906 dstX0 = 0;
907 dstX1 = s->window.width;
908
909 int height = (s->window.width * h) / w;
910 dstY0 = (s->window.height - height) / 2;
911 dstY1 = dstY0 + height;
912 } else {
913 int width = (s->window.height * w) / h;
914 dstX0 = (s->window.width - width) / 2;
915 dstX1 = dstX0 + width;
916
917 dstY0 = 0;
918 dstY1 = s->window.height;
919
920 }
921 glClear(GL_COLOR_BUFFER_BIT);
922 glBlitNamedFramebuffer((GLuint)framebuffer, // readFramebuffer
923 (GLuint)0, // backbuffer // drawFramebuffer
924 (GLint)0, // srcX0
925 (GLint)0, // srcY0
926 (GLint)w, // srcX1
927 (GLint)h, // srcY1
928 (GLint)dstX0, // dstX0
929 (GLint)dstY0, // dstY0
930 (GLint)dstX1, // dstX1
931 (GLint)dstY1, // dstY1
932 (GLbitfield)GL_COLOR_BUFFER_BIT, // mask
933 (GLenum)GL_LINEAR); // filter
934
935 SDL_GL_SwapWindow(s->window.sdl_window);
936 }
937
938 PROFILE_DETAIL("glFinish");
939 glFinish();
940
941 PROFILE_DETAIL("release swapchain");
942 XrSwapchainImageReleaseInfo swapchain_image_release_info;
943 swapchain_image_release_info.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
944 swapchain_image_release_info.next = nullptr;
945
946 result = xrReleaseSwapchainImage(
947 swapchains[i].get(),
948 &swapchain_image_release_info);
949
950 if (!XR_SUCCEEDED(result)){
951 log_msg(LOG_LEVEL_ERROR, "Failed to release swapchain image!\n");
952 break;
953 }
954 }
955
956 const XrCompositionLayerBaseHeader *composition_layers = (const XrCompositionLayerBaseHeader *) &projection_layer;
957 XrFrameEndInfo frame_end_info;
958 frame_end_info.type = XR_TYPE_FRAME_END_INFO;
959 frame_end_info.displayTime = frame_state.predictedDisplayTime;
960 frame_end_info.layerCount = 1;
961 frame_end_info.layers = &composition_layers;
962 frame_end_info.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
963 frame_end_info.next = nullptr;
964
965 PROFILE_DETAIL("End Frame");
966 result = xrEndFrame(session.get(), &frame_end_info);
967 if (!XR_SUCCEEDED(result)){
968 log_msg(LOG_LEVEL_ERROR, "Failed to end frame!\n");
969 break;
970 }
971
972 }
973
974 exit_uv(0);
975 worker_thread.join();
976}
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
static void * worker_thread(void *arg)
void exit_uv(int status)
Definition host.cpp:625
static int64_t select_swapchain_fmt(const std::vector< int64_t > &swapchain_formats)
static void worker(state_xrgl *s)
static glm::mat4 get_proj_mat(const XrFovf &fov, float zNear, float zFar)
static std::vector< XrViewConfigurationView > get_views(Openxr_state &xr_state)
static std::vector< int64_t > get_swapchain_formats(XrSession session)
#define PROFILE_FUNC
#define PROFILE_DETAIL(name)
void render(int width, int height)
void make_render_context_current()
void make_worker_context_current()
SDL_Window * sdl_window
PanoramaScene scene
Sdl_window window

References Openxr_session::begin(), exit_uv(), Openxr_instance::get(), Openxr_local_space::get(), Openxr_session::get(), get_proj_mat(), get_swapchain_formats(), get_views(), Sdl_window::height, Openxr_state::instance, LOG_LEVEL_ERROR, LOG_LEVEL_NOTICE, LOG_LEVEL_WARNING, log_msg(), Sdl_window::make_render_context_current(), Sdl_window::make_worker_context_current(), PROFILE_DETAIL, PROFILE_FUNC, PanoramaScene::render(), state_xrgl::scene, Sdl_window::sdl_window, select_swapchain_fmt(), state, Openxr_state::system_id, Sdl_window::width, state_xrgl::window, worker(), worker_thread(), and state_xrgl::xr_state.

Here is the call graph for this function:

◆ get_proj_mat()

static glm::mat4 get_proj_mat ( const XrFovf & fov,
float zNear,
float zFar )
static

Definition at line 465 of file openxr_gl.cpp.

465 {
466 glm::mat4 res{};
467
468 float tanLeft = glm::tan(fov.angleLeft);
469 float tanRight = glm::tan(fov.angleRight);
470 float tanUp = glm::tan(fov.angleUp);
471 float tanDown = glm::tan(fov.angleDown);
472
473 res[0][0] = 2.f / (tanRight - tanLeft);
474 res[1][1] = 2.f / (tanUp - tanDown);
475 res[2][0] = (tanRight + tanLeft) / (tanRight - tanLeft);
476 res[2][1] = (tanUp + tanDown) / (tanUp - tanDown);
477 res[2][2] = -(zFar + zNear) / (zFar - zNear);
478 res[2][3] = -1;
479 res[3][2] = -(2.f * zFar * zNear) / (zFar - zNear);
480
481 return res;
482}

Referenced by display_xrgl_run().

◆ get_swapchain_formats()

static std::vector< int64_t > get_swapchain_formats ( XrSession session)
static

Definition at line 443 of file openxr_gl.cpp.

443 {
444 XrResult result;
445 unsigned swapchain_format_count;
446 result = xrEnumerateSwapchainFormats(session,
447 0,
448 &swapchain_format_count,
449 nullptr);
450
451 printf("Runtime supports %d swapchain formats\n", swapchain_format_count);
452 std::vector<int64_t> swapchain_formats(swapchain_format_count);
453 result = xrEnumerateSwapchainFormats(session,
454 swapchain_format_count,
455 &swapchain_format_count,
456 swapchain_formats.data());
457
458 if(!XR_SUCCEEDED(result)){
459 throw std::runtime_error("Failed to enumerate swapchain formats!");
460 }
461
462 return swapchain_formats;
463}

Referenced by display_xrgl_run().

◆ get_views()

static std::vector< XrViewConfigurationView > get_views ( Openxr_state & xr_state)
static

Definition at line 413 of file openxr_gl.cpp.

413 {
414 unsigned view_count;
415 XrResult result = xrEnumerateViewConfigurationViews(xr_state.instance.get(),
416 xr_state.system_id,
417 XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
418 0,
419 &view_count,
420 nullptr);
421
422 if(!XR_SUCCEEDED(result)){
423 throw std::runtime_error("Failed to enumerate view configuration views!");
424 }
425
426 std::vector<XrViewConfigurationView> config_views(view_count);
427 for(auto& view : config_views) view.type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
428
429 result = xrEnumerateViewConfigurationViews(xr_state.instance.get(),
430 xr_state.system_id,
431 XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
432 view_count,
433 &view_count,
434 config_views.data());
435
436 if(!XR_SUCCEEDED(result)){
437 throw std::runtime_error("Failed to enumerate view configuration views!");
438 }
439
440 return config_views;
441}

References Openxr_instance::get(), Openxr_state::instance, and Openxr_state::system_id.

Referenced by display_xrgl_run().

Here is the call graph for this function:

◆ map_new_buffer()

static void map_new_buffer ( struct video_frame * f)
static

Definition at line 501 of file openxr_gl.cpp.

501 {
502 glBufferData(GL_PIXEL_UNPACK_BUFFER, f->tiles[0].data_len, 0, GL_STREAM_DRAW);
503 f->tiles[0].data = (char *) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
504 GLenum ret = glGetError();
505 if(ret != GL_NO_ERROR){
506 std::cerr << "Error mapping: " << ret << std::endl;
507 }
508 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
509}
unsigned int data_len
length of the data
Definition types.h:288

References tile::data, tile::data_len, and video_frame::tiles.

Referenced by allocate_frame(), and recycle_frame().

◆ recycle_frame()

static void recycle_frame ( video_frame * f)
static

Definition at line 511 of file openxr_gl.cpp.

511 {
512 GlBuffer *pbo = static_cast<GlBuffer *>(f->callbacks.dispose_udata);
513 if(!pbo){
514 return;
515 }
516 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->get());
517 if(f->tiles[0].data){
518 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
519 }
521}

References video_frame::callbacks, tile::data, video_frame_callbacks::dispose_udata, GlBuffer::get(), map_new_buffer(), and video_frame::tiles.

Referenced by worker().

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( openxr_gl ,
& openxr_gl_info,
LIBRARY_CLASS_VIDEO_DISPLAY ,
VIDEO_DISPLAY_ABI_VERSION  )

◆ select_swapchain_fmt()

static int64_t select_swapchain_fmt ( const std::vector< int64_t > & swapchain_formats)
static

Definition at line 484 of file openxr_gl.cpp.

484 {
485 const int64_t preferred_formats[] = {
486 GL_RGBA8_EXT,
487 GL_SRGB8_ALPHA8_EXT
488 };
489
490 for(auto pref : preferred_formats){
491 for(auto supported_fmt : swapchain_formats){
492 if(pref == supported_fmt){
493 return pref;
494 }
495 }
496 }
497
498 return 0;
499}

Referenced by display_xrgl_run().

◆ worker()

static void worker ( state_xrgl * s)
static

Definition at line 550 of file openxr_gl.cpp.

550 {
553 std::unique_lock<std::mutex> lk(s->lock);
554 for(size_t i = 0; i < MAX_BUFFER_SIZE; i++){
555 video_frame *buf = vf_alloc(1);
556 GlBuffer *pbo = new GlBuffer();
557 buf->callbacks.dispose_udata = pbo;
558 s->free_frame_pool.push_back(buf);
559 }
560 lk.unlock();
561 s->free_frame_ready_cv.notify_all();
562
563 bool running = true;
564 lk.lock();
565 while(running){
566 PROFILE_DETAIL("Wait for frame");
567 s->new_frame_ready_cv.wait(lk,
568 [s]{
569 return !s->frame_queue.empty() || !s->dispose_frame_pool.empty();
570 });
571 if(!s->dispose_frame_pool.empty()){
572 PROFILE_DETAIL("Process disposed frames");
573 for(video_frame *f : s->dispose_frame_pool){
575 recycle_frame(f);
576 s->free_frame_pool.push_back(f);
577 } else {
578 delete_frame(f);
579
580 struct video_frame *buffer = allocate_frame(s);
581 s->free_frame_pool.push_back(buffer);
582 }
583 }
584 s->dispose_frame_pool.clear();
585 s->free_frame_ready_cv.notify_all();
586 }
587
588 if(!s->frame_queue.empty()){
589 PROFILE_DETAIL("put_frame");
590 video_frame *frame = s->frame_queue.front();
591 s->frame_queue.pop();
592 lk.unlock();
593 if(!frame){
594 SDL_Event event;
595 event.type = SDL_QUIT;
596 SDL_PushEvent(&event);
597 running = false;
598 } else {
599 s->frame_consumed_cv.notify_one();
601
602 lk.lock();
603 s->dispose_frame_pool.push_back(frame);
604 }
605 }
606 }
607}
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
static void recycle_frame(video_frame *f)
static video_frame * allocate_frame(state_xrgl *s)
static void delete_frame(video_frame *f)
void put_frame(video_frame *f, bool pbo_frame=false)

References allocate_frame(), video_frame::callbacks, state_xrgl::current_desc, delete_frame(), state_xrgl::dispose_frame_pool, video_frame_callbacks::dispose_udata, frame, state_xrgl::frame_consumed_cv, state_xrgl::frame_queue, state_xrgl::free_frame_pool, state_xrgl::free_frame_ready_cv, state_xrgl::lock, Sdl_window::make_worker_context_current(), MAX_BUFFER_SIZE, state_xrgl::new_frame_ready_cv, PROFILE_DETAIL, PROFILE_FUNC, PanoramaScene::put_frame(), recycle_frame(), state_xrgl::scene, vf_alloc(), video_desc_eq(), video_desc_from_frame(), and state_xrgl::window.

Referenced by display_xrgl_run().

Here is the call graph for this function:

Variable Documentation

◆ openxr_gl_info

const struct video_display_info openxr_gl_info
static
Initial value:
= {
NULL,
NULL,
}
#define DISPLAY_NO_GENERIC_FPS_INDICATOR
static void display_xrgl_done(void *state)
static struct video_frame * display_xrgl_getf(void *state)
static void display_xrgl_run(void *state)
static bool display_xrgl_get_property(void *state, int property, void *val, size_t *len)
static bool display_xrgl_reconfigure(void *state, struct video_desc desc)
static void * display_xrgl_init(struct module *parent, const char *fmt, unsigned int flags)
static void display_xrgl_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static bool display_xrgl_putf(void *state, struct video_frame *frame, long long nonblock)

Definition at line 1152 of file openxr_gl.cpp.