Add helper scripts and wlroots integration
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
		| @@ -10,10 +10,29 @@ extern "C" { | ||||
| #include <cstring> | ||||
| #include <memory> | ||||
|  | ||||
| #define GL_GLEXT_PROTOTYPES | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glext.h> | ||||
| #include <GL/glx.h> | ||||
| #include <X11/Xlib.h> | ||||
| #include <openxr/openxr.h> | ||||
| #include <openxr/openxr_platform.h> | ||||
| #include <vector> | ||||
| // Internal backend definition | ||||
| struct openxr_backend { | ||||
| 	wlr_backend base; | ||||
| 	wl_display* display; | ||||
| 	wl_event_loop* event_loop; | ||||
| 	XrInstance instance {}; | ||||
| 	XrSession session {}; | ||||
| 	XrSpace app_space { XR_NULL_HANDLE }; | ||||
| 	XrSwapchain swapchain { XR_NULL_HANDLE }; | ||||
| 	int32_t width = 0, height = 0; | ||||
| 	std::vector<XrSwapchainImageOpenGLKHR> swapchain_images; | ||||
| 	std::vector<GLuint> framebuffers; | ||||
| 	bool started = false; | ||||
| 	struct wlr_output* output = nullptr; | ||||
| }; | ||||
|  | ||||
| static void output_destroy(struct wlr_output* wlr_output) { (void)wlr_output; } | ||||
|  | ||||
| @@ -28,8 +47,77 @@ static bool output_test( | ||||
| static bool output_commit( | ||||
|     struct wlr_output* wlr_output, const struct wlr_output_state* state) | ||||
| { | ||||
| 	(void)wlr_output; | ||||
| 	// Retrieve our backend | ||||
| 	auto* xr = reinterpret_cast<openxr_backend*>(wlr_output->backend); | ||||
| 	(void)state; | ||||
| 	// Wait for frame | ||||
| 	XrFrameState frameState { XR_TYPE_FRAME_STATE }; | ||||
| 	xrWaitFrame(xr->session, nullptr, &frameState); | ||||
| 	xrBeginFrame(xr->session, nullptr); | ||||
| 	// Locate views | ||||
| 	uint32_t viewCount = static_cast<uint32_t>(xr->framebuffers.size()); | ||||
| 	std::vector<XrView> views(viewCount, { XR_TYPE_VIEW }); | ||||
| 	XrViewLocateInfo viewLocInfo { XR_TYPE_VIEW_LOCATE_INFO }; | ||||
| 	viewLocInfo.viewConfigurationType | ||||
| 	    = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; | ||||
| 	viewLocInfo.displayTime = frameState.predictedDisplayTime; | ||||
| 	viewLocInfo.space = xr->app_space; | ||||
| 	XrViewState viewState { XR_TYPE_VIEW_STATE }; | ||||
| 	uint32_t viewCountOutput; | ||||
| 	xrLocateViews(xr->session, &viewLocInfo, &viewState, viewCount, | ||||
| 	    &viewCountOutput, views.data()); | ||||
| 	// Prepare projection views | ||||
| 	std::vector<XrCompositionLayerProjectionView> projViews( | ||||
| 	    viewCountOutput, { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW }); | ||||
| 	for (uint32_t i = 0; i < viewCountOutput; ++i) { | ||||
| 		// Acquire swapchain image | ||||
| 		XrSwapchainImageAcquireInfo acqInfo { | ||||
| 			XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO | ||||
| 		}; | ||||
| 		uint32_t imgIndex; | ||||
| 		xrAcquireSwapchainImage(xr->swapchain, &acqInfo, &imgIndex); | ||||
| 		XrSwapchainImageWaitInfo waitInfo { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; | ||||
| 		waitInfo.timeout = XR_INFINITE_DURATION; | ||||
| 		xrWaitSwapchainImage(xr->swapchain, &waitInfo); | ||||
| 		// Bind framebuffer and clear | ||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, xr->framebuffers[imgIndex]); | ||||
| 		glViewport(0, 0, xr->width, xr->height); | ||||
| 		glClearColor(0.1f, 0.1f, 0.1f, 1.0f); | ||||
| 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
| 		// TODO: render scene (e.g., wlr_scene_render) | ||||
| 		// Release swapchain image | ||||
| 		{ | ||||
| 			XrSwapchainImageReleaseInfo relInfo { | ||||
| 				XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO | ||||
| 			}; | ||||
| 			xrReleaseSwapchainImage(xr->swapchain, &relInfo); | ||||
| 		} | ||||
| 		// Setup projection view | ||||
| 		projViews[i].pose = views[i].pose; | ||||
| 		projViews[i].fov = views[i].fov; | ||||
| 		projViews[i].subImage.swapchain = xr->swapchain; | ||||
| 		projViews[i].subImage.imageArrayIndex = imgIndex; | ||||
| 		// Set image rectangle offset and extent | ||||
| 		projViews[i].subImage.imageRect.offset.x = 0; | ||||
| 		projViews[i].subImage.imageRect.offset.y = 0; | ||||
| 		projViews[i].subImage.imageRect.extent.width = xr->width; | ||||
| 		projViews[i].subImage.imageRect.extent.height = xr->height; | ||||
| 	} | ||||
| 	// Unbind | ||||
| 	glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
| 	// End frame | ||||
| 	XrCompositionLayerProjection layer { XR_TYPE_COMPOSITION_LAYER_PROJECTION }; | ||||
| 	layer.space = xr->app_space; | ||||
| 	layer.viewCount = static_cast<uint32_t>(projViews.size()); | ||||
| 	layer.views = projViews.data(); | ||||
| 	XrCompositionLayerBaseHeader const* layers[] | ||||
| 	    = { reinterpret_cast<XrCompositionLayerBaseHeader const*>(&layer) }; | ||||
| 	XrFrameEndInfo frameEndInfo { XR_TYPE_FRAME_END_INFO }; | ||||
| 	frameEndInfo.displayTime = frameState.predictedDisplayTime; | ||||
| 	frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; | ||||
| 	frameEndInfo.layerCount = 1; | ||||
| 	frameEndInfo.layers = layers; | ||||
| 	xrEndFrame(xr->session, &frameEndInfo); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -48,23 +136,6 @@ static const struct wlr_output_impl output_impl = { | ||||
| 	.get_primary_formats = output_get_primary_formats, | ||||
| }; | ||||
|  | ||||
| #include <GL/glx.h> | ||||
| #include <X11/Xlib.h> | ||||
| #include <cstring> | ||||
| #include <memory> | ||||
| #include <openxr/openxr.h> | ||||
| #include <openxr/openxr_platform.h> | ||||
|  | ||||
| struct openxr_backend { | ||||
| 	wlr_backend base; | ||||
| 	wl_display* display; | ||||
| 	wl_event_loop* event_loop; | ||||
| 	XrInstance instance {}; | ||||
| 	XrSession session {}; | ||||
| 	bool started = false; | ||||
| 	struct wlr_output* output = nullptr; | ||||
| }; | ||||
|  | ||||
| static bool backend_start(wlr_backend* backend) | ||||
| { | ||||
| 	auto* xr = reinterpret_cast<openxr_backend*>(backend); | ||||
| @@ -156,6 +227,68 @@ static bool backend_start(wlr_backend* backend) | ||||
| 		wlr_log(WLR_ERROR, "xrCreateSession failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	// Create reference space | ||||
| 	XrReferenceSpaceCreateInfo spaceInfo { | ||||
| 		XR_TYPE_REFERENCE_SPACE_CREATE_INFO | ||||
| 	}; | ||||
| 	spaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; | ||||
| 	spaceInfo.poseInReferenceSpace = { { 0, 0, 0, 1 }, { 0, 0, 0 } }; | ||||
| 	if (xrCreateReferenceSpace(xr->session, &spaceInfo, &xr->app_space) | ||||
| 	    != XR_SUCCESS) { | ||||
| 		wlr_log(WLR_ERROR, "xrCreateReferenceSpace failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	// Get recommended view configuration | ||||
| 	uint32_t viewCount; | ||||
| 	xrEnumerateViewConfigurationViews(xr->instance, system_id, | ||||
| 	    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &viewCount, nullptr); | ||||
| 	std::vector<XrViewConfigurationView> viewConfigs( | ||||
| 	    viewCount, { XR_TYPE_VIEW_CONFIGURATION_VIEW }); | ||||
| 	xrEnumerateViewConfigurationViews(xr->instance, system_id, | ||||
| 	    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, viewCount, &viewCount, | ||||
| 	    viewConfigs.data()); | ||||
| 	xr->width = viewConfigs[0].recommendedImageRectWidth; | ||||
| 	xr->height = viewConfigs[0].recommendedImageRectHeight; | ||||
| 	// Create swapchain | ||||
| 	uint32_t formatCount; | ||||
| 	xrEnumerateSwapchainFormats(xr->session, 0, &formatCount, nullptr); | ||||
| 	std::vector<int64_t> formats(formatCount); | ||||
| 	xrEnumerateSwapchainFormats( | ||||
| 	    xr->session, formatCount, &formatCount, formats.data()); | ||||
| 	int64_t swapFormat = formats.empty() ? 0 : formats[0]; | ||||
| 	XrSwapchainCreateInfo swapchain_ci { XR_TYPE_SWAPCHAIN_CREATE_INFO }; | ||||
| 	swapchain_ci.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; | ||||
| 	swapchain_ci.format = swapFormat; | ||||
| 	swapchain_ci.sampleCount = 1; | ||||
| 	swapchain_ci.width = xr->width; | ||||
| 	swapchain_ci.height = xr->height; | ||||
| 	swapchain_ci.faceCount = 1; | ||||
| 	swapchain_ci.arraySize = viewCount; | ||||
| 	swapchain_ci.mipCount = 1; | ||||
| 	if (xrCreateSwapchain(xr->session, &swapchain_ci, &xr->swapchain) | ||||
| 	    != XR_SUCCESS) { | ||||
| 		wlr_log(WLR_ERROR, "xrCreateSwapchain failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	// Enumerate swapchain images | ||||
| 	uint32_t imageCount; | ||||
| 	xrEnumerateSwapchainImages(xr->swapchain, 0, &imageCount, nullptr); | ||||
| 	xr->swapchain_images.resize( | ||||
| 	    imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR }); | ||||
| 	xrEnumerateSwapchainImages(xr->swapchain, imageCount, &imageCount, | ||||
| 	    reinterpret_cast<XrSwapchainImageBaseHeader*>( | ||||
| 	        xr->swapchain_images.data())); | ||||
| 	// Create framebuffers for each image | ||||
| 	xr->framebuffers.resize(imageCount); | ||||
| 	for (uint32_t i = 0; i < imageCount; ++i) { | ||||
| 		GLuint fbo; | ||||
| 		glGenFramebuffers(1, &fbo); | ||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, fbo); | ||||
| 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | ||||
| 		    GL_TEXTURE_2D, xr->swapchain_images[i].image, 0); | ||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
| 		xr->framebuffers[i] = fbo; | ||||
| 	} | ||||
|  | ||||
| 	xr->output = static_cast<wlr_output*>(calloc(1, sizeof(wlr_output))); | ||||
| 	if (xr->output) { | ||||
| @@ -173,6 +306,20 @@ static bool backend_start(wlr_backend* backend) | ||||
| static void backend_destroy(wlr_backend* backend) | ||||
| { | ||||
| 	auto* xr = reinterpret_cast<openxr_backend*>(backend); | ||||
| 	// destroy swapchain and framebuffers | ||||
| 	if (xr->swapchain) { | ||||
| 		xrDestroySwapchain(xr->swapchain); | ||||
| 		xr->swapchain = XR_NULL_HANDLE; | ||||
| 	} | ||||
| 	for (auto fbo : xr->framebuffers) { | ||||
| 		glDeleteFramebuffers(1, &fbo); | ||||
| 	} | ||||
| 	// destroy reference space | ||||
| 	if (xr->app_space) { | ||||
| 		xrDestroySpace(xr->app_space); | ||||
| 		xr->app_space = XR_NULL_HANDLE; | ||||
| 	} | ||||
| 	// destroy XR session and instance | ||||
| 	if (xr->session) { | ||||
| 		xrDestroySession(xr->session); | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user