mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 07:05:58 +01:00
toplevelexport: support dmabuf + various fixes
This commit is contained in:
parent
3a1496b4eb
commit
b65adf8d4a
6 changed files with 55 additions and 21 deletions
|
@ -217,8 +217,10 @@ void Events::listener_monitorCommit(void* owner, void* data) {
|
||||||
|
|
||||||
const auto E = (wlr_output_event_commit*)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_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
|
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_monitorBind(void* owner, void* data) {
|
void Events::listener_monitorBind(void* owner, void* data) {
|
||||||
|
|
|
@ -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))
|
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// render the client
|
|
||||||
const auto PMONITOR = frame->pMonitor;
|
|
||||||
|
|
||||||
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer)) {
|
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer)) {
|
||||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -36,8 +36,6 @@ CToplevelExportProtocolManager::CToplevelExportProtocolManager() {
|
||||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
||||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
||||||
|
|
||||||
g_pHookSystem->hookDynamic("preRender", [&](void* self, std::any data) { onMonitorRender(std::any_cast<CMonitor*>(data)); });
|
|
||||||
|
|
||||||
Debug::log(LOG, "ToplevelExportManager started successfully!");
|
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;
|
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);
|
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) {
|
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);
|
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
|
||||||
|
|
||||||
if (m_vFramesAwaitingWrite.empty())
|
if (m_vFramesAwaitingWrite.empty())
|
||||||
return; // nothing to share
|
return; // nothing to share
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output);
|
||||||
|
|
||||||
std::vector<SScreencopyFrame*> framesToRemove;
|
std::vector<SScreencopyFrame*> framesToRemove;
|
||||||
|
|
||||||
// share frame if correct output
|
// share frame if correct output
|
||||||
|
@ -292,6 +297,9 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||||
continue;
|
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};
|
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))
|
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))
|
if (!frame->buffer || !g_pCompositor->windowValidMapped(frame->pWindow))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: damage
|
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
|
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
|
||||||
if (!copyFrameDmabuf(frame)) {
|
if (!copyFrameDmabuf(frame, &now)) {
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -333,12 +339,17 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags);
|
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 tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
|
||||||
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
||||||
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
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) {
|
bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
||||||
void* data;
|
void* data;
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
|
@ -404,8 +415,6 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb);
|
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);
|
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data);
|
||||||
|
|
||||||
g_pHyprOpenGL->end();
|
g_pHyprOpenGL->end();
|
||||||
|
@ -420,10 +429,31 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) {
|
||||||
// todo
|
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, frame->buffer))
|
||||||
Debug::log(ERR, "DMABUF copying not impl'd!");
|
return false;
|
||||||
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) {
|
void CToplevelExportProtocolManager::onWindowUnmap(CWindow* pWindow) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ class CToplevelExportProtocolManager {
|
||||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
||||||
void displayDestroy();
|
void displayDestroy();
|
||||||
void onWindowUnmap(CWindow* pWindow);
|
void onWindowUnmap(CWindow* pWindow);
|
||||||
|
void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
wl_global* m_pGlobal = nullptr;
|
||||||
|
@ -33,10 +34,9 @@ class CToplevelExportProtocolManager {
|
||||||
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
||||||
|
|
||||||
void shareFrame(SScreencopyFrame* frame);
|
void shareFrame(SScreencopyFrame* frame);
|
||||||
bool copyFrameDmabuf(SScreencopyFrame* frame);
|
bool copyFrameDmabuf(SScreencopyFrame* frame, timespec* now);
|
||||||
bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
|
bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
|
||||||
|
void sendDamage(SScreencopyFrame* frame);
|
||||||
void onMonitorRender(CMonitor* pMonitor);
|
|
||||||
|
|
||||||
friend class CScreencopyClient;
|
friend class CScreencopyClient;
|
||||||
};
|
};
|
|
@ -199,6 +199,10 @@ void CHyprOpenGLImpl::end() {
|
||||||
m_RenderData.mouseZoomUseMouse = true;
|
m_RenderData.mouseZoomUseMouse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CHyprOpenGLImpl::bindWlrOutputFb() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb);
|
||||||
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::initShaders() {
|
void CHyprOpenGLImpl::initShaders() {
|
||||||
GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC);
|
GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC);
|
||||||
m_RenderData.pCurrentMonData->m_shQUAD.program = prog;
|
m_RenderData.pCurrentMonData->m_shQUAD.program = prog;
|
||||||
|
|
|
@ -97,6 +97,7 @@ class CHyprOpenGLImpl {
|
||||||
|
|
||||||
void begin(CMonitor*, CRegion*, bool fake = false);
|
void begin(CMonitor*, CRegion*, bool fake = false);
|
||||||
void end();
|
void end();
|
||||||
|
void bindWlrOutputFb();
|
||||||
|
|
||||||
void renderRect(wlr_box*, const CColor&, int round = 0);
|
void renderRect(wlr_box*, const CColor&, int round = 0);
|
||||||
void renderRectWithDamage(wlr_box*, const CColor&, CRegion* damage, int round = 0);
|
void renderRectWithDamage(wlr_box*, const CColor&, CRegion* damage, int round = 0);
|
||||||
|
|
Loading…
Reference in a new issue