mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 20:45:59 +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;
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<CMonitor*>(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<SScreencopyFrame*> 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!");
|
||||
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) {
|
||||
|
|
|
@ -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<SScreencopyFrame*> 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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue