From 016da234d0e852de3ef20eb2e89ac58d2a85f6e7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:09:54 +0200 Subject: Core: Move to aquamarine (#6608) Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry Co-authored-by: Mihai Fufezan Co-authored-by: Jan Beich Co-authored-by: vaxerski Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo --- src/render/Renderer.cpp | 597 +++++++++++++++++++++++++----------------------- 1 file changed, 305 insertions(+), 292 deletions(-) (limited to 'src/render/Renderer.cpp') diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a7f3c941..82dfc887 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2,6 +2,8 @@ #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" #include +#include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -13,6 +15,10 @@ #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/DRMSyncobj.hpp" +#include "../protocols/LinuxDMABUF.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "debug/Log.hpp" extern "C" { #include @@ -25,11 +31,11 @@ static int cursorTicker(void* data) { } CHyprRenderer::CHyprRenderer() { - if (g_pCompositor->m_sWLRSession) { - wlr_device* dev; - wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) { - const auto DRMV = drmGetVersion(dev->fd); - + if (g_pCompositor->m_pAqBackend->hasSession()) { + for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { + const auto DRMV = drmGetVersion(dev->fd); + if (!DRMV) + continue; std::string name = std::string{DRMV->name, DRMV->name_len}; std::transform(name.begin(), name.end(), name.begin(), tolower); @@ -42,7 +48,7 @@ CHyprRenderer::CHyprRenderer() { drmFreeVersion(DRMV); } } else { - Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks"); + Debug::log(LOG, "Aq backend has no session, omitting full DRM node checks"); const auto DRMV = drmGetVersion(g_pCompositor->m_iDRMFD); @@ -108,6 +114,14 @@ static void renderSurface(SP surface, int x, int y, void* da if (!TEXTURE->m_iTexID) return; + // explicit sync: wait for the timeline, if any + if (surface->syncobj && surface->syncobj->acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); + return; + } + } + TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; @@ -167,12 +181,10 @@ static void renderSurface(SP surface, int x, int y, void* da if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->discarded(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for invisible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } + return; // invisible } @@ -225,11 +237,8 @@ static void renderSurface(SP surface, int x, int y, void* da } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->presented(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for visible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } g_pHyprOpenGL->blend(true); @@ -1079,53 +1088,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPmirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - - // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - // return false; - - // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - - // if (!PCANDIDATE) - // return false; - - // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - - // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - // return false; - - // // finally, we should be GTG. - // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - - // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - // return false; - - // timespec now; - // clock_gettime(CLOCK_MONOTONIC, &now); - // PSURFACE->frame(&now); - // auto FEEDBACK = makeShared(PSURFACE); - // FEEDBACK->attachMonitor(pMonitor); - // FEEDBACK->presented(); - // FEEDBACK->setPresentationType(true); - // PROTO::presentation->queueData(FEEDBACK); - - // if (pMonitor->state.commit()) { - // if (m_pLastScanout.expired()) { - // m_pLastScanout = PCANDIDATE; - // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - // } - // } else { - // m_pLastScanout.reset(); - // return false; - // } - - // return true; -} - void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now(); @@ -1177,7 +1139,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->framesToSkip -= 1; if (!pMonitor->noFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); else Debug::log(LOG, "NoFrameSchedule hit for {}.", pMonitor->szName); @@ -1205,6 +1167,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); } + if (!pMonitor->output->needsFrame && pMonitor->forceFullFrames == 0) + return; + // tearing and DS first bool shouldTear = false; if (pMonitor->tearingState.nextRenderTorn) { @@ -1230,11 +1195,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (!*PNODIRECTSCANOUT && !shouldTear) { - if (attemptDirectScanout(pMonitor)) { + if (pMonitor->attemptDirectScanout()) { return; - } else if (!m_pLastScanout.expired()) { + } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); - m_pLastScanout.reset(); + pMonitor->lastScanout.reset(); } } @@ -1249,7 +1214,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { clock_gettime(CLOCK_MONOTONIC, &now); // check the damage - bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged(); + bool hasChanged = pMonitor->output->needsFrame || pMonitor->damage.hasChanged(); if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) return; @@ -1295,7 +1260,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); - pMonitor->state.clear(); return; } @@ -1316,11 +1280,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. // now, prep the damage, get the extended damage region - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring + damage.expand(BLURRADIUS); // expand for proper blurring finalDamage = damage; - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring 2 + damage.expand(BLURRADIUS); // expand for proper blurring } else finalDamage = damage; } @@ -1396,10 +1360,10 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { - CRegion frameDamage{}; + CRegion frameDamage{finalDamage}; - const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform); - wlr_region_transform(frameDamage.pixman(), finalDamage.pixman(), TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); + const auto TRANSFORM = invertTransform(pMonitor->transform); + frameDamage.transform(wlTransformToHyprutils(TRANSFORM), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR) frameDamage.add(0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); @@ -1414,18 +1378,16 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { EMIT_HOOK_EVENT("render", RENDER_POST); - pMonitor->state.wlr()->tearing_page_flip = shouldTear; + pMonitor->output->state->setPresentationMode(shouldTear ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : + Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!pMonitor->state.commit()) { - pMonitor->damage.damageEntire(); - return; - } + commitPendingAndDoExplicitSync(pMonitor); if (shouldTear) pMonitor->tearingState.busy = true; if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); pMonitor->pendingFrame = false; @@ -1442,6 +1404,63 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } +bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + // apply timelines for explicit sync + pMonitor->output->state->resetExplicitFences(); + + bool anyExplicit = !explicitPresented.empty(); + if (anyExplicit) { + Debug::log(TRACE, "Explicit sync presented begin"); + auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); + if (inFence < 0) + Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); + + pMonitor->output->state->setExplicitInFence(inFence); + + for (auto& e : explicitPresented) { + Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); + if (!e->syncobj || !e->syncobj->releaseTimeline) + continue; + e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); + } + + explicitPresented.clear(); + auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); + if (outFence < 0) + Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); + + pMonitor->output->state->setExplicitOutFence(outFence); + Debug::log(TRACE, "Explicit sync presented end"); + } + + pMonitor->lastWaitPoint = 0; + + bool ok = pMonitor->state.commit(); + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } + + if (!*PENABLEEXPLICIT) + return ok; + + if (pMonitor->output->state->state().explicitInFence >= 0) + close(pMonitor->output->state->state().explicitInFence); + + if (pMonitor->output->state->state().explicitOutFence >= 0) { + if (ok) + pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + close(pMonitor->output->state->state().explicitOutFence); + } + + return ok; +} + void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { Vector2D translate = {geometry.x, geometry.y}; float scale = (float)geometry.width / pMonitor->vecPixelSize.x; @@ -1480,33 +1499,11 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE } } -void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - // FIXME: fix when moved to new impl - // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - // return; - - // if (!pWindow->m_bIsFullscreen) { - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); - // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - // return; - // } - - // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - - // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - // .main_renderer = g_pCompositor->m_sWLRRenderer, - // .scanout_primary_output = PMONITOR->output, - // }; - - // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - - // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - // return; - - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); - // wlr_linux_dmabuf_feedback_v1_finish(&feedback); +void CHyprRenderer::setSurfaceScanoutMode(SP surface, SP monitor) { + if (!PROTO::linuxDma) + return; - // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + PROTO::linuxDma->updateScanoutTranche(surface, monitor); } // taken from Sway. @@ -1572,7 +1569,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorvecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { - if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) + if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) continue; const auto PLAYER = ls->layerSurface; @@ -1708,7 +1705,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou damageBox.scale(scale); // schedule frame events - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); if (damageBox.empty()) return; @@ -1820,13 +1817,13 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2; monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; - wlr_region_scale(transformed.pixman(), transformed.pixman(), scale); + transformed.scale(scale); transformed.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale); transformed.translate(Vector2D(monbox.x, monbox.y)); mirror->addDamage(&transformed); - g_pCompositor->scheduleFrameForMonitor(mirror); + g_pCompositor->scheduleFrameForMonitor(mirror, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } } @@ -1869,7 +1866,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // don't touch VR headsets - if (pMonitor->output->non_desktop) + if (pMonitor->output->nonDesktop) return true; if (!pMonitor->m_bEnabled) { @@ -1900,7 +1897,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // Needed in case we are switching from a custom modeline to a standard mode pMonitor->customDrmMode = {}; pMonitor->currentMode = nullptr; - bool autoScale = false; + + pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + + bool autoScale = false; if (RULE->scale > 0.1) { pMonitor->scale = RULE->scale; @@ -1910,38 +1910,35 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->scale = DEFAULTSCALE; } - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - pMonitor->setScale = pMonitor->scale; - - wlr_output_state_set_transform(pMonitor->state.wlr(), RULE->transform); + pMonitor->setScale = pMonitor->scale; pMonitor->transform = RULE->transform; - const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : RULE->refreshRate * 1000; + const auto WLRREFRESHRATE = pMonitor->output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0; // loop over modes and choose an appropriate one. if (RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) { - if (!wl_list_empty(&pMonitor->output->modes) && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { - wlr_output_mode* mode; - bool found = false; + if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { + bool found = false; - wl_list_for_each(mode, &pMonitor->output->modes, link) { + for (auto& mode : pMonitor->output->modes) { // if delta of refresh rate, w and h chosen and mode is < 1 we accept it - if (DELTALESSTHAN(mode->width, RULE->resolution.x, 1) && DELTALESSTHAN(mode->height, RULE->resolution.y, 1) && - DELTALESSTHAN(mode->refresh / 1000.f, RULE->refreshRate, 1)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) && + DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) { + pMonitor->output->state->setMode(mode); - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); found = true; - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -1949,14 +1946,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!found) { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (!pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, @@ -1965,13 +1962,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); @@ -1982,30 +1979,30 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR bool fail = false; if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) { - if (!wlr_output_is_drm(pMonitor->output)) { + if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) { Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); fail = true; } else { - auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); - if (mode) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - pMonitor->customDrmMode = RULE->drmMode; - } else { - Debug::log(ERR, "wlr_drm_connector_add_mode failed"); - fail = true; - } + // FIXME: + // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); + // if (mode) { + // wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + // pMonitor->customDrmMode = RULE->drmMode; + // } else { + // Debug::log(ERR, "wlr_drm_connector_add_mode failed"); + // fail = true; + // } } - } else { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); - } + } else + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (fail || !pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->output->name, RULE->resolution, @@ -2014,48 +2011,47 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->customDrmMode = {}; - } else { + } else Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); - } } } else if (RULE->resolution != Vector2D()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - float currentWidth = 0; - float currentHeight = 0; - float currentRefresh = 0; - bool success = false; + if (!pMonitor->output->modes.empty()) { + float currentWidth = 0; + float currentHeight = 0; + float currentRefresh = 0; + bool success = false; //(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution if (RULE->resolution == Vector2D(-1, -1)) { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + mode->refreshRate > (currentRefresh + 3000.f)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } } } else { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || - (mode->width > currentWidth && mode->height > currentHeight)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } @@ -2063,10 +2059,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!success) { - Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh / 1000.f); + if (pMonitor->output->state->state().mode) + Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, + (float)RULE->refreshRate, pMonitor->output->state->state().mode->pixelSize.x, pMonitor->output->state->state().mode->pixelSize.y, + pMonitor->output->state->state().mode->refreshRate / 1000.f); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, (float)RULE->refreshRate); @@ -2074,13 +2072,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { @@ -2091,27 +2089,26 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } } else { - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + if (!pMonitor->output->modes.empty()) { + for (auto& mode : pMonitor->output->modes) { + pMonitor->output->state->setMode(mode); - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -2119,21 +2116,49 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } else { // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; pMonitor->currentMode = PREFERREDMODE; Debug::log(LOG, "Setting preferred mode for {}", pMonitor->output->name); } } - pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR() - || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync + pMonitor->vrrActive = pMonitor->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR() + || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync pMonitor->vecPixelSize = pMonitor->vecSize; + // clang-format off + static const std::array>, 2> formats{ + std::vector>{ /* 10-bit */ + {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + }, + std::vector>{ /* 8-bit */ + {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + } + }; + // clang-format on + + bool set10bit = false; + + for (auto& fmt : formats[(int)!RULE->enable10bit]) { + pMonitor->output->state->setFormat(fmt.second); + + if (!pMonitor->state.test()) { + Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); + } else { + Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); + if (RULE->enable10bit && fmt.first.contains("101010")) + set10bit = true; + break; + } + } + + pMonitor->enabled10bit = set10bit; + Vector2D logicalSize = pMonitor->vecPixelSize / pMonitor->scale; if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { // invalid scale, will produce fractional pixels. @@ -2145,10 +2170,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR double scaleZero = searchScale / 120.0; Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero; - if (logicalZero == logicalZero.round()) { + if (logicalZero == logicalZero.round()) pMonitor->scale = scaleZero; - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - } else { + else { for (size_t i = 1; i < 90; ++i) { double scaleUp = (searchScale + i) / 120.0; double scaleDown = (searchScale - i) / 120.0; @@ -2185,57 +2209,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } else pMonitor->scale = searchScale; } - - // for wlroots, that likes flooring, we have to do this. - double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale); - logicalX += 0.1; - - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX); - } - } - - // clang-format off - static const std::array>, 2> formats{ - std::vector>{ /* 10-bit */ - {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - }, - std::vector>{ /* 8-bit */ - {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - } - }; - // clang-format on - - bool set10bit = false; - pMonitor->drmFormat = DRM_FORMAT_INVALID; - - for (auto& fmt : formats[(int)!RULE->enable10bit]) { - wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second); - - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); - } else { - Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); - if (RULE->enable10bit && fmt.first.contains("101010")) - set10bit = true; - - pMonitor->drmFormat = fmt.second; - break; } } - pMonitor->enabled10bit = set10bit; + pMonitor->output->scheduleFrame(); if (!pMonitor->state.commit()) Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name); - int x, y; - wlr_output_transformed_resolution(pMonitor->output, &x, &y); - pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).round(); - pMonitor->vecTransformedSize = Vector2D(x, y); + Vector2D xfmd = pMonitor->transform % 2 == 1 ? Vector2D{pMonitor->vecPixelSize.y, pMonitor->vecPixelSize.x} : pMonitor->vecPixelSize; + pMonitor->vecSize = (xfmd / pMonitor->scale).round(); + pMonitor->vecTransformedSize = xfmd; if (pMonitor->createdByUser) { CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + transformedBox.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); } @@ -2245,7 +2233,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize) g_pHyprOpenGL->destroyMonitorResources(pMonitor); - // updato wlroots g_pCompositor->arrangeMonitors(); pMonitor->damage.setSize(pMonitor->vecTransformedSize); @@ -2260,9 +2247,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // updato us arrangeLayersForMonitor(pMonitor->ID); - // frame skip - pMonitor->framesToSkip = 1; - // reload to fix mirrors g_pConfigManager->m_bWantsMonitorReload = true; @@ -2329,7 +2313,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Hiding the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2341,7 +2325,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Showing the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2570,37 +2554,37 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient = PCANDIDATE; } -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) { - auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; }); +SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { + auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); if (it != m_vRenderbuffers.end()) - return it->get(); + return *it; - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); -} + auto buf = makeShared(buffer, fmt); -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { - auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); - - if (it != m_vRenderbuffers.end()) - return it->get(); + if (!buf->good()) + return nullptr; - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); + m_vRenderbuffers.emplace_back(buf); + return buf; } void CHyprRenderer::makeEGLCurrent() { - if (!g_pCompositor) + if (!g_pCompositor || !g_pHyprOpenGL) return; - if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)); + if (eglGetCurrentContext() != g_pHyprOpenGL->m_pEglContext) + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_pHyprOpenGL->m_pEglContext); } void CHyprRenderer::unsetEGL() { - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!g_pHyprOpenGL) + return; + + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2618,35 +2602,33 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return true; } - int bufferAge = 0; + /* This is a constant expression, as we always use double-buffering in our swapchain + TODO: Rewrite the CDamageRing to take advantage of that maybe? It's made to support longer swapchains atm because we used to do wlroots */ + static constexpr const int HL_BUFFER_AGE = 2; if (!buffer) { - if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) { - Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName); - return false; - } - - m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge); - if (!m_pCurrentWlrBuffer) { + m_pCurrentBuffer = pMonitor->output->swapchain->next(nullptr); + if (!m_pCurrentBuffer) { Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName); return false; } } else - m_pCurrentHLBuffer = buffer; + m_pCurrentBuffer = buffer; try { - if (m_pCurrentWlrBuffer) - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); - else - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentBuffer, pMonitor->output->state->state().drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); - wlr_buffer_unlock(m_pCurrentWlrBuffer); + return false; + } + + if (!m_pCurrentRenderbuffer) { + Debug::log(ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->szName); return false; } if (mode == RENDER_MODE_NORMAL) { - damage = pMonitor->damage.getBufferDamage(bufferAge); + damage = pMonitor->damage.getBufferDamage(HL_BUFFER_AGE); pMonitor->damage.rotate(); } @@ -2662,6 +2644,9 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + PMONITOR->commitSeq++; if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); @@ -2674,29 +2659,57 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_FULL_FAKE) return; - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); - else - glFlush(); - if (m_eRenderMode == RENDER_MODE_NORMAL) { - wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer); - unsetEGL(); // flush the context - } + PMONITOR->output->state->setBuffer(m_pCurrentBuffer); + + if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto sync = g_pHyprOpenGL->createEGLSync(-1); + if (!sync) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); + return; + } + + auto dupedfd = sync->dupFenceFD(); + sync.reset(); + if (dupedfd < 0) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); + return; + } - wlr_buffer_unlock(m_pCurrentWlrBuffer); + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); + close(dupedfd); + if (!ok) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); + return; + } + } else { + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); + } + } m_pCurrentRenderbuffer->unbind(); m_pCurrentRenderbuffer = nullptr; - m_pCurrentWlrBuffer = nullptr; + m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { std::erase_if(m_vRenderbuffers, [&](const auto& rbo) { return rbo.get() == rb; }); } -CRenderbuffer* CHyprRenderer::getCurrentRBO() { +SP CHyprRenderer::getCurrentRBO() { return m_pCurrentRenderbuffer; } -- cgit v1.2.3