diff --git a/src/LunarWM.cppm b/src/LunarWM.cppm index 3d8945d..6171c8e 100644 --- a/src/LunarWM.cppm +++ b/src/LunarWM.cppm @@ -821,49 +821,62 @@ private: wlr_xdg_toplevel_set_size(tl->xdg_toplevel, 0, 0); return; } + tl->update(); }; wl_signal_add(&surface->events.commit, &commit); destroy.notify = [](wl_listener *l, void *) { - auto tl = wl_container_of(l, (Toplevel*)nullptr, destroy); + auto tl = wl_container_of(l, (Toplevel *)nullptr, destroy); auto &vec = tl->server->m_wayland.toplevels; vec.erase(std::remove_if(vec.begin(), vec.end(), - [tl](auto &p){ return p.get() == tl; }), vec.end()); + [tl](auto &p) { return p.get() == tl; }), + vec.end()); }; wl_signal_add(&surface->events.destroy, &destroy); } - void update() { + void update() + { + texture = wlr_surface_get_texture(surface); + struct wlr_client_buffer *cl_buf = surface->buffer; + if (!texture || !cl_buf) { + return; + } - texture = wlr_surface_get_texture(surface); - if (!texture) - return; - wlr_gles2_texture_get_attribs(texture, &attribs); - char const *texture_target = "unknown"; - if (attribs.target == GL_TEXTURE_EXTERNAL_OES) { - texture_target = "GL_TEXTURE_EXTERNAL_OES"; - } else if (attribs.target == GL_TEXTURE_2D) { - texture_target = "GL_TEXTURE_2D"; - } - gles_texture = gles2_get_texture(texture); - if (!gles_texture) { - return; - } - rl_texture.id = attribs.tex; - rl_texture.width = texture->width; - rl_texture.height = texture->height; - rl_texture.mipmaps = 1; - rl_texture.format = gles_texture->has_alpha ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8; + if (locked_buffer && locked_buffer != &cl_buf->base) { + wlr_buffer_unlock(locked_buffer); + locked_buffer = nullptr; + } + if (locked_buffer == nullptr) { + locked_buffer = wlr_buffer_lock(&cl_buf->base); + } - SetTextureFilter(rl_texture, TEXTURE_FILTER_BILINEAR); - SetTextureWrap(rl_texture, TEXTURE_WRAP_CLAMP); + wlr_gles2_texture_get_attribs(texture, &attribs); + gles_texture = gles2_get_texture(texture); + if (!gles_texture) { + return; + } + rl_texture.id = attribs.tex; + rl_texture.width = texture->width; + rl_texture.height = texture->height; + rl_texture.mipmaps = 1; + rl_texture.format = gles_texture->has_alpha + ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 + : PIXELFORMAT_UNCOMPRESSED_R8G8B8; + + SetTextureFilter(rl_texture, TEXTURE_FILTER_BILINEAR); + SetTextureWrap(rl_texture, TEXTURE_WRAP_CLAMP); } - ~Toplevel() { + ~Toplevel() + { wl_list_remove(&commit.link); wl_list_remove(&destroy.link); + if (locked_buffer) { + wlr_buffer_unlock(locked_buffer); + } } LunarWM *server {}; @@ -874,6 +887,8 @@ private: wlr_xdg_toplevel *xdg_toplevel {}; wlr_surface *surface {}; wlr_texture *texture {}; + + wlr_buffer *locked_buffer {}; wlr_gles2_texture_attribs attribs {}; wlr_gles2_texture *gles_texture {}; Texture2D rl_texture {}; @@ -915,8 +930,6 @@ private: std::vector> toplevels; - // Output stuff to update buffers - struct wl_listener new_output_listener {}; } m_wayland; struct { @@ -1274,54 +1287,6 @@ void LunarWM::init_wayland() }; wl_signal_add(&m_wayland.xdg_shell->events.new_popup, &m_wayland.new_xdg_popup_listener); - - // Output stuff - wl_signal_add(&m_wayland.backend->events.new_output, &m_wayland.new_output_listener); - m_wayland.new_output_listener.notify = [](wl_listener *listener, void *data) { - wlr_output *output = reinterpret_cast(data); - LunarWM *sample = - wl_container_of(listener, static_cast(nullptr), m_wayland.new_output_listener); - - wlr_output_init_render(output, sample->m_wayland.allocator, sample->m_wayland.renderer); - - auto my_output = new Output; - my_output->output = output; - my_output->server = sample; - wl_signal_add(&output->events.frame, &my_output->frame); - my_output->frame.notify = [](struct wl_listener *listener, void *data) { - Output *sample_output = - wl_container_of(listener, static_cast(nullptr), frame); - LunarWM *sample = sample_output->server; - wlr_output *wlr_output = sample_output->output; - - struct wlr_output_state state; - wlr_output_state_init(&state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL); - wlr_render_pass_submit(pass); - - wlr_output_commit_state(wlr_output, &state); - wlr_output_state_finish(&state); - }; - wl_signal_add(&output->events.destroy, &my_output->destroy); - my_output->destroy.notify = [](struct wl_listener *listener, void *data) { - struct Output *sample_output = - wl_container_of(listener, static_cast(nullptr), destroy); - wlr_log(WLR_DEBUG, "Output removed"); - wl_list_remove(&sample_output->frame.link); - wl_list_remove(&sample_output->destroy.link); - free(sample_output); - }; - - wlr_output_state state; - wlr_output_state_init(&state); - wlr_output_state_set_enabled(&state, true); - wlr_output_mode *mode = wlr_output_preferred_mode(output); - if (mode != NULL) { - wlr_output_state_set_mode(&state, mode); - } - wlr_output_commit_state(output, &state); - wlr_output_state_finish(&state); - }; } void LunarWM::init_xr() @@ -1909,18 +1874,20 @@ void LunarWM::poll_events_xr() bool LunarWM::render_layer(RenderLayerInfo &info, float dt) { // locate views ----------------------------------------------------------- - std::uint32_t view_count = (std::uint32_t)m_xr.view_configuration_views.size(); + std::uint32_t view_count + = (std::uint32_t)m_xr.view_configuration_views.size(); std::vector views(view_count, { XR_TYPE_VIEW }); - XrViewLocateInfo locInfo{ XR_TYPE_VIEW_LOCATE_INFO }; - locInfo.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; - locInfo.displayTime = info.predicted_display_time; - locInfo.space = m_xr.local_space; + XrViewLocateInfo locInfo { XR_TYPE_VIEW_LOCATE_INFO }; + locInfo.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; + locInfo.displayTime = info.predicted_display_time; + locInfo.space = m_xr.local_space; - XrViewState viewState{ XR_TYPE_VIEW_STATE }; + XrViewState viewState { XR_TYPE_VIEW_STATE }; std::uint32_t located = 0; - if (xrLocateViews(m_xr.session, &locInfo, &viewState, - view_count, &located, 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"); return false; @@ -1930,10 +1897,11 @@ bool LunarWM::render_layer(RenderLayerInfo &info, float dt) auto &color_sc = m_xr.swapchains.color[0]; auto &depth_sc = m_xr.swapchains.depth[0]; - auto acquire_wait = [](XrSwapchain sc, std::uint32_t &idx)->bool { - XrSwapchainImageAcquireInfo ai{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO }; - if (xrAcquireSwapchainImage(sc, &ai, &idx) != XR_SUCCESS) return false; - XrSwapchainImageWaitInfo wi{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; + auto acquire_wait = [](XrSwapchain sc, std::uint32_t &idx) -> bool { + XrSwapchainImageAcquireInfo ai { XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO }; + if (xrAcquireSwapchainImage(sc, &ai, &idx) != XR_SUCCESS) + return false; + XrSwapchainImageWaitInfo wi { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; wi.timeout = XR_INFINITE_DURATION; return xrWaitSwapchainImage(sc, &wi) == XR_SUCCESS; }; @@ -1949,44 +1917,45 @@ bool LunarWM::render_layer(RenderLayerInfo &info, float dt) GLuint depth_tex = m_xr.get_swapchain_image(depth_sc.swapchain, depIdx); // build FBO -------------------------------------------------------------- - if (!m_renderer.fbo) glGenFramebuffers(1, &m_renderer.fbo); + 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); + RL_ATTACHMENT_TEXTURE2D, 0); rlFramebufferAttach(m_renderer.fbo, depth_tex, RL_ATTACHMENT_DEPTH, - RL_ATTACHMENT_TEXTURE2D, 0); + RL_ATTACHMENT_TEXTURE2D, 0); assert(rlFramebufferComplete(m_renderer.fbo)); - std::uint32_t eyeW = m_xr.view_configuration_views[0].recommendedImageRectWidth; - std::uint32_t eyeH = m_xr.view_configuration_views[0].recommendedImageRectHeight; + std::uint32_t eyeW + = m_xr.view_configuration_views[0].recommendedImageRectWidth; + std::uint32_t eyeH + = m_xr.view_configuration_views[0].recommendedImageRectHeight; - m_renderer.tmp_rt = { - m_renderer.fbo, + 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 } - }; + { depth_tex, (int)(eyeW * view_count), (int)eyeH, 1, -1 } }; // head-space view matrix (matches rlOpenXR) ------------------------------ - XrSpaceLocation headLoc{ XR_TYPE_SPACE_LOCATION }; + XrSpaceLocation headLoc { XR_TYPE_SPACE_LOCATION }; xrLocateSpace(m_xr.view_space, m_xr.local_space, - info.predicted_display_time, &headLoc); + info.predicted_display_time, &headLoc); Matrix headView = MatrixInvert(xr_matrix(headLoc.pose)); // per-eye projection + view-offset --------------------------------------- - Matrix projR = xr_projection_matrix(views[1].fov); - Matrix projL = xr_projection_matrix(views[0].fov); - Matrix viewOffR = MatrixMultiply(xr_matrix(views[1].pose), headView); - Matrix viewOffL = MatrixMultiply(xr_matrix(views[0].pose), headView); + Matrix projR = xr_projection_matrix(views[1].fov); + Matrix projL = xr_projection_matrix(views[0].fov); + Matrix viewOffR = MatrixMultiply(xr_matrix(views[1].pose), headView); + Matrix viewOffL = MatrixMultiply(xr_matrix(views[0].pose), headView); // draw ------------------------------------------------------------------- BeginTextureMode(m_renderer.tmp_rt); rlEnableStereoRender(); - rlSetMatrixProjectionStereo(projL, projR); // right, left (yes) + rlSetMatrixProjectionStereo(projL, projR); // right, left (yes) rlSetMatrixViewOffsetStereo(viewOffL, viewOffR); glViewport(0, 0, (GLsizei)(eyeW * view_count), (GLsizei)eyeH); - ClearBackground(RAYWHITE); + ClearBackground({ 0, 0, 10, 255 }); m_renderer.update_camera(*this, m_renderer.camera, info); @@ -2000,37 +1969,37 @@ bool LunarWM::render_layer(RenderLayerInfo &info, float dt) EndTextureMode(); // release swapchain images ---------------------------------------------- - XrSwapchainImageReleaseInfo ri{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO }; + XrSwapchainImageReleaseInfo ri { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO }; xrReleaseSwapchainImage(color_sc.swapchain, &ri); xrReleaseSwapchainImage(depth_sc.swapchain, &ri); // fill projection layer -------------------------------------------------- - info.layer_projection_views.resize(view_count, - { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW }); + info.layer_projection_views.resize( + view_count, { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW }); for (std::uint32_t i = 0; i < view_count; ++i) { 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.offset = { xOff, 0 }; - pv.subImage.imageRect.extent = { (int32_t)eyeW, (int32_t)eyeH }; - pv.subImage.imageArrayIndex = 0; + pv.fov = views[i].fov; + pv.subImage.swapchain = color_sc.swapchain; + pv.subImage.imageRect.offset = { xOff, 0 }; + pv.subImage.imageRect.extent = { (int32_t)eyeW, (int32_t)eyeH }; + pv.subImage.imageArrayIndex = 0; } info.layer_projection = { - .type = XR_TYPE_COMPOSITION_LAYER_PROJECTION, - .layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | - XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, - .space = m_xr.local_space, - .viewCount = view_count, - .views = info.layer_projection_views.data(), + .type = XR_TYPE_COMPOSITION_LAYER_PROJECTION, + .layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT + | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, + .space = m_xr.local_space, + .viewCount = view_count, + .views = info.layer_projection_views.data(), }; info.layers.clear(); - info.layers.push_back( - reinterpret_cast(&info.layer_projection)); + info.layers.push_back(reinterpret_cast( + &info.layer_projection)); return true; } @@ -2176,15 +2145,36 @@ void LunarWM::run() == EGL_FALSE) { throw std::runtime_error("Failed to eglMakeCurrent"); } + + struct timespec n; + clock_gettime(CLOCK_MONOTONIC, &n); + for (auto const &tl : m_wayland.toplevels) { + if (tl->surface) { + wlr_surface_send_frame_done(tl->surface, &n); + } + } } } +static void DrawBillboardNoShear(Camera3D const &cam, Texture2D tex, + Vector3 pos, float scale = 1.0f, Color tint = WHITE) +{ + Rectangle src = { 0, 0, (float)tex.width, (float)tex.height }; + + Vector2 size = { scale * fabsf(src.width / src.height), scale }; + Vector2 origin = { size.x * 0.5f, size.y * 0.5f }; + + DrawBillboardPro(cam, tex, src, pos, cam.up, size, origin, 0.0f, tint); +} + void LunarWM::render_3d(float dt) { DrawGrid(10, 1); for (auto const &tl : m_wayland.toplevels) { - DrawBillboard(m_renderer.camera, tl->rl_texture, { -2, 1, -2 }, 1, WHITE); + tl->update(); + DrawBillboardNoShear( + m_renderer.camera, tl->rl_texture, { 0, 1, -1.4f }, 1.0f); } }