mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-09 15:45:57 +01:00
use gl sync
This commit is contained in:
parent
db3259bfe4
commit
c53fcd0c80
7 changed files with 84 additions and 63 deletions
|
@ -1,9 +1,29 @@
|
||||||
#include "FrameSchedulingManager.hpp"
|
#include "FrameSchedulingManager.hpp"
|
||||||
#include "../debug/Log.hpp"
|
#include "../debug/Log.hpp"
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
|
#include "eventLoop/EventLoopManager.hpp"
|
||||||
|
|
||||||
int onPresentTimer(void* data) {
|
static void onPresentTimer(std::shared_ptr<CEventLoopTimer> self, void* data) {
|
||||||
return g_pFrameSchedulingManager->onVblankTimer(data);
|
g_pFrameSchedulingManager->onVblankTimer(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onFenceTimer(std::shared_ptr<CEventLoopTimer> self, void* data) {
|
||||||
|
g_pFrameSchedulingManager->onFenceTimer((CMonitor*)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameSchedulingManager::onFenceTimer(CMonitor* pMonitor) {
|
||||||
|
SSchedulingData* DATA = &m_vSchedulingData.emplace_back(SSchedulingData{pMonitor});
|
||||||
|
|
||||||
|
RASSERT(DATA, "No data in fenceTimer");
|
||||||
|
|
||||||
|
#ifndef GLES2
|
||||||
|
GLint syncStatus = 0;
|
||||||
|
glGetSynciv(DATA->fenceSync, GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
|
||||||
|
bool GPUSignaled = syncStatus == GL_SIGNALED;
|
||||||
|
|
||||||
|
if (GPUSignaled)
|
||||||
|
gpuDone(pMonitor);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameSchedulingManager::registerMonitor(CMonitor* pMonitor) {
|
void CFrameSchedulingManager::registerMonitor(CMonitor* pMonitor) {
|
||||||
|
@ -13,12 +33,22 @@ void CFrameSchedulingManager::registerMonitor(CMonitor* pMonitor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SSchedulingData* DATA = &m_vSchedulingData.emplace_back(SSchedulingData{pMonitor});
|
SSchedulingData* DATA = &m_vSchedulingData.emplace_back(SSchedulingData{pMonitor});
|
||||||
DATA->event = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, onPresentTimer, DATA);
|
|
||||||
|
|
||||||
|
#ifdef GLES2
|
||||||
|
DATA->legacyScheduler = true;
|
||||||
|
#else
|
||||||
DATA->legacyScheduler = !wlr_backend_is_drm(pMonitor->output->backend);
|
DATA->legacyScheduler = !wlr_backend_is_drm(pMonitor->output->backend);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DATA->fenceTimer = std::make_shared<CEventLoopTimer>(::onFenceTimer, pMonitor);
|
||||||
|
DATA->vblankTimer = std::make_shared<CEventLoopTimer>(::onPresentTimer, pMonitor);
|
||||||
|
|
||||||
|
g_pEventLoopManager->addTimer(DATA->fenceTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameSchedulingManager::unregisterMonitor(CMonitor* pMonitor) {
|
void CFrameSchedulingManager::unregisterMonitor(CMonitor* pMonitor) {
|
||||||
|
SSchedulingData* DATA = &m_vSchedulingData.emplace_back(SSchedulingData{pMonitor});
|
||||||
|
g_pEventLoopManager->removeTimer(DATA->fenceTimer);
|
||||||
std::erase_if(m_vSchedulingData, [pMonitor](const auto& d) { return d.pMonitor == pMonitor; });
|
std::erase_if(m_vSchedulingData, [pMonitor](const auto& d) { return d.pMonitor == pMonitor; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +71,8 @@ void CFrameSchedulingManager::onFrameNeeded(CMonitor* pMonitor) {
|
||||||
onPresent(pMonitor, nullptr);
|
onPresent(pMonitor, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameSchedulingManager::gpuDone(wlr_buffer* pBuffer) {
|
void CFrameSchedulingManager::gpuDone(CMonitor* pMonitor) {
|
||||||
const auto DATA = dataFor(pBuffer);
|
const auto DATA = dataFor(pMonitor);
|
||||||
|
|
||||||
Debug::log(LOG, "gpuDone");
|
Debug::log(LOG, "gpuDone");
|
||||||
|
|
||||||
|
@ -119,7 +149,6 @@ void CFrameSchedulingManager::onPresent(CMonitor* pMonitor, wlr_output_event_pre
|
||||||
if (DATA->forceFrames > 0)
|
if (DATA->forceFrames > 0)
|
||||||
DATA->forceFrames--;
|
DATA->forceFrames--;
|
||||||
DATA->rendered = false;
|
DATA->rendered = false;
|
||||||
DATA->gpuReady = false;
|
|
||||||
DATA->activelyPushing = true;
|
DATA->activelyPushing = true;
|
||||||
|
|
||||||
// check if there is damage
|
// check if there is damage
|
||||||
|
@ -138,7 +167,7 @@ void CFrameSchedulingManager::onPresent(CMonitor* pMonitor, wlr_output_event_pre
|
||||||
Debug::log(LOG, "render");
|
Debug::log(LOG, "render");
|
||||||
|
|
||||||
// we can't do this on wayland
|
// we can't do this on wayland
|
||||||
float msUntilVblank = 0;
|
float µsUntilVblank = 0;
|
||||||
|
|
||||||
if (presentationData) {
|
if (presentationData) {
|
||||||
timespec now;
|
timespec now;
|
||||||
|
@ -147,22 +176,24 @@ void CFrameSchedulingManager::onPresent(CMonitor* pMonitor, wlr_output_event_pre
|
||||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::seconds{now.tv_sec} + std::chrono::nanoseconds{now.tv_nsec}) -
|
std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::seconds{now.tv_sec} + std::chrono::nanoseconds{now.tv_nsec}) -
|
||||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::seconds{presentationData->when->tv_sec} +
|
std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::seconds{presentationData->when->tv_sec} +
|
||||||
std::chrono::nanoseconds{presentationData->when->tv_nsec})};
|
std::chrono::nanoseconds{presentationData->when->tv_nsec})};
|
||||||
msUntilVblank = (presentationData->refresh ? presentationData->refresh / 1000000.0 : pMonitor->refreshRate / 1000.0) -
|
µsUntilVblank = (presentationData->refresh ? presentationData->refresh / 1000000.0 : pMonitor->refreshRate / 1000.0) -
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(LASTVBLANK).count();
|
std::chrono::duration_cast<std::chrono::microseconds>(LASTVBLANK).count();
|
||||||
|
|
||||||
DATA->nextVblank = std::chrono::system_clock::now() + LASTVBLANK +
|
DATA->nextVblank = std::chrono::system_clock::now() + LASTVBLANK +
|
||||||
std::chrono::nanoseconds{int{presentationData->refresh ? presentationData->refresh : 1000000000 / pMonitor->refreshRate}};
|
std::chrono::nanoseconds{int{presentationData->refresh ? presentationData->refresh : 1000000000 / pMonitor->refreshRate}};
|
||||||
} else
|
} else
|
||||||
msUntilVblank = std::chrono::duration_cast<std::chrono::milliseconds>(DATA->nextVblank - std::chrono::system_clock::now()).count();
|
µsUntilVblank = std::chrono::duration_cast<std::chrono::microseconds>(DATA->nextVblank - std::chrono::system_clock::now()).count();
|
||||||
|
|
||||||
if (msUntilVblank > 0) {
|
if (µsUntilVblank > 10)
|
||||||
wl_event_source_timer_update(DATA->event, 0);
|
DATA->vblankTimer->updateTimeout(std::chrono::microseconds((long)(µsUntilVblank - 100)));
|
||||||
wl_event_source_timer_update(DATA->event, std::floor(msUntilVblank + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::log(LOG, "until vblank {:.2f}", msUntilVblank);
|
Debug::log(LOG, "until vblank {:.2f}µs", µsUntilVblank);
|
||||||
|
|
||||||
renderMonitor(DATA);
|
renderMonitor(DATA);
|
||||||
|
|
||||||
|
#ifndef GLES2
|
||||||
|
DATA->fenceSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CFrameSchedulingManager::SSchedulingData* CFrameSchedulingManager::dataFor(CMonitor* pMonitor) {
|
CFrameSchedulingManager::SSchedulingData* CFrameSchedulingManager::dataFor(CMonitor* pMonitor) {
|
||||||
|
@ -219,25 +250,33 @@ void CFrameSchedulingManager::renderMonitor(SSchedulingData* data) {
|
||||||
data->rendered = true;
|
data->rendered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CFrameSchedulingManager::onVblankTimer(void* data) {
|
void CFrameSchedulingManager::onVblankTimer(void* data) {
|
||||||
auto DATA = (SSchedulingData*)data;
|
auto DATA = (SSchedulingData*)data;
|
||||||
|
|
||||||
if (DATA->rendered && DATA->gpuReady) {
|
#ifndef GLES2
|
||||||
|
|
||||||
|
GLint syncStatus = 0;
|
||||||
|
glGetSynciv(DATA->fenceSync, GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
|
||||||
|
bool GPUSignaled = syncStatus == GL_SIGNALED;
|
||||||
|
|
||||||
|
if (DATA->rendered && GPUSignaled) {
|
||||||
Debug::log(LOG, "timer nothing");
|
Debug::log(LOG, "timer nothing");
|
||||||
// cool, we don't need to do anything. Wait for present.
|
// cool, we don't need to do anything. Wait for present.
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DATA->rendered && !DATA->gpuReady) {
|
if (DATA->rendered && !GPUSignaled) {
|
||||||
Debug::log(LOG, "timer delay");
|
Debug::log(LOG, "timer delay");
|
||||||
// we missed a vblank :(
|
// we missed a vblank :(
|
||||||
DATA->delayed = true;
|
DATA->delayed = true;
|
||||||
return 0;
|
// start the fence timer
|
||||||
|
DATA->fenceTimer->updateTimeout(std::chrono::microseconds(850));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// what the fuck?
|
// what the fuck?
|
||||||
Debug::log(ERR, "Vblank timer fired without a frame????");
|
Debug::log(ERR, "Vblank timer fired without a frame????");
|
||||||
return 0;
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFrameSchedulingManager::isMonitorUsingLegacyScheduler(CMonitor* pMonitor) {
|
bool CFrameSchedulingManager::isMonitorUsingLegacyScheduler(CMonitor* pMonitor) {
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "../helpers/Timer.hpp"
|
#include "../helpers/Timer.hpp"
|
||||||
|
#include "eventLoop/EventLoopTimer.hpp"
|
||||||
|
#ifndef GLES2
|
||||||
|
#include <GLES3/gl32.h>
|
||||||
|
#else
|
||||||
|
#define GLsync void*
|
||||||
|
#endif
|
||||||
|
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
struct wlr_buffer;
|
struct wlr_buffer;
|
||||||
|
@ -13,16 +19,17 @@ class CFrameSchedulingManager {
|
||||||
void registerMonitor(CMonitor* pMonitor);
|
void registerMonitor(CMonitor* pMonitor);
|
||||||
void unregisterMonitor(CMonitor* pMonitor);
|
void unregisterMonitor(CMonitor* pMonitor);
|
||||||
|
|
||||||
void gpuDone(wlr_buffer* pBuffer);
|
void gpuDone(CMonitor* pMonitor);
|
||||||
void registerBuffer(wlr_buffer* pBuffer, CMonitor* pMonitor);
|
void registerBuffer(wlr_buffer* pBuffer, CMonitor* pMonitor);
|
||||||
void dropBuffer(wlr_buffer* pBuffer);
|
void dropBuffer(wlr_buffer* pBuffer);
|
||||||
|
void onFenceTimer(CMonitor* pMonitor);
|
||||||
|
|
||||||
void onFrameNeeded(CMonitor* pMonitor);
|
void onFrameNeeded(CMonitor* pMonitor);
|
||||||
|
|
||||||
void onPresent(CMonitor* pMonitor, wlr_output_event_present* presentationData);
|
void onPresent(CMonitor* pMonitor, wlr_output_event_present* presentationData);
|
||||||
void onFrame(CMonitor* pMonitor);
|
void onFrame(CMonitor* pMonitor);
|
||||||
|
|
||||||
int onVblankTimer(void* data);
|
void onVblankTimer(void* data);
|
||||||
|
|
||||||
bool isMonitorUsingLegacyScheduler(CMonitor* pMonitor);
|
bool isMonitorUsingLegacyScheduler(CMonitor* pMonitor);
|
||||||
|
|
||||||
|
@ -33,9 +40,6 @@ class CFrameSchedulingManager {
|
||||||
// CPU frame rendering has been finished
|
// CPU frame rendering has been finished
|
||||||
bool rendered = false;
|
bool rendered = false;
|
||||||
|
|
||||||
// GPU frame rendering has been finished
|
|
||||||
bool gpuReady = false;
|
|
||||||
|
|
||||||
// GPU didn't manage to render last frame in time.
|
// GPU didn't manage to render last frame in time.
|
||||||
// we got a vblank before we got a gpuDone()
|
// we got a vblank before we got a gpuDone()
|
||||||
bool delayed = false;
|
bool delayed = false;
|
||||||
|
@ -52,9 +56,6 @@ class CFrameSchedulingManager {
|
||||||
// buffers associated with this monitor
|
// buffers associated with this monitor
|
||||||
std::vector<wlr_buffer*> buffers;
|
std::vector<wlr_buffer*> buffers;
|
||||||
|
|
||||||
// event source for the vblank timer
|
|
||||||
wl_event_source* event = nullptr;
|
|
||||||
|
|
||||||
// whether we're actively pushing frames
|
// whether we're actively pushing frames
|
||||||
bool activelyPushing = false;
|
bool activelyPushing = false;
|
||||||
|
|
||||||
|
@ -64,6 +65,13 @@ class CFrameSchedulingManager {
|
||||||
|
|
||||||
// next predicted vblank
|
// next predicted vblank
|
||||||
std::chrono::system_clock::time_point nextVblank;
|
std::chrono::system_clock::time_point nextVblank;
|
||||||
|
|
||||||
|
// for delayed fence stuff
|
||||||
|
std::shared_ptr<CEventLoopTimer> fenceTimer;
|
||||||
|
std::shared_ptr<CEventLoopTimer> vblankTimer;
|
||||||
|
|
||||||
|
// fence sync
|
||||||
|
GLsync fenceSync = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<SSchedulingData> m_vSchedulingData;
|
std::vector<SSchedulingData> m_vSchedulingData;
|
||||||
|
|
|
@ -13,6 +13,13 @@ CEventLoopTimer::CEventLoopTimer(std::optional<std::chrono::system_clock::durati
|
||||||
expires = std::chrono::system_clock::now() + *timeout;
|
expires = std::chrono::system_clock::now() + *timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEventLoopTimer::CEventLoopTimer(std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_,
|
||||||
|
void* data_) :
|
||||||
|
cb(cb_),
|
||||||
|
data(data_) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::duration> timeout) {
|
void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::duration> timeout) {
|
||||||
if (!timeout.has_value()) {
|
if (!timeout.has_value()) {
|
||||||
expires.reset();
|
expires.reset();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
class CEventLoopTimer {
|
class CEventLoopTimer {
|
||||||
public:
|
public:
|
||||||
CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_, void* data_);
|
CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_, void* data_);
|
||||||
|
CEventLoopTimer(std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_, void* data_);
|
||||||
|
|
||||||
// if not specified, disarms.
|
// if not specified, disarms.
|
||||||
// if specified, arms.
|
// if specified, arms.
|
||||||
|
|
|
@ -22,20 +22,6 @@ CRenderbuffer::~CRenderbuffer() {
|
||||||
g_pFrameSchedulingManager->dropBuffer(m_pWlrBuffer);
|
g_pFrameSchedulingManager->dropBuffer(m_pWlrBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (RB->hasFence())
|
|
||||||
g_pFrameSchedulingManager->gpuDone(RB->m_pWlrBuffer);
|
|
||||||
|
|
||||||
RB->removeFence();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format, CMonitor* pMonitor) : m_pWlrBuffer(buffer), m_pMonitor(pMonitor) {
|
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
|
// EVIL, but we can't include a hidden header because nixos is fucking special
|
||||||
|
@ -109,19 +95,3 @@ void CRenderbuffer::unbind() {
|
||||||
CFramebuffer* CRenderbuffer::getFB() {
|
CFramebuffer* CRenderbuffer::getFB() {
|
||||||
return &m_sFramebuffer;
|
return &m_sFramebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderbuffer::plantFence() {
|
|
||||||
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_WRITABLE, fdHandleWrite, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CRenderbuffer::removeFence() {
|
|
||||||
if (m_pFDWrite)
|
|
||||||
wl_event_source_remove(m_pFDWrite);
|
|
||||||
m_pFDWrite = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRenderbuffer::hasFence() {
|
|
||||||
return m_pFDWrite;
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,9 +13,6 @@ class CRenderbuffer {
|
||||||
void bindFB();
|
void bindFB();
|
||||||
void unbind();
|
void unbind();
|
||||||
CFramebuffer* getFB();
|
CFramebuffer* getFB();
|
||||||
void plantFence();
|
|
||||||
void removeFence();
|
|
||||||
bool hasFence();
|
|
||||||
|
|
||||||
wlr_buffer* m_pWlrBuffer = nullptr;
|
wlr_buffer* m_pWlrBuffer = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -2676,7 +2676,6 @@ void CHyprRenderer::endRender() {
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
if (m_eRenderMode == RENDER_MODE_NORMAL) {
|
if (m_eRenderMode == RENDER_MODE_NORMAL) {
|
||||||
m_pCurrentRenderbuffer->plantFence();
|
|
||||||
wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
|
wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
|
||||||
unsetEGL(); // flush the context
|
unsetEGL(); // flush the context
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue