From b65adf8d4a0c239f5aa44425d14d1fe14f675643 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Thu, 20 Jul 2023 12:42:25 +0200 Subject: [PATCH] toplevelexport: support dmabuf + various fixes --- src/events/Monitors.cpp | 4 ++- src/protocols/Screencopy.cpp | 3 -- src/protocols/ToplevelExport.cpp | 58 ++++++++++++++++++++++++-------- src/protocols/ToplevelExport.hpp | 6 ++-- src/render/OpenGL.cpp | 4 +++ src/render/OpenGL.hpp | 1 + 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index d748ef40..5e87c4fb 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -217,8 +217,10 @@ void Events::listener_monitorCommit(void* owner, void* data) { const auto E = (wlr_output_event_commit*)data; - if (E->committed & WLR_OUTPUT_STATE_BUFFER) + if (E->committed & WLR_OUTPUT_STATE_BUFFER) { g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E); + g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E); + } } void Events::listener_monitorBind(void* owner, void* data) { diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index c93bd5f7..11d63612 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -422,9 +422,6 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) return false; - // render the client - const auto PMONITOR = frame->pMonitor; - if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer)) { wlr_buffer_end_data_ptr_access(frame->buffer); return false; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index eeeaa81f..318af943 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -36,8 +36,6 @@ CToplevelExportProtocolManager::CToplevelExportProtocolManager() { m_liDisplayDestroy.notify = handleDisplayDestroy; wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); - g_pHookSystem->hookDynamic("preRender", [&](void* self, std::any data) { onMonitorRender(std::any_cast(data)); }); - Debug::log(LOG, "ToplevelExportManager started successfully!"); } @@ -207,6 +205,12 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width; hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + + if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { + hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height); + } + + hyprland_toplevel_export_frame_v1_send_buffer_done(PFRAME->resource); } void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) { @@ -278,11 +282,12 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r m_vFramesAwaitingWrite.emplace_back(PFRAME); } -void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) { - +void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share + const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output); + std::vector framesToRemove; // share frame if correct output @@ -292,6 +297,9 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) { continue; } + if (PMONITOR != g_pCompositor->getMonitorFromID(f->pWindow->m_iMonitorID)) + continue; + wlr_box geometry = {f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y, f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y}; if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry)) @@ -314,14 +322,12 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { if (!frame->buffer || !g_pCompositor->windowValidMapped(frame->pWindow)) return; - // TODO: damage - timespec now; clock_gettime(CLOCK_MONOTONIC, &now); uint32_t flags = 0; if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { - if (!copyFrameDmabuf(frame)) { + if (!copyFrameDmabuf(frame, &now)) { hyprland_toplevel_export_frame_v1_send_failed(frame->resource); return; } @@ -333,12 +339,17 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { } hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags); - // todo: send damage + sendDamage(frame); uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec); } +void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) { + // TODO: send proper dmg + hyprland_toplevel_export_frame_v1_send_damage(frame->resource, 0, 0, frame->box.width, frame->box.height); +} + bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { void* data; uint32_t format; @@ -404,8 +415,6 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb); - glFinish(); // flush - glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data); g_pHyprOpenGL->end(); @@ -420,10 +429,31 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times return true; } -bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { - // todo - Debug::log(ERR, "DMABUF copying not impl'd!"); - return false; +bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) { + if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, frame->buffer)) + return false; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); + + CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; + + g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true); + + g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0)); + + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + + g_pHyprOpenGL->bindWlrOutputFb(); + + wlr_box monbox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f); + + g_pHyprOpenGL->end(); + + wlr_renderer_end(g_pCompositor->m_sWLRRenderer); + return true; } void CToplevelExportProtocolManager::onWindowUnmap(CWindow* pWindow) { diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 45e979f6..50b967ed 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -22,6 +22,7 @@ class CToplevelExportProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); void displayDestroy(); void onWindowUnmap(CWindow* pWindow); + void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); private: wl_global* m_pGlobal = nullptr; @@ -33,10 +34,9 @@ class CToplevelExportProtocolManager { std::vector m_vFramesAwaitingWrite; void shareFrame(SScreencopyFrame* frame); - bool copyFrameDmabuf(SScreencopyFrame* frame); + bool copyFrameDmabuf(SScreencopyFrame* frame, timespec* now); bool copyFrameShm(SScreencopyFrame* frame, timespec* now); - - void onMonitorRender(CMonitor* pMonitor); + void sendDamage(SScreencopyFrame* frame); friend class CScreencopyClient; }; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index db9b136d..c79fab70 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -199,6 +199,10 @@ void CHyprOpenGLImpl::end() { m_RenderData.mouseZoomUseMouse = true; } +void CHyprOpenGLImpl::bindWlrOutputFb() { + glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb); +} + void CHyprOpenGLImpl::initShaders() { GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); m_RenderData.pCurrentMonData->m_shQUAD.program = prog; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index fc72782f..ac5c3e6b 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -97,6 +97,7 @@ class CHyprOpenGLImpl { void begin(CMonitor*, CRegion*, bool fake = false); void end(); + void bindWlrOutputFb(); void renderRect(wlr_box*, const CColor&, int round = 0); void renderRectWithDamage(wlr_box*, const CColor&, CRegion* damage, int round = 0);