toplevelexport: support dmabuf + various fixes

This commit is contained in:
vaxerski 2023-07-20 12:42:25 +02:00
parent 3a1496b4eb
commit b65adf8d4a
6 changed files with 55 additions and 21 deletions

View file

@ -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) {

View file

@ -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;

View file

@ -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!");
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) {

View file

@ -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;
};

View file

@ -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;

View file

@ -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);