| @@ -14,7 +14,7 @@ add_compile_definitions( | |||||||
| 	XR_USE_GRAPHICS_API_OPENGL_ES | 	XR_USE_GRAPHICS_API_OPENGL_ES | ||||||
| ) | ) | ||||||
|  |  | ||||||
| find_package(PkgConfig) | find_package(PkgConfig REQUIRED) | ||||||
|  |  | ||||||
| pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET GLOBAL wayland-server) | pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET GLOBAL wayland-server) | ||||||
| pkg_check_modules(EGL REQUIRED IMPORTED_TARGET egl) | pkg_check_modules(EGL REQUIRED IMPORTED_TARGET egl) | ||||||
| @@ -22,6 +22,19 @@ pkg_check_modules(GLES2 REQUIRED IMPORTED_TARGET glesv2) | |||||||
| pkg_check_modules(WLROOTS REQUIRED IMPORTED_TARGET wlroots-0.19) | pkg_check_modules(WLROOTS REQUIRED IMPORTED_TARGET wlroots-0.19) | ||||||
| pkg_check_modules(OPENXR REQUIRED IMPORTED_TARGET openxr) | pkg_check_modules(OPENXR REQUIRED IMPORTED_TARGET openxr) | ||||||
|  |  | ||||||
|  | include(FetchContent) | ||||||
|  |  | ||||||
|  | FetchContent_Declare( | ||||||
|  | 	raylib | ||||||
|  | 	GIT_REPOSITORY https://github.com/slendidev/raylib.git | ||||||
|  | 	GIT_TAG "lunar" | ||||||
|  | 	GIT_SHALLOW 1 | ||||||
|  | ) | ||||||
|  | set(OPENGL_VERSION "ES 3.0") | ||||||
|  | set(PLATFORM DRM) | ||||||
|  | set(BUILD_EXAMPLES OFF) | ||||||
|  | FetchContent_MakeAvailable(raylib) | ||||||
|  |  | ||||||
| add_executable(${PROJECT_NAME}) | add_executable(${PROJECT_NAME}) | ||||||
| target_sources(${PROJECT_NAME} PUBLIC | target_sources(${PROJECT_NAME} PUBLIC | ||||||
| 	src/main.cpp | 	src/main.cpp | ||||||
| @@ -37,5 +50,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC | |||||||
| 	PkgConfig::GLES2 | 	PkgConfig::GLES2 | ||||||
| 	PkgConfig::WLROOTS | 	PkgConfig::WLROOTS | ||||||
| 	PkgConfig::OPENXR | 	PkgConfig::OPENXR | ||||||
|  | 	raylib | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -49,6 +49,13 @@ | |||||||
|             wlroots |             wlroots | ||||||
|             vulkan-loader |             vulkan-loader | ||||||
|  |  | ||||||
|  |             # For raylib | ||||||
|  |             xorg.libXrandr | ||||||
|  |             xorg.libXinerama | ||||||
|  |             xorg.libXcursor | ||||||
|  |             xorg.libXi | ||||||
|  |             glfw | ||||||
|  |  | ||||||
|             libffi |             libffi | ||||||
|             wayland |             wayland | ||||||
|             wayland-scanner |             wayland-scanner | ||||||
|   | |||||||
							
								
								
									
										572
									
								
								src/LunarWM.cppm
									
									
									
									
									
								
							
							
						
						
									
										572
									
								
								src/LunarWM.cppm
									
									
									
									
									
								
							| @@ -25,12 +25,20 @@ extern "C" { | |||||||
| #include <wlr/util/log.h> | #include <wlr/util/log.h> | ||||||
| } | } | ||||||
|  |  | ||||||
|  | PFNGLDRAWBUFFERSEXTPROC glDrawBuffersEXT = NULL; | ||||||
|  |  | ||||||
|  | #include <raylib.h> | ||||||
|  | #include <raymath.h> | ||||||
|  | #include <rlgl.h> | ||||||
|  |  | ||||||
| export module LunarWM.LunarWM; | export module LunarWM.LunarWM; | ||||||
|  |  | ||||||
| import std; | import std; | ||||||
|  |  | ||||||
| import LunarWM.Math; | import LunarWM.Math; | ||||||
|  |  | ||||||
|  | using Clock = std::chrono::high_resolution_clock; | ||||||
|  |  | ||||||
| namespace std { | namespace std { | ||||||
| template <> struct formatter<XrResult, char> { | template <> struct formatter<XrResult, char> { | ||||||
|   template <class ParseContext> constexpr auto parse(ParseContext &ctx) { |   template <class ParseContext> constexpr auto parse(ParseContext &ctx) { | ||||||
| @@ -39,7 +47,8 @@ template <> struct formatter<XrResult, char> { | |||||||
|  |  | ||||||
|   static constexpr std::string_view to_string(XrResult r) { |   static constexpr std::string_view to_string(XrResult r) { | ||||||
|     switch (r) { |     switch (r) { | ||||||
| 		case XR_FRAME_DISCARDED: return "XR_FRAME_DISCARDED"; |     case XR_FRAME_DISCARDED: | ||||||
|  |       return "XR_FRAME_DISCARDED"; | ||||||
|     case XR_ERROR_VALIDATION_FAILURE: |     case XR_ERROR_VALIDATION_FAILURE: | ||||||
|       return "XR_ERROR_VALIDATION_FAILURE: The function usage was invalid in " |       return "XR_ERROR_VALIDATION_FAILURE: The function usage was invalid in " | ||||||
|              "some way."; |              "some way."; | ||||||
| @@ -539,11 +548,65 @@ private: | |||||||
|  |  | ||||||
| namespace LunarWM { | namespace LunarWM { | ||||||
|  |  | ||||||
|  | static Matrix xr_projection_matrix(const XrFovf& fov) | ||||||
|  | { | ||||||
|  | 	static_assert(RL_CULL_DISTANCE_FAR > RL_CULL_DISTANCE_NEAR); | ||||||
|  |  | ||||||
|  | 	Matrix matrix{}; | ||||||
|  |  | ||||||
|  | 	const float near = (float)RL_CULL_DISTANCE_NEAR; | ||||||
|  | 	const float far = (float)RL_CULL_DISTANCE_FAR; | ||||||
|  |  | ||||||
|  | 	const float tan_angle_left = tanf(fov.angleLeft); | ||||||
|  | 	const float tan_angle_right = tanf(fov.angleRight); | ||||||
|  |  | ||||||
|  | 	const float tan_angle_down = tanf(fov.angleDown); | ||||||
|  | 	const float tan_angle_up = tanf(fov.angleUp); | ||||||
|  |  | ||||||
|  | 	const float tan_angle_width = tan_angle_right - tan_angle_left; | ||||||
|  | 	const float tan_angle_height = tan_angle_up - tan_angle_down; | ||||||
|  |  | ||||||
|  | 	matrix.m0 = 2 / tan_angle_width; | ||||||
|  | 	matrix.m4 = 0; | ||||||
|  | 	matrix.m8 = (tan_angle_right + tan_angle_left) / tan_angle_width; | ||||||
|  | 	matrix.m12 = 0; | ||||||
|  |  | ||||||
|  | 	matrix.m1 = 0; | ||||||
|  | 	matrix.m5 = 2 / tan_angle_height; | ||||||
|  | 	matrix.m9 = (tan_angle_up + tan_angle_down) / tan_angle_height; | ||||||
|  | 	matrix.m13 = 0; | ||||||
|  |  | ||||||
|  | 	matrix.m2 = 0; | ||||||
|  | 	matrix.m6 = 0; | ||||||
|  | 	matrix.m10 = -(far + near) / (far - near); | ||||||
|  | 	matrix.m14 = -(far * (near + near)) / (far - near); | ||||||
|  |  | ||||||
|  | 	matrix.m3 = 0; | ||||||
|  | 	matrix.m7 = 0; | ||||||
|  | 	matrix.m11 = -1; | ||||||
|  | 	matrix.m15 = 0; | ||||||
|  |  | ||||||
|  | 	return matrix; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static Matrix xr_matrix(const XrPosef& pose) | ||||||
|  | { | ||||||
|  | 	Matrix translation = MatrixTranslate(pose.position.x, pose.position.y, pose.position.z); | ||||||
|  | 	Matrix rotation = QuaternionToMatrix(Quaternion{pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w}); | ||||||
|  | 	return rotation * translation; | ||||||
|  | } | ||||||
|  |  | ||||||
| enum class SwapchainType { | enum class SwapchainType { | ||||||
|   Color, |   Color, | ||||||
|   Depth, |   Depth, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct SwapchainInfo { | ||||||
|  |   XrSwapchain swapchain{XR_NULL_HANDLE}; | ||||||
|  |   std::int64_t swapchain_format{}; | ||||||
|  |   std::vector<GLuint> image_views; | ||||||
|  | }; | ||||||
|  |  | ||||||
| export struct LunarWM { | export struct LunarWM { | ||||||
|   LunarWM() = default; |   LunarWM() = default; | ||||||
|   ~LunarWM(); |   ~LunarWM(); | ||||||
| @@ -560,7 +623,8 @@ private: | |||||||
|   void init_xr(); |   void init_xr(); | ||||||
|  |  | ||||||
|   void poll_events_xr(); |   void poll_events_xr(); | ||||||
|   bool render_layer(RenderLayerInfo &info); |   bool render_layer(RenderLayerInfo &info, float dt); | ||||||
|  | 	void render_3d(float dt); | ||||||
|  |  | ||||||
|   bool m_initialized{}; |   bool m_initialized{}; | ||||||
|  |  | ||||||
| @@ -587,12 +651,6 @@ private: | |||||||
|   } m_wayland; |   } m_wayland; | ||||||
|  |  | ||||||
|   struct { |   struct { | ||||||
|     struct SwapchainInfo { |  | ||||||
|       XrSwapchain swapchain{XR_NULL_HANDLE}; |  | ||||||
|       std::int64_t swapchain_format{}; |  | ||||||
|       std::vector<GLuint> image_views; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     std::optional<XrInstance> instance; |     std::optional<XrInstance> instance; | ||||||
|     std::optional<XrSystemId> system_id; |     std::optional<XrSystemId> system_id; | ||||||
|     XrSession session{XR_NULL_HANDLE}; |     XrSession session{XR_NULL_HANDLE}; | ||||||
| @@ -607,52 +665,97 @@ private: | |||||||
|         std::pair<SwapchainType, std::vector<XrSwapchainImageOpenGLESKHR>>> |         std::pair<SwapchainType, std::vector<XrSwapchainImageOpenGLESKHR>>> | ||||||
|         swapchain_images_map; |         swapchain_images_map; | ||||||
|  |  | ||||||
| 		std::vector<XrViewConfigurationView> view_configuration_views; |     std::vector<XrViewConfigurationView> view_configuration_views; | ||||||
| 		XrEnvironmentBlendMode environment_blend_mode; |     XrEnvironmentBlendMode environment_blend_mode; | ||||||
|  |  | ||||||
|     XrSpace local_space{XR_NULL_HANDLE}; |     XrSpace local_space{XR_NULL_HANDLE}; | ||||||
|  |     XrSpace view_space{XR_NULL_HANDLE}; | ||||||
|  |  | ||||||
|     std::uint32_t get_swapchain_image(XrSwapchain swapchain, uint32_t index) { |     std::uint32_t get_swapchain_image(XrSwapchain swapchain, uint32_t index) { | ||||||
|       return swapchain_images_map[swapchain].second[index].image; |       return swapchain_images_map[swapchain].second[index].image; | ||||||
|     } |     } | ||||||
|   } m_xr; |   } m_xr; | ||||||
|  |  | ||||||
| 	struct { |   struct RendererFrame { | ||||||
| 		GLuint vertex_array{}; |     GLuint fbo{0}; | ||||||
| 		GLuint set_framebuffer{}; |     uint32_t color_idx{UINT32_MAX}; | ||||||
|  |     uint32_t depth_idx{UINT32_MAX}; | ||||||
|  |     bool has_depth{}; | ||||||
|  |   }; | ||||||
|  |  | ||||||
| 		void begin_rendering() { |   struct { | ||||||
| 			glGenVertexArrays(1, &vertex_array); |     GLuint fbo{}; | ||||||
| 			glBindVertexArray(vertex_array); |     RenderTexture2D tmp_rt{}; | ||||||
|  |  | ||||||
| 			glGenFramebuffers(1, &set_framebuffer); | 		Camera3D camera{ | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, set_framebuffer); | 			.position = { 0, 0, 0 }, | ||||||
|  | 			.target = { 0, 0, 1 }, | ||||||
|  | 			.up = { 0, 1, 0 }, | ||||||
|  | 			.fovy = 45, | ||||||
|  | 			.projection = CAMERA_PERSPECTIVE, | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		bool begin_render(GLuint color_tex, GLuint depth_tex, uint32_t w, uint32_t h, const XrView& view) { | ||||||
|  |       if (!fbo) // create once | ||||||
|  |         glGenFramebuffers(1, &fbo); | ||||||
|  |  | ||||||
|  |       rlFramebufferAttach(fbo, color_tex, RL_ATTACHMENT_COLOR_CHANNEL0, | ||||||
|  |                           RL_ATTACHMENT_TEXTURE2D, 0); | ||||||
|  |  | ||||||
|  |       assert(rlFramebufferComplete(fbo)); | ||||||
|  | 			glBindFramebuffer(GL_FRAMEBUFFER, fbo); | ||||||
|  | 			GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); | ||||||
|  | 			if(fbStatus != GL_FRAMEBUFFER_COMPLETE){ | ||||||
|  | 				printf("FBO incomplete: 0x%04x\n", fbStatus); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  |       tmp_rt = {.id = fbo, | ||||||
|  |                 .texture = {color_tex, (int)w, (int)h, 1, -1}, | ||||||
|  |                 .depth = {depth_tex, (int)w, (int)h, 1, -1}}; | ||||||
|  |  | ||||||
|  |       BeginTextureMode(tmp_rt); | ||||||
|  |       rlEnableStereoRender(); | ||||||
|  |  | ||||||
|  |       const XrFovf &fov = view.fov; | ||||||
|  |       Matrix proj = xr_projection_matrix(fov); | ||||||
|  |       Matrix viewM = MatrixInvert(xr_matrix(view.pose)); | ||||||
|  |  | ||||||
|  |       rlSetMatrixProjectionStereo(proj, proj); | ||||||
|  |       rlSetMatrixViewOffsetStereo(viewM, viewM); | ||||||
|  |  | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void end_render(LunarWM &wm, SwapchainInfo &color_sc, | ||||||
|  |                     SwapchainInfo *depth_sc) { | ||||||
|  |       rlDisableStereoRender(); | ||||||
|  |       EndTextureMode(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 		void update_camera(LunarWM &wm, Camera3D &camera, RenderLayerInfo &info) | ||||||
|  | 		{ | ||||||
|  | 			const XrTime time = info.predicted_display_time; | ||||||
|  |  | ||||||
|  | 			XrSpaceLocation view_location{ XR_TYPE_SPACE_LOCATION }; | ||||||
|  | 			XrResult result = xrLocateSpace(wm.m_xr.view_space, wm.m_xr.local_space, time, &view_location); | ||||||
|  | 			if (result != XR_SUCCESS) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (view_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { | ||||||
|  | 				const auto& pos = view_location.pose.position; | ||||||
|  | 				camera.position = Vector3{ pos.x, pos.y, pos.z }; | ||||||
|  | 			} | ||||||
|  | 			if (view_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { | ||||||
|  | 				const auto& rot = view_location.pose.orientation; | ||||||
|  | 				const auto forward = Vector3RotateByQuaternion(Vector3{ 0, 0, -1 }, Quaternion{ rot.x, rot.y, rot.z, rot.w }); | ||||||
|  | 				const auto up = Vector3RotateByQuaternion(Vector3{ 0, 1, 0 }, Quaternion{ rot.x, rot.y, rot.z, rot.w }); | ||||||
|  | 				camera.target = camera.position + forward; | ||||||
|  | 				camera.up = up; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |   } m_renderer; | ||||||
| 		void end_rendering() { |  | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, 0); |  | ||||||
| 			glDeleteFramebuffers(1, &set_framebuffer); |  | ||||||
| 			set_framebuffer = 0; |  | ||||||
|  |  | ||||||
| 			glBindVertexArray(0); |  | ||||||
| 			glDeleteVertexArrays(1, &vertex_array); |  | ||||||
| 			vertex_array = 0; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		void clear_color(GLuint image_view, float r, float g, float b, float a) { |  | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)(uint64_t)image_view); |  | ||||||
| 			glClearColor(r, g, b, a); |  | ||||||
| 			glClear(GL_COLOR_BUFFER_BIT); |  | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, 0); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		void clear_depth(GLuint image_view, float d) { |  | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)(uint64_t)image_view); |  | ||||||
| 			glClearDepthf(d); |  | ||||||
| 			glClear(GL_DEPTH_BUFFER_BIT); |  | ||||||
| 			glBindFramebuffer(GL_FRAMEBUFFER, 0); |  | ||||||
| 		} |  | ||||||
| 	} m_renderer; |  | ||||||
|  |  | ||||||
|   struct RenderLayerInfo { |   struct RenderLayerInfo { | ||||||
|     XrTime predicted_display_time; |     XrTime predicted_display_time; | ||||||
| @@ -664,6 +767,8 @@ private: | |||||||
|     std::vector<XrCompositionLayerProjectionView> layer_projection_views; |     std::vector<XrCompositionLayerProjectionView> layer_projection_views; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | 	std::chrono::time_point<Clock> m_last_tick; | ||||||
|  |  | ||||||
|   bool m_running{}; |   bool m_running{}; | ||||||
|   bool m_session_running{}; |   bool m_session_running{}; | ||||||
|   bool m_session_state{}; |   bool m_session_state{}; | ||||||
| @@ -671,14 +776,28 @@ private: | |||||||
|  |  | ||||||
| void LunarWM::init() { | void LunarWM::init() { | ||||||
|   this->init_wayland(); |   this->init_wayland(); | ||||||
|   if (eglMakeCurrent(m_wayland.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, |  | ||||||
|  | 	wlr_log(WLR_INFO, "0"); | ||||||
|  | 	auto draw = eglGetCurrentSurface(EGL_DRAW); | ||||||
|  | 	auto read = eglGetCurrentSurface(EGL_READ); | ||||||
|  | 	if (eglMakeCurrent(m_wayland.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, | ||||||
|  | 										 m_wayland.egl_context) == EGL_FALSE) { | ||||||
|  | 		throw std::runtime_error("Failed to eglMakeCurrent"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	wlr_log(WLR_INFO, "1"); | ||||||
|  |   this->init_xr(); | ||||||
|  | 	wlr_log(WLR_INFO, "2"); | ||||||
|  |  | ||||||
|  |   wlr_log(WLR_INFO, "OpenGL ES version: %s", glGetString(GL_VERSION)); | ||||||
|  | 	InitWindow(0, 0, ""); | ||||||
|  | 	wlr_log(WLR_INFO, "3"); | ||||||
|  |  | ||||||
|  |   if (eglMakeCurrent(m_wayland.egl_display, read, draw, | ||||||
|                      m_wayland.egl_context) == EGL_FALSE) { |                      m_wayland.egl_context) == EGL_FALSE) { | ||||||
|     throw std::runtime_error("Failed to eglMakeCurrent"); |     throw std::runtime_error("Failed to eglMakeCurrent"); | ||||||
|   } |   } | ||||||
|   this->init_xr(); | 	wlr_log(WLR_INFO, "4"); | ||||||
|  |  | ||||||
|   wlr_log(WLR_INFO, "OpenGL ES version: %s", glGetString(GL_VERSION)); |  | ||||||
|  |  | ||||||
|   m_initialized = true; |   m_initialized = true; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -915,6 +1034,7 @@ void LunarWM::init_xr() { | |||||||
|   glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); |   glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); | ||||||
|  |  | ||||||
|   { |   { | ||||||
|  |     glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC) eglGetProcAddress("glDrawBuffersEXT"); | ||||||
|     XrGraphicsBindingEGLMNDX gbind = { |     XrGraphicsBindingEGLMNDX gbind = { | ||||||
|         .type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, |         .type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, | ||||||
|         .next = nullptr, |         .next = nullptr, | ||||||
| @@ -969,7 +1089,8 @@ void LunarWM::init_xr() { | |||||||
|       throw std::runtime_error( |       throw std::runtime_error( | ||||||
|           "Failed to get amount of OpenXR view configuration views"); |           "Failed to get amount of OpenXR view configuration views"); | ||||||
|     } |     } | ||||||
|     m_xr.view_configuration_views.resize(count, {XR_TYPE_VIEW_CONFIGURATION_VIEW}); |     m_xr.view_configuration_views.resize(count, | ||||||
|  |                                          {XR_TYPE_VIEW_CONFIGURATION_VIEW}); | ||||||
|     if (xrEnumerateViewConfigurationViews( |     if (xrEnumerateViewConfigurationViews( | ||||||
|             *m_xr.instance, *m_xr.system_id, |             *m_xr.instance, *m_xr.system_id, | ||||||
|             XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, count, &count, |             XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, count, &count, | ||||||
| @@ -995,9 +1116,9 @@ void LunarWM::init_xr() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   std::vector<std::int64_t> swapchain_format_depth_needles{ |   std::vector<std::int64_t> swapchain_format_depth_needles{ | ||||||
|       GL_DEPTH_COMPONENT32F, |  | ||||||
|       GL_DEPTH_COMPONENT24, |  | ||||||
|       GL_DEPTH_COMPONENT16, |       GL_DEPTH_COMPONENT16, | ||||||
|  |       // GL_DEPTH_COMPONENT32F, | ||||||
|  |       // GL_DEPTH_COMPONENT24, | ||||||
|   }; |   }; | ||||||
|   const std::vector<int64_t>::const_iterator &swapchain_format_depth_it = |   const std::vector<int64_t>::const_iterator &swapchain_format_depth_it = | ||||||
|       std::find_first_of(swapchain_formats.begin(), swapchain_formats.end(), |       std::find_first_of(swapchain_formats.begin(), swapchain_formats.end(), | ||||||
| @@ -1009,8 +1130,7 @@ void LunarWM::init_xr() { | |||||||
|   } |   } | ||||||
|   auto const swapchain_format_depth = *swapchain_format_depth_it; |   auto const swapchain_format_depth = *swapchain_format_depth_it; | ||||||
|  |  | ||||||
|   std::vector<std::int64_t> swapchain_format_color_needles{GL_RGBA8, |   std::vector<std::int64_t> swapchain_format_color_needles{GL_SRGB8_ALPHA8}; | ||||||
|                                                            GL_RGBA8_SNORM}; |  | ||||||
|   const std::vector<int64_t>::const_iterator &swapchain_format_color_it = |   const std::vector<int64_t>::const_iterator &swapchain_format_color_it = | ||||||
|       std::find_first_of(swapchain_formats.begin(), swapchain_formats.end(), |       std::find_first_of(swapchain_formats.begin(), swapchain_formats.end(), | ||||||
|                          std::begin(swapchain_format_color_needles), |                          std::begin(swapchain_format_color_needles), | ||||||
| @@ -1021,9 +1141,6 @@ void LunarWM::init_xr() { | |||||||
|   } |   } | ||||||
|   auto const swapchain_format_color = *swapchain_format_color_it; |   auto const swapchain_format_color = *swapchain_format_color_it; | ||||||
|  |  | ||||||
|   m_xr.swapchains.color.resize(m_xr.view_configuration_views.size()); |  | ||||||
|   m_xr.swapchains.depth.resize(m_xr.view_configuration_views.size()); |  | ||||||
|  |  | ||||||
|   auto const AllocateSwapchainImageData = |   auto const AllocateSwapchainImageData = | ||||||
|       [&](XrSwapchain swapchain, SwapchainType type, uint32_t count) { |       [&](XrSwapchain swapchain, SwapchainType type, uint32_t count) { | ||||||
|         m_xr.swapchain_images_map[swapchain].first = type; |         m_xr.swapchain_images_map[swapchain].first = type; | ||||||
| @@ -1032,10 +1149,19 @@ void LunarWM::init_xr() { | |||||||
|         return reinterpret_cast<XrSwapchainImageBaseHeader *>( |         return reinterpret_cast<XrSwapchainImageBaseHeader *>( | ||||||
|             m_xr.swapchain_images_map[swapchain].second.data()); |             m_xr.swapchain_images_map[swapchain].second.data()); | ||||||
|       }; |       }; | ||||||
|   for (std::size_t i = 0; i < m_xr.view_configuration_views.size(); i++) { |  | ||||||
|     auto &color_sc = m_xr.swapchains.color[i]; | 	const uint32_t view_count = (uint32_t)m_xr.view_configuration_views.size(); | ||||||
|     auto &depth_sc = m_xr.swapchains.depth[i]; | 	const uint32_t eyeW  = m_xr.view_configuration_views[0].recommendedImageRectWidth; | ||||||
|     auto &vcv = m_xr.view_configuration_views[i]; | 	const uint32_t eyeH  = m_xr.view_configuration_views[0].recommendedImageRectHeight; | ||||||
|  | 	const uint32_t bufW  = eyeW * view_count; | ||||||
|  |  | ||||||
|  | 	m_xr.swapchains.color.resize(1); | ||||||
|  | 	m_xr.swapchains.depth.resize(1); | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		auto &color_sc = m_xr.swapchains.color[0]; | ||||||
|  | 		auto &depth_sc = m_xr.swapchains.depth[0]; | ||||||
|  |     auto &vcv = m_xr.view_configuration_views[0]; | ||||||
|  |  | ||||||
|     { // Create color swapchain |     { // Create color swapchain | ||||||
|       XrSwapchainCreateInfo ci{ |       XrSwapchainCreateInfo ci{ | ||||||
| @@ -1046,8 +1172,8 @@ void LunarWM::init_xr() { | |||||||
|                         XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, |                         XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, | ||||||
|           .format = swapchain_format_color, |           .format = swapchain_format_color, | ||||||
|           .sampleCount = vcv.recommendedSwapchainSampleCount, |           .sampleCount = vcv.recommendedSwapchainSampleCount, | ||||||
|           .width = vcv.recommendedImageRectWidth, |           .width = bufW, | ||||||
|           .height = vcv.recommendedImageRectHeight, |           .height = eyeH, | ||||||
|           .faceCount = 1, |           .faceCount = 1, | ||||||
|           .arraySize = 1, |           .arraySize = 1, | ||||||
|           .mipCount = 1, |           .mipCount = 1, | ||||||
| @@ -1069,8 +1195,8 @@ void LunarWM::init_xr() { | |||||||
|                         XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, |                         XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, | ||||||
|           .format = swapchain_format_depth, |           .format = swapchain_format_depth, | ||||||
|           .sampleCount = vcv.recommendedSwapchainSampleCount, |           .sampleCount = vcv.recommendedSwapchainSampleCount, | ||||||
|           .width = vcv.recommendedImageRectWidth, |           .width = bufW, | ||||||
|           .height = vcv.recommendedImageRectHeight, |           .height = eyeH, | ||||||
|           .faceCount = 1, |           .faceCount = 1, | ||||||
|           .arraySize = 1, |           .arraySize = 1, | ||||||
|           .mipCount = 1, |           .mipCount = 1, | ||||||
| @@ -1178,14 +1304,14 @@ void LunarWM::init_xr() { | |||||||
|       throw std::runtime_error("Failed to get XR environment blend modes"); |       throw std::runtime_error("Failed to get XR environment blend modes"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   std::vector<XrEnvironmentBlendMode> requested_environment_blend_modes { |   std::vector<XrEnvironmentBlendMode> requested_environment_blend_modes{ | ||||||
| 		XR_ENVIRONMENT_BLEND_MODE_OPAQUE, |       XR_ENVIRONMENT_BLEND_MODE_OPAQUE, | ||||||
| 		XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, |       XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, | ||||||
| 		XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, |       XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, | ||||||
| 	}; |   }; | ||||||
|  |  | ||||||
|   for (auto const &bm : requested_environment_blend_modes) { |   for (auto const &bm : requested_environment_blend_modes) { | ||||||
| 		m_xr.environment_blend_mode = bm; |     m_xr.environment_blend_mode = bm; | ||||||
|     if (std::ranges::contains(environment_blend_modes, bm)) { |     if (std::ranges::contains(environment_blend_modes, bm)) { | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| @@ -1200,7 +1326,7 @@ void LunarWM::init_xr() { | |||||||
|     XrReferenceSpaceCreateInfo ci{ |     XrReferenceSpaceCreateInfo ci{ | ||||||
|         .type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO, |         .type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO, | ||||||
|         .next = nullptr, |         .next = nullptr, | ||||||
|         .referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL, |         .referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE, | ||||||
|         .poseInReferenceSpace = {.orientation = {0.0f, 0.0f, 0.0f, 1.0f}, |         .poseInReferenceSpace = {.orientation = {0.0f, 0.0f, 0.0f, 1.0f}, | ||||||
|                                  .position = {0.0f, 0.0f, 0.0f}}, |                                  .position = {0.0f, 0.0f, 0.0f}}, | ||||||
|     }; |     }; | ||||||
| @@ -1210,6 +1336,21 @@ void LunarWM::init_xr() { | |||||||
|       throw std::runtime_error("Failed to create OpenXR reference space"); |       throw std::runtime_error("Failed to create OpenXR reference space"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   { // View reference space | ||||||
|  |     XrReferenceSpaceCreateInfo ci{ | ||||||
|  |         .type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO, | ||||||
|  |         .next = nullptr, | ||||||
|  |         .referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW, | ||||||
|  |         .poseInReferenceSpace = {.orientation = {0.0f, 0.0f, 0.0f, 1.0f}, | ||||||
|  |                                  .position = {0.0f, 0.0f, 0.0f}}, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (xrCreateReferenceSpace(m_xr.session, &ci, &m_xr.view_space) != | ||||||
|  |         XR_SUCCESS) { | ||||||
|  |       throw std::runtime_error("Failed to create OpenXR reference space"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void LunarWM::poll_events_xr() { | void LunarWM::poll_events_xr() { | ||||||
| @@ -1305,83 +1446,134 @@ void LunarWM::poll_events_xr() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| bool LunarWM::render_layer(RenderLayerInfo &info) { | bool LunarWM::render_layer(RenderLayerInfo &info, float dt) | ||||||
| 	std::vector<XrView> views(m_xr.view_configuration_views.size(), {XR_TYPE_VIEW}); | { | ||||||
|  | 	const uint32_t view_count = (uint32_t)m_xr.view_configuration_views.size(); | ||||||
|  | 	std::vector<XrView> views(view_count, { XR_TYPE_VIEW }); | ||||||
|  |  | ||||||
| 	XrViewState view_state{XR_TYPE_VIEW_STATE}; | 	XrViewLocateInfo locInfo{ XR_TYPE_VIEW_LOCATE_INFO }; | ||||||
| 	XrViewLocateInfo view_locate{XR_TYPE_VIEW_LOCATE_INFO}; | 	locInfo.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; | ||||||
| 	view_locate.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; | 	locInfo.displayTime           = info.predicted_display_time; | ||||||
| 	view_locate.displayTime = info.predicted_display_time; | 	locInfo.space                 = m_xr.local_space; | ||||||
| 	view_locate.space = m_xr.local_space; |  | ||||||
|  |  | ||||||
| 	uint32_t view_count = 0; | 	XrViewState viewState{ XR_TYPE_VIEW_STATE }; | ||||||
| 	if (xrLocateViews(m_xr.session, &view_locate, &view_state, | 	uint32_t    located = 0; | ||||||
| 			(uint32_t)views.size(), &view_count, views.data()) != XR_SUCCESS) { | 	if (xrLocateViews(m_xr.session, &locInfo, &viewState, | ||||||
|  | 	                  view_count, &located, views.data()) != XR_SUCCESS || | ||||||
|  | 	    located != view_count) | ||||||
|  | 	{ | ||||||
| 		wlr_log(WLR_ERROR, "Failed to locate views"); | 		wlr_log(WLR_ERROR, "Failed to locate views"); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	info.layer_projection_views.resize(view_count, {XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW}); | 	auto &color_sc  = m_xr.swapchains.color[0]; | ||||||
|  | 	auto &depth_sc  = m_xr.swapchains.depth[0]; | ||||||
|  |  | ||||||
| 	auto acquire_wait = [](XrSwapchain sc, uint32_t &idx) -> bool { | 	auto acquire_wait = [](XrSwapchain sc, uint32_t &idx)->bool{ | ||||||
| 		XrSwapchainImageAcquireInfo ai{XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO}; | 		XrSwapchainImageAcquireInfo ai{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO }; | ||||||
| 		if (xrAcquireSwapchainImage(sc, &ai, &idx) != XR_SUCCESS) return false; | 		if (xrAcquireSwapchainImage(sc, &ai, &idx) != XR_SUCCESS) return false; | ||||||
|  | 		XrSwapchainImageWaitInfo wi{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; | ||||||
| 		XrSwapchainImageWaitInfo wi{XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO}; |  | ||||||
| 		wi.timeout = XR_INFINITE_DURATION; | 		wi.timeout = XR_INFINITE_DURATION; | ||||||
| 		return xrWaitSwapchainImage(sc, &wi) == XR_SUCCESS; | 		return xrWaitSwapchainImage(sc, &wi) == XR_SUCCESS; | ||||||
| 	}; | 	}; | ||||||
| 	auto release = [](XrSwapchain sc) { |  | ||||||
| 		XrSwapchainImageReleaseInfo ri{XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO}; |  | ||||||
| 		xrReleaseSwapchainImage(sc, &ri); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	for (uint32_t i = 0; i < view_count; ++i) { | 	uint32_t colIdx = 0, depIdx = 0; | ||||||
| 		auto &color_sc = m_xr.swapchains.color[i]; | 	if (!acquire_wait(color_sc.swapchain, colIdx) || | ||||||
| 		auto &depth_sc = m_xr.swapchains.depth[i]; | 	    !acquire_wait(depth_sc.swapchain,  depIdx)) | ||||||
|  | 	{ | ||||||
| 		uint32_t color_idx = 0, depth_idx = 0; | 		wlr_log(WLR_ERROR, "Swap-chain acquire failed"); | ||||||
| 		if (!acquire_wait(color_sc.swapchain, color_idx) || | 		return false; | ||||||
| 				!acquire_wait(depth_sc.swapchain, depth_idx)) { |  | ||||||
| 			wlr_log(WLR_ERROR, "Failed to acquire swapchain images"); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		const uint32_t w = m_xr.view_configuration_views[i].recommendedImageRectWidth; |  | ||||||
| 		const uint32_t h = m_xr.view_configuration_views[i].recommendedImageRectHeight; |  | ||||||
|  |  | ||||||
| 		m_renderer.begin_rendering(); |  | ||||||
| 		{ |  | ||||||
| 			if (m_xr.environment_blend_mode == XR_ENVIRONMENT_BLEND_MODE_OPAQUE) |  | ||||||
| 				m_renderer.clear_color(color_sc.image_views[color_idx], 0.17f, 0.17f, 0.17f, 1.0f); |  | ||||||
| 			else |  | ||||||
| 				m_renderer.clear_color(color_sc.image_views[color_idx], 0.0f, 0.0f, 0.0f, 1.0f); |  | ||||||
|  |  | ||||||
| 			m_renderer.clear_depth(depth_sc.image_views[depth_idx], 1.0f); |  | ||||||
| 		} |  | ||||||
| 		m_renderer.end_rendering(); |  | ||||||
|  |  | ||||||
| 		auto &pv = info.layer_projection_views[i]; |  | ||||||
| 		pv.pose = views[i].pose; |  | ||||||
| 		pv.fov = views[i].fov; |  | ||||||
| 		pv.subImage.swapchain = color_sc.swapchain; |  | ||||||
| 		pv.subImage.imageRect = {{0, 0}, {(int32_t)w, (int32_t)h}}; |  | ||||||
| 		pv.subImage.imageArrayIndex = 0; |  | ||||||
|  |  | ||||||
| 		release(color_sc.swapchain); |  | ||||||
| 		release(depth_sc.swapchain); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	GLuint color_tex = m_xr.get_swapchain_image(color_sc.swapchain, colIdx); | ||||||
|  | 	GLuint depth_tex = m_xr.get_swapchain_image(depth_sc.swapchain,  depIdx); | ||||||
|  |  | ||||||
|  | 	if (!m_renderer.fbo) glGenFramebuffers(1, &m_renderer.fbo); | ||||||
|  | 	glBindFramebuffer(GL_FRAMEBUFFER, m_renderer.fbo); | ||||||
|  |  | ||||||
|  | 	rlFramebufferAttach(m_renderer.fbo, color_tex, RL_ATTACHMENT_COLOR_CHANNEL0, | ||||||
|  | 	                    RL_ATTACHMENT_TEXTURE2D, 0); | ||||||
|  | 	rlFramebufferAttach(m_renderer.fbo, depth_tex,  RL_ATTACHMENT_DEPTH, | ||||||
|  | 	                    RL_ATTACHMENT_TEXTURE2D, 0); | ||||||
|  | 	assert(rlFramebufferComplete(m_renderer.fbo)); | ||||||
|  |  | ||||||
|  | 	const uint32_t eyeW = m_xr.view_configuration_views[0].recommendedImageRectWidth; | ||||||
|  | 	const uint32_t eyeH = m_xr.view_configuration_views[0].recommendedImageRectHeight; | ||||||
|  |  | ||||||
|  | 	m_renderer.tmp_rt = { m_renderer.fbo, | ||||||
|  | 	                      { color_tex, (int)(eyeW*view_count), (int)eyeH, 1, -1 }, | ||||||
|  | 	                      { depth_tex, (int)(eyeW*view_count), (int)eyeH, 1, -1 } }; | ||||||
|  |  | ||||||
|  | 	Matrix projL  = xr_projection_matrix(views[0].fov); | ||||||
|  | 	Matrix projR  = xr_projection_matrix(views[1].fov); | ||||||
|  | 	Matrix viewL  = MatrixInvert( xr_matrix(views[0].pose) ); | ||||||
|  | 	Matrix viewR  = MatrixInvert( xr_matrix(views[1].pose) ); | ||||||
|  |  | ||||||
|  | 	BeginTextureMode(m_renderer.tmp_rt); | ||||||
|  |  | ||||||
|  | 	rlEnableStereoRender(); | ||||||
|  | 	rlSetMatrixProjectionStereo(projL, projR); | ||||||
|  | 	rlSetMatrixViewOffsetStereo(viewL, viewR); | ||||||
|  |  | ||||||
|  | 	glViewport(0, 0, (GLsizei)(eyeW*view_count), (GLsizei)eyeH);  | ||||||
|  | 	ClearBackground(RAYWHITE); | ||||||
|  |  | ||||||
|  | 	BeginMode3D(m_renderer.camera); | ||||||
|  | 	{ | ||||||
|  | 		this->render_3d(dt); | ||||||
|  | 	} | ||||||
|  | 	EndMode3D(); | ||||||
|  |  | ||||||
|  | 	rlDisableStereoRender(); | ||||||
|  | 	EndTextureMode(); | ||||||
|  |  | ||||||
|  | 	XrSwapchainImageReleaseInfo ri{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO }; | ||||||
|  | 	xrReleaseSwapchainImage(color_sc.swapchain, &ri); | ||||||
|  | 	xrReleaseSwapchainImage(depth_sc.swapchain,  &ri); | ||||||
|  |  | ||||||
|  | 	info.layer_projection_views.resize(view_count, | ||||||
|  | 	                                   { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW }); | ||||||
|  |  | ||||||
|  | 	for (uint32_t i = 0; i < view_count; ++i) | ||||||
|  | 	{ | ||||||
|  | 		const int32_t xOff = (int32_t)i * (int32_t)eyeW; | ||||||
|  |  | ||||||
|  | 		auto &pv                 = info.layer_projection_views[i]; | ||||||
|  | 		pv.pose                  = views[i].pose; | ||||||
|  | 		pv.fov                   = views[i].fov; | ||||||
|  | 		pv.subImage.swapchain    = color_sc.swapchain; | ||||||
|  | 		pv.subImage.imageRect    = { { xOff, 0 }, | ||||||
|  | 		                             { (int32_t)eyeW, (int32_t)eyeH } }; | ||||||
|  | 		pv.subImage.imageArrayIndex = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	info.layer_projection.type      = XR_TYPE_COMPOSITION_LAYER_PROJECTION; | ||||||
|  | 	info.layer_projection.space     = m_xr.local_space; | ||||||
|  | 	info.layer_projection.viewCount = view_count; | ||||||
|  | 	info.layer_projection.views     = info.layer_projection_views.data(); | ||||||
| 	info.layer_projection.layerFlags = | 	info.layer_projection.layerFlags = | ||||||
| 		XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | | 	    XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | | ||||||
| 		XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; | 	    XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; | ||||||
| 	info.layer_projection.space = m_xr.local_space; |  | ||||||
| 	info.layer_projection.viewCount = (uint32_t)info.layer_projection_views.size(); | 	info.layers.clear(); | ||||||
| 	info.layer_projection.views = info.layer_projection_views.data(); | 	info.layers.push_back( | ||||||
|  | 	    reinterpret_cast<XrCompositionLayerBaseHeader*>(&info.layer_projection)); | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void LunarWM::render_3d(float dt) { | ||||||
|  | 	static float animT {0.0f}; | ||||||
|  | 	animT += dt; | ||||||
|  |  | ||||||
|  | 	DrawGrid(10, 1); | ||||||
|  |  | ||||||
|  | 	Vector3 forward = Vector3Normalize(Vector3Subtract(m_renderer.camera.target, m_renderer.camera.position)); | ||||||
|  | 	float distance = 5.0f + sinf(animT) * 3.0f; | ||||||
|  | 	Vector3 spherePos = Vector3Add(m_renderer.camera.position, Vector3Scale(forward, distance)); | ||||||
|  | 	DrawSphere(spherePos, 0.5f, YELLOW); | ||||||
|  | } | ||||||
|  |  | ||||||
| LunarWM::~LunarWM() { | LunarWM::~LunarWM() { | ||||||
|   assert(m_initialized); |   assert(m_initialized); | ||||||
|  |  | ||||||
| @@ -1435,62 +1627,88 @@ void LunarWM::run() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   auto const *socket = wl_display_add_socket_auto(m_wayland.display); |   auto const *socket = wl_display_add_socket_auto(m_wayland.display); | ||||||
| 	if (!socket) { |   if (!socket) { | ||||||
| 		throw std::runtime_error("Failed to add wayland socket to display"); |     throw std::runtime_error("Failed to add wayland socket to display"); | ||||||
| 	} |   } | ||||||
|  |  | ||||||
| 	setenv("WAYLAND_DISPLAY", socket, true); |   setenv("WAYLAND_DISPLAY", socket, true); | ||||||
| 	wlr_log(WLR_INFO, "Running compositor on WAYLAND_DISPLAY=%s", socket); |   wlr_log(WLR_INFO, "Running compositor on WAYLAND_DISPLAY=%s", socket); | ||||||
|  |  | ||||||
| 	m_running = true; |   m_running = true; | ||||||
| 	while (m_running) { |   while (m_running) { | ||||||
| 		wl_display_flush_clients(m_wayland.display); | 		auto now = Clock::now(); | ||||||
| 		wl_event_loop_dispatch(m_wayland.event_loop, 0); | 		float dt = std::chrono::duration<float>(now - m_last_tick).count(); | ||||||
|  | 		m_last_tick = now; | ||||||
|  |  | ||||||
| 		poll_events_xr(); |     wl_display_flush_clients(m_wayland.display); | ||||||
|  |     wl_event_loop_dispatch(m_wayland.event_loop, 0); | ||||||
|  |  | ||||||
| 		XrFrameState frame_state{ | 		auto draw = eglGetCurrentSurface(EGL_DRAW); | ||||||
| 				.type = XR_TYPE_FRAME_STATE, | 		auto read = eglGetCurrentSurface(EGL_READ); | ||||||
| 		}; | 		if (eglMakeCurrent(m_wayland.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, | ||||||
| 		XrFrameWaitInfo frame_wait_info{ | 											 m_wayland.egl_context) == EGL_FALSE) { | ||||||
| 				.type = XR_TYPE_FRAME_WAIT_INFO, | 			throw std::runtime_error("Failed to eglMakeCurrent"); | ||||||
| 				.next = nullptr, |  | ||||||
| 		}; |  | ||||||
| 		if (xrWaitFrame(m_xr.session, &frame_wait_info, &frame_state) != |  | ||||||
| 				XR_SUCCESS) { |  | ||||||
| 			throw std::runtime_error("Failed to wait for OpenXR frame"); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		XrFrameBeginInfo frame_begin_info{ |     poll_events_xr(); | ||||||
| 				.type = XR_TYPE_FRAME_BEGIN_INFO, |  | ||||||
| 				.next = nullptr, |  | ||||||
| 		}; |  | ||||||
| 		XrResult res = xrBeginFrame(m_xr.session, &frame_begin_info); |  | ||||||
| 		if (res != XR_FRAME_DISCARDED && res != XR_SUCCESS) { |  | ||||||
| 			throw std::runtime_error( |  | ||||||
| 					std::format("Failed to begin the OpenXR Frame: {}", res)); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		RenderLayerInfo render_layer_info{ |     XrFrameState frame_state{ | ||||||
| 				.predicted_display_time = frame_state.predictedDisplayTime, |         .type = XR_TYPE_FRAME_STATE, | ||||||
| 		}; |     }; | ||||||
| 		bool session_active = (m_xr.session_state == XR_SESSION_STATE_SYNCHRONIZED || m_xr.session_state == XR_SESSION_STATE_VISIBLE || m_xr.session_state == XR_SESSION_STATE_FOCUSED); |     XrFrameWaitInfo frame_wait_info{ | ||||||
| 		if (session_active && frame_state.shouldRender) { |         .type = XR_TYPE_FRAME_WAIT_INFO, | ||||||
| 				auto rendered = this->render_layer(render_layer_info); |         .next = nullptr, | ||||||
| 				if (rendered) { |     }; | ||||||
| 						render_layer_info.layers.push_back(reinterpret_cast<XrCompositionLayerBaseHeader *>(&render_layer_info.layer_projection)); |     if (xrWaitFrame(m_xr.session, &frame_wait_info, &frame_state) != | ||||||
| 				} |         XR_SUCCESS) { | ||||||
| 		} |       throw std::runtime_error("Failed to wait for OpenXR frame"); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		XrFrameEndInfo frame_end_info { |     XrFrameBeginInfo frame_begin_info{ | ||||||
| 			.type = XR_TYPE_FRAME_END_INFO, |         .type = XR_TYPE_FRAME_BEGIN_INFO, | ||||||
| 			.displayTime = frame_state.predictedDisplayTime, |         .next = nullptr, | ||||||
| 			.environmentBlendMode = m_xr.environment_blend_mode, |     }; | ||||||
| 			.layerCount = static_cast<uint32_t>(render_layer_info.layers.size()), |     XrResult res = xrBeginFrame(m_xr.session, &frame_begin_info); | ||||||
| 			.layers = render_layer_info.layers.data(), |     if (res != XR_FRAME_DISCARDED && res != XR_SUCCESS) { | ||||||
| 		}; |       throw std::runtime_error( | ||||||
| 		if (xrEndFrame(m_xr.session, &frame_end_info) != XR_SUCCESS) { |           std::format("Failed to begin the OpenXR Frame: {}", res)); | ||||||
| 			throw std::runtime_error("Failed to end OpenXR frame"); |     } | ||||||
|  |  | ||||||
|  | 		WindowShouldClose(); | ||||||
|  |  | ||||||
|  |     RenderLayerInfo render_layer_info{ | ||||||
|  |         .predicted_display_time = frame_state.predictedDisplayTime, | ||||||
|  |     }; | ||||||
|  |     bool session_active = | ||||||
|  |         (m_xr.session_state == XR_SESSION_STATE_SYNCHRONIZED || | ||||||
|  |          m_xr.session_state == XR_SESSION_STATE_VISIBLE || | ||||||
|  |          m_xr.session_state == XR_SESSION_STATE_FOCUSED); | ||||||
|  |     if (session_active && frame_state.shouldRender) { | ||||||
|  |       auto rendered = this->render_layer(render_layer_info, dt); | ||||||
|  |       if (rendered) { | ||||||
|  |         render_layer_info.layers.push_back( | ||||||
|  |             reinterpret_cast<XrCompositionLayerBaseHeader *>( | ||||||
|  |                 &render_layer_info.layer_projection)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     XrFrameEndInfo frame_end_info{ | ||||||
|  |         .type = XR_TYPE_FRAME_END_INFO, | ||||||
|  |         .displayTime = frame_state.predictedDisplayTime, | ||||||
|  |         .environmentBlendMode = m_xr.environment_blend_mode, | ||||||
|  |         .layerCount = static_cast<uint32_t>(render_layer_info.layers.size()), | ||||||
|  |         .layers = render_layer_info.layers.data(), | ||||||
|  |     }; | ||||||
|  |     if (xrEndFrame(m_xr.session, &frame_end_info) != XR_SUCCESS) { | ||||||
|  |       throw std::runtime_error("Failed to end OpenXR frame"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 		BeginDrawing(); | ||||||
|  | 		EndDrawing(); | ||||||
|  |  | ||||||
|  | 		if (eglMakeCurrent(m_wayland.egl_display, read, draw, | ||||||
|  | 											 m_wayland.egl_context) == EGL_FALSE) { | ||||||
|  | 			throw std::runtime_error("Failed to eglMakeCurrent"); | ||||||
| 		} | 		} | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user