mirror of https://github.com/hyprwm/Hyprland
buggy frame scheduler ugh
This commit is contained in:
parent
63e3668529
commit
e5f379cd40
|
@ -13,6 +13,8 @@
|
|||
#include <ranges>
|
||||
#include "helpers/VarList.hpp"
|
||||
|
||||
#include "managers/FrameSchedulingManager.hpp"
|
||||
|
||||
int handleCritSignal(int signo, void* data) {
|
||||
Debug::log(LOG, "Hyprland received signal {}", signo);
|
||||
|
||||
|
@ -520,6 +522,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
|||
|
||||
Debug::log(LOG, "Creating the CursorManager!");
|
||||
g_pCursorManager = std::make_unique<CCursorManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the FrameSchedulingManager!");
|
||||
g_pFrameSchedulingManager = std::make_unique<CFrameSchedulingManager>();
|
||||
} break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
@ -2375,7 +2380,10 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
|
|||
if (pMonitor->renderingActive)
|
||||
pMonitor->pendingFrame = true;
|
||||
|
||||
wlr_output_schedule_frame(pMonitor->output);
|
||||
if (!pMonitor->frameNeededSource)
|
||||
return;
|
||||
|
||||
wl_event_source_timer_update(pMonitor->frameNeededSource, 1);
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace Events {
|
|||
DYNLISTENFUNC(monitorNeedsFrame);
|
||||
DYNLISTENFUNC(monitorCommit);
|
||||
DYNLISTENFUNC(monitorBind);
|
||||
DYNLISTENFUNC(monitorPresent);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Events.hpp"
|
||||
#include "../debug/HyprCtl.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../managers/FrameSchedulingManager.hpp"
|
||||
|
||||
// --------------------------------------------------------- //
|
||||
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
|
||||
|
@ -126,34 +127,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
|||
|
||||
CMonitor* const PMONITOR = (CMonitor*)owner;
|
||||
|
||||
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
||||
|
||||
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
|
||||
return m->output != g_pCompositor->m_pUnsafeOutput->output;
|
||||
})) {
|
||||
// restore from unsafe state
|
||||
g_pCompositor->leaveUnsafeState();
|
||||
}
|
||||
|
||||
return; // cannot draw on session inactive (different tty)
|
||||
}
|
||||
|
||||
if (!PMONITOR->m_bEnabled)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
|
||||
|
||||
PMONITOR->tearingState.busy = false;
|
||||
|
||||
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
|
||||
|
||||
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
|
||||
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
|
||||
|
||||
PMONITOR->tearingState.nextRenderTorn = true;
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = false;
|
||||
}
|
||||
return; // TODO: remove completely
|
||||
|
||||
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
|
||||
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
|
||||
|
@ -260,3 +234,8 @@ void Events::listener_monitorCommit(void* owner, void* data) {
|
|||
void Events::listener_monitorBind(void* owner, void* data) {
|
||||
;
|
||||
}
|
||||
|
||||
void Events::listener_monitorPresent(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
g_pFrameSchedulingManager->onPresent(PMONITOR);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,26 @@
|
|||
#include "MiscFunctions.hpp"
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/FrameSchedulingManager.hpp"
|
||||
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
int ratHandler(void* data) {
|
||||
static int ratHandler(void* data) {
|
||||
g_pHyprRenderer->renderMonitor((CMonitor*)data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wlFrameCallback(void* data) {
|
||||
const auto PMONITOR = (CMonitor*)data;
|
||||
|
||||
Debug::log(LOG, "wlFrameCallback");
|
||||
|
||||
g_pFrameSchedulingManager->onFrameNeeded(PMONITOR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
CMonitor::CMonitor() : state(this) {
|
||||
wlr_damage_ring_init(&damage);
|
||||
}
|
||||
|
@ -25,6 +36,7 @@ CMonitor::~CMonitor() {
|
|||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorPresent.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
}
|
||||
|
||||
|
@ -36,6 +48,7 @@ void CMonitor::onConnect(bool noRule) {
|
|||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
hyprListener_monitorPresent.removeCallback();
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
|
||||
|
@ -43,6 +56,7 @@ void CMonitor::onConnect(bool noRule) {
|
|||
hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this);
|
||||
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
||||
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
|
||||
hyprListener_monitorPresent.initCallback(&output->events.present, &Events::listener_monitorPresent, this);
|
||||
|
||||
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||
|
||||
|
@ -211,9 +225,12 @@ void CMonitor::onConnect(bool noRule) {
|
|||
if (!found)
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||
frameNeededSource = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, wlFrameCallback, this);
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
|
||||
g_pFrameSchedulingManager->registerMonitor(this);
|
||||
}
|
||||
|
||||
void CMonitor::onDisconnect(bool destroy) {
|
||||
|
@ -223,6 +240,8 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
renderTimer = nullptr;
|
||||
}
|
||||
|
||||
g_pFrameSchedulingManager->unregisterMonitor(this);
|
||||
|
||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
|
@ -256,6 +275,7 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
hyprListener_monitorPresent.removeCallback();
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
for (auto& ls : m_aLayerSurfaceLayers[i]) {
|
||||
|
|
|
@ -98,8 +98,9 @@ class CMonitor {
|
|||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
wl_event_source* frameNeededSource = nullptr; // for ::scheduleFrameForMonitor
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
|
||||
SMonitorRule activeMonitorRule;
|
||||
|
@ -129,6 +130,7 @@ class CMonitor {
|
|||
DYNLISTENER(monitorNeedsFrame);
|
||||
DYNLISTENER(monitorCommit);
|
||||
DYNLISTENER(monitorBind);
|
||||
DYNLISTENER(monitorPresent);
|
||||
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
|
||||
CEventManager::CEventManager() {}
|
||||
|
||||
int fdHandleWrite(int fd, uint32_t mask, void* data) {
|
||||
static int fdHandleWrite(int fd, uint32_t mask, void* data) {
|
||||
const auto PEVMGR = (CEventManager*)data;
|
||||
return PEVMGR->onFDWrite(fd, mask);
|
||||
}
|
||||
|
||||
int socket2HandleWrite(int fd, uint32_t mask, void* data) {
|
||||
static int socket2HandleWrite(int fd, uint32_t mask, void* data) {
|
||||
const auto PEVMGR = (CEventManager*)data;
|
||||
return PEVMGR->onSocket2Write(fd, mask);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
#include "FrameSchedulingManager.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
int onPresentTimer(void* data) {
|
||||
return g_pFrameSchedulingManager->onVblankTimer(data);
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::registerMonitor(CMonitor* pMonitor) {
|
||||
if (dataFor(pMonitor)) {
|
||||
Debug::log(ERR, "BUG THIS: Attempted to double register to CFrameSchedulingManager");
|
||||
return;
|
||||
}
|
||||
|
||||
SSchedulingData* DATA = &m_vSchedulingData.emplace_back(SSchedulingData{pMonitor});
|
||||
DATA->event = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, onPresentTimer, DATA);
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::unregisterMonitor(CMonitor* pMonitor) {
|
||||
std::erase_if(m_vSchedulingData, [pMonitor](const auto& d) { return d.pMonitor == pMonitor; });
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::onFrameNeeded(CMonitor* pMonitor) {
|
||||
const auto DATA = dataFor(pMonitor);
|
||||
|
||||
RASSERT(DATA, "No data in gpuDone");
|
||||
|
||||
if (pMonitor->output->frame_pending || pMonitor->tearingState.activelyTearing)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "onFrameNeeded");
|
||||
|
||||
onPresent(pMonitor);
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::gpuDone(wlr_buffer* pBuffer) {
|
||||
const auto DATA = dataFor(pBuffer);
|
||||
|
||||
RASSERT(DATA, "No data in gpuDone");
|
||||
|
||||
if (!DATA->delayed)
|
||||
return;
|
||||
|
||||
// delayed frame, let's render immediately, our shit will be presented soon
|
||||
// if we finish rendering before the next vblank somehow, kernel will be mad, but oh well
|
||||
DATA->gpuDoneCall = true;
|
||||
g_pHyprRenderer->renderMonitor(DATA->pMonitor);
|
||||
DATA->delayedFrameSubmitted = true;
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::registerBuffer(wlr_buffer* pBuffer, CMonitor* pMonitor) {
|
||||
const auto DATA = dataFor(pMonitor);
|
||||
|
||||
RASSERT(DATA, "No data in registerBuffer");
|
||||
|
||||
if (std::find(DATA->buffers.begin(), DATA->buffers.end(), pBuffer) != DATA->buffers.end())
|
||||
return;
|
||||
|
||||
DATA->buffers.push_back(pBuffer);
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::dropBuffer(wlr_buffer* pBuffer) {
|
||||
for (auto& d : m_vSchedulingData) {
|
||||
std::erase(d.buffers, pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::onPresent(CMonitor* pMonitor) {
|
||||
const auto DATA = dataFor(pMonitor);
|
||||
|
||||
RASSERT(DATA, "No data in onPresent");
|
||||
|
||||
if (pMonitor->tearingState.activelyTearing) {
|
||||
DATA->activelyPushing = false;
|
||||
return; // don't render
|
||||
}
|
||||
|
||||
if (DATA->delayedFrameSubmitted) {
|
||||
DATA->delayedFrameSubmitted = false;
|
||||
DATA->activelyPushing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "onPresent");
|
||||
|
||||
int forceFrames = DATA->forceFrames + pMonitor->forceFullFrames;
|
||||
|
||||
DATA->lastPresent.reset();
|
||||
|
||||
// reset state, request a render if necessary
|
||||
DATA->delayed = false;
|
||||
if (DATA->forceFrames > 0)
|
||||
DATA->forceFrames--;
|
||||
DATA->rendered = false;
|
||||
DATA->gpuReady = false;
|
||||
DATA->activelyPushing = true;
|
||||
|
||||
// check if there is damage
|
||||
bool hasDamage = pixman_region32_not_empty(&pMonitor->damage.current);
|
||||
if (!hasDamage) {
|
||||
for (int i = 0; i < WLR_DAMAGE_RING_PREVIOUS_LEN; ++i) {
|
||||
hasDamage = hasDamage || pixman_region32_not_empty(&pMonitor->damage.previous[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasDamage && forceFrames <= 0) {
|
||||
DATA->activelyPushing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "remder!");
|
||||
|
||||
// we can't do this on wayland
|
||||
if (!wlr_backend_is_wl(pMonitor->output->backend) && !DATA->gpuDoneCall) {
|
||||
const float TIMEUNTILVBLANK = 1000.0 / pMonitor->refreshRate;
|
||||
wl_event_source_timer_update(DATA->event, 0);
|
||||
wl_event_source_timer_update(DATA->event, std::floor(TIMEUNTILVBLANK));
|
||||
}
|
||||
|
||||
renderMonitor(DATA);
|
||||
|
||||
DATA->gpuDoneCall = false;
|
||||
}
|
||||
|
||||
CFrameSchedulingManager::SSchedulingData* CFrameSchedulingManager::dataFor(CMonitor* pMonitor) {
|
||||
for (auto& d : m_vSchedulingData) {
|
||||
if (d.pMonitor == pMonitor)
|
||||
return &d;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFrameSchedulingManager::SSchedulingData* CFrameSchedulingManager::dataFor(wlr_buffer* pBuffer) {
|
||||
for (auto& d : m_vSchedulingData) {
|
||||
if (std::find(d.buffers.begin(), d.buffers.end(), pBuffer) != d.buffers.end())
|
||||
return &d;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CFrameSchedulingManager::renderMonitor(SSchedulingData* data) {
|
||||
CMonitor* pMonitor = data->pMonitor;
|
||||
|
||||
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Attempted to render frame on inactive session!");
|
||||
|
||||
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
|
||||
return m->output != g_pCompositor->m_pUnsafeOutput->output;
|
||||
})) {
|
||||
// restore from unsafe state
|
||||
g_pCompositor->leaveUnsafeState();
|
||||
}
|
||||
|
||||
return; // cannot draw on session inactive (different tty)
|
||||
}
|
||||
|
||||
if (!pMonitor->m_bEnabled)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->recheckSolitaryForMonitor(pMonitor);
|
||||
|
||||
pMonitor->tearingState.busy = false;
|
||||
|
||||
if (pMonitor->tearingState.activelyTearing && pMonitor->solitaryClient /* can be invalidated by a recheck */) {
|
||||
|
||||
if (!pMonitor->tearingState.frameScheduledWhileBusy)
|
||||
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
|
||||
|
||||
pMonitor->tearingState.nextRenderTorn = true;
|
||||
pMonitor->tearingState.frameScheduledWhileBusy = false;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->renderMonitor(pMonitor);
|
||||
data->rendered = true;
|
||||
}
|
||||
|
||||
int CFrameSchedulingManager::onVblankTimer(void* data) {
|
||||
auto DATA = (SSchedulingData*)data;
|
||||
|
||||
if (DATA->rendered && DATA->gpuReady) {
|
||||
// cool, we don't need to do anything. Wait for present.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DATA->rendered && !DATA->gpuReady) {
|
||||
// we missed a vblank :(
|
||||
DATA->delayed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// what the fuck?
|
||||
Debug::log(ERR, "Vblank timer fired without a frame????");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "../helpers/Timer.hpp"
|
||||
|
||||
class CMonitor;
|
||||
struct wlr_buffer;
|
||||
|
||||
class CFrameSchedulingManager {
|
||||
public:
|
||||
void registerMonitor(CMonitor* pMonitor);
|
||||
void unregisterMonitor(CMonitor* pMonitor);
|
||||
|
||||
void gpuDone(wlr_buffer* pBuffer);
|
||||
void registerBuffer(wlr_buffer* pBuffer, CMonitor* pMonitor);
|
||||
void dropBuffer(wlr_buffer* pBuffer);
|
||||
|
||||
void onFrameNeeded(CMonitor* pMonitor);
|
||||
|
||||
void onPresent(CMonitor* pMonitor);
|
||||
|
||||
int onVblankTimer(void* data);
|
||||
|
||||
private:
|
||||
struct SSchedulingData {
|
||||
CMonitor* pMonitor = nullptr;
|
||||
|
||||
// CPU frame rendering has been finished
|
||||
bool rendered = false;
|
||||
|
||||
// GPU frame rendering has been finished
|
||||
bool gpuReady = false;
|
||||
|
||||
// GPU didn't manage to render last frame in time.
|
||||
// we got a vblank before we got a gpuDone()
|
||||
bool delayed = false;
|
||||
|
||||
// whether the frame was submitted from gpuDone
|
||||
bool delayedFrameSubmitted = false;
|
||||
|
||||
// whether this call comes from gpuDone
|
||||
bool gpuDoneCall = false;
|
||||
|
||||
// we need to render a few full frames at the beginning to catch all buffers
|
||||
int forceFrames = 5;
|
||||
|
||||
// last present timer
|
||||
CTimer lastPresent;
|
||||
|
||||
// buffers associated with this monitor
|
||||
std::vector<wlr_buffer*> buffers;
|
||||
|
||||
// event source for the vblank timer
|
||||
wl_event_source* event = nullptr;
|
||||
|
||||
// whether we're actively pushing frames
|
||||
bool activelyPushing = false;
|
||||
};
|
||||
|
||||
std::vector<SSchedulingData> m_vSchedulingData;
|
||||
|
||||
SSchedulingData* dataFor(CMonitor* pMonitor);
|
||||
SSchedulingData* dataFor(wlr_buffer* pBuffer);
|
||||
|
||||
void renderMonitor(SSchedulingData* data);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CFrameSchedulingManager> g_pFrameSchedulingManager;
|
|
@ -1,6 +1,7 @@
|
|||
#include "Renderbuffer.hpp"
|
||||
#include "OpenGL.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/FrameSchedulingManager.hpp"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
@ -15,9 +16,24 @@ CRenderbuffer::~CRenderbuffer() {
|
|||
glDeleteRenderbuffers(1, &m_iRBO);
|
||||
|
||||
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
|
||||
|
||||
wl_event_source_remove(m_pFDWrite);
|
||||
|
||||
g_pFrameSchedulingManager->dropBuffer(m_pWlrBuffer);
|
||||
}
|
||||
|
||||
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer) {
|
||||
static int fdHandleWrite(int fd, uint32_t mask, void* data) {
|
||||
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
|
||||
return 0;
|
||||
|
||||
const auto RB = (CRenderbuffer*)data;
|
||||
|
||||
g_pFrameSchedulingManager->gpuDone(RB->m_pWlrBuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format, CMonitor* pMonitor) : m_pWlrBuffer(buffer), m_pMonitor(pMonitor) {
|
||||
|
||||
// EVIL, but we can't include a hidden header because nixos is fucking special
|
||||
static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*);
|
||||
|
@ -58,7 +74,20 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
hyprListener_destroyBuffer.initCallback(
|
||||
&buffer->events.destroy, [](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy((CRenderbuffer*)owner); }, this, "CRenderbuffer");
|
||||
&buffer->events.destroy,
|
||||
[](void* owner, void* data) {
|
||||
const auto RB = (CRenderbuffer*)owner;
|
||||
g_pHyprRenderer->onRenderbufferDestroy(RB);
|
||||
g_pFrameSchedulingManager->dropBuffer(RB->m_pWlrBuffer);
|
||||
},
|
||||
this, "CRenderbuffer");
|
||||
|
||||
wlr_dmabuf_attributes attrs = {0};
|
||||
wlr_buffer_get_dmabuf(m_pWlrBuffer, &attrs);
|
||||
|
||||
m_pFDWrite = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, attrs.fd[0], WL_EVENT_READABLE, fdHandleWrite, this);
|
||||
|
||||
g_pFrameSchedulingManager->registerBuffer(m_pWlrBuffer, pMonitor);
|
||||
}
|
||||
|
||||
void CRenderbuffer::bind() {
|
||||
|
|
|
@ -6,7 +6,7 @@ class CMonitor;
|
|||
|
||||
class CRenderbuffer {
|
||||
public:
|
||||
CRenderbuffer(wlr_buffer* buffer, uint32_t format);
|
||||
CRenderbuffer(wlr_buffer* buffer, uint32_t format, CMonitor* pMonitor);
|
||||
~CRenderbuffer();
|
||||
|
||||
void bind();
|
||||
|
@ -22,4 +22,6 @@ class CRenderbuffer {
|
|||
EGLImageKHR m_iImage = 0;
|
||||
GLuint m_iRBO = 0;
|
||||
CFramebuffer m_sFramebuffer;
|
||||
CMonitor* m_pMonitor = nullptr;
|
||||
wl_event_source* m_pFDWrite = nullptr;
|
||||
};
|
|
@ -1063,6 +1063,7 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
|||
}
|
||||
|
||||
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();
|
||||
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
|
||||
|
@ -2273,6 +2274,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
|||
|
||||
Events::listener_change(nullptr, nullptr);
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(pMonitor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2585,13 +2588,13 @@ void CHyprRenderer::renderSoftwareCursors(CMonitor* pMonitor, const CRegion& dam
|
|||
}
|
||||
}
|
||||
|
||||
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) {
|
||||
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt, CMonitor* pMonitor) {
|
||||
auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; });
|
||||
|
||||
if (it != m_vRenderbuffers.end())
|
||||
return it->get();
|
||||
|
||||
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
|
||||
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt, pMonitor)).get();
|
||||
}
|
||||
|
||||
void CHyprRenderer::makeEGLCurrent() {
|
||||
|
@ -2636,7 +2639,7 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
|
|||
m_pCurrentWlrBuffer = wlr_buffer_lock(buffer);
|
||||
|
||||
try {
|
||||
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
|
||||
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat, pMonitor);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName);
|
||||
wlr_buffer_unlock(m_pCurrentWlrBuffer);
|
||||
|
|
|
@ -135,7 +135,8 @@ class CHyprRenderer {
|
|||
bool hiddenOnKeyboard = false;
|
||||
} m_sCursorHiddenConditions;
|
||||
|
||||
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
|
||||
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt, CMonitor* pMonitor);
|
||||
|
||||
std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
|
||||
|
||||
friend class CHyprOpenGLImpl;
|
||||
|
|
Loading…
Reference in New Issue