Core: Move to aquamarine (#6608)
Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry <vaxry@vaxry.net> Co-authored-by: Mihai Fufezan <mihai@fufexan.net> Co-authored-by: Jan Beich <jbeich@FreeBSD.org> Co-authored-by: vaxerski <vaxerski@users.noreply.github.com> Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund <tomenglund26@gmail.com> Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo <diniamo53@gmail.com>
This commit is contained in:
parent
f642fb97df
commit
016da234d0
131 changed files with 4755 additions and 3460 deletions
|
|
@ -9,6 +9,9 @@
|
|||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include <xf86drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <gbm.h>
|
||||
#include <filesystem>
|
||||
|
||||
inline void loadGLProc(void* pProc, const char* name) {
|
||||
void* proc = (void*)eglGetProcAddress(name);
|
||||
|
|
@ -19,17 +22,203 @@ inline void loadGLProc(void* pProc, const char* name) {
|
|||
*(void**)pProc = proc;
|
||||
}
|
||||
|
||||
static enum LogLevel eglLogToLevel(EGLint type) {
|
||||
switch (type) {
|
||||
case EGL_DEBUG_MSG_CRITICAL_KHR: return CRIT;
|
||||
case EGL_DEBUG_MSG_ERROR_KHR: return ERR;
|
||||
case EGL_DEBUG_MSG_WARN_KHR: return WARN;
|
||||
case EGL_DEBUG_MSG_INFO_KHR: return LOG;
|
||||
default: return LOG;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* eglErrorToString(EGLint error) {
|
||||
switch (error) {
|
||||
case EGL_SUCCESS: return "EGL_SUCCESS";
|
||||
case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
|
||||
case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
|
||||
case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
|
||||
case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
|
||||
case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
|
||||
case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
|
||||
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
||||
case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
|
||||
case EGL_BAD_DEVICE_EXT: return "EGL_BAD_DEVICE_EXT";
|
||||
case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
|
||||
case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
|
||||
case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
|
||||
case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
|
||||
case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
|
||||
case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static void eglLog(EGLenum error, const char* command, EGLint type, EGLLabelKHR thread, EGLLabelKHR obj, const char* msg) {
|
||||
Debug::log(eglLogToLevel(type), "[EGL] Command {} errored out with {} (0x{}): {}", command, eglErrorToString(error), error, msg);
|
||||
}
|
||||
|
||||
static int openRenderNode(int drmFd) {
|
||||
auto renderName = drmGetRenderDeviceNameFromFd(drmFd);
|
||||
if (!renderName) {
|
||||
// This can happen on split render/display platforms, fallback to
|
||||
// primary node
|
||||
renderName = drmGetPrimaryDeviceNameFromFd(drmFd);
|
||||
if (!renderName) {
|
||||
Debug::log(ERR, "drmGetPrimaryDeviceNameFromFd failed");
|
||||
return -1;
|
||||
}
|
||||
Debug::log(LOG, "DRM dev {} has no render node, falling back to primary", renderName);
|
||||
|
||||
drmVersion* render_version = drmGetVersion(drmFd);
|
||||
if (render_version && render_version->name) {
|
||||
Debug::log(LOG, "DRM dev versionName", render_version->name);
|
||||
if (strcmp(render_version->name, "evdi") == 0) {
|
||||
free(renderName);
|
||||
renderName = (char*)malloc(sizeof(char) * 15);
|
||||
strcpy(renderName, "/dev/dri/card0");
|
||||
}
|
||||
drmFreeVersion(render_version);
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "openRenderNode got drm device {}", renderName);
|
||||
|
||||
int renderFD = open(renderName, O_RDWR | O_CLOEXEC);
|
||||
if (renderFD < 0)
|
||||
Debug::log(ERR, "openRenderNode failed to open drm device {}", renderName);
|
||||
|
||||
free(renderName);
|
||||
return renderFD;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::initEGL(bool gbm) {
|
||||
std::vector<EGLint> attrs;
|
||||
if (m_sExts.KHR_display_reference) {
|
||||
attrs.push_back(EGL_TRACK_REFERENCES_KHR);
|
||||
attrs.push_back(EGL_TRUE);
|
||||
}
|
||||
|
||||
attrs.push_back(EGL_NONE);
|
||||
|
||||
m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data());
|
||||
if (m_pEglDisplay == EGL_NO_DISPLAY)
|
||||
RASSERT(false, "EGL: failed to create a platform display");
|
||||
|
||||
attrs.clear();
|
||||
|
||||
EGLint major, minor;
|
||||
if (eglInitialize(m_pEglDisplay, &major, &minor) == EGL_FALSE)
|
||||
RASSERT(false, "EGL: failed to initialize a platform display");
|
||||
|
||||
const std::string EGLEXTENSIONS = (const char*)eglQueryString(m_pEglDisplay, EGL_EXTENSIONS);
|
||||
|
||||
m_sExts.IMG_context_priority = EGLEXTENSIONS.contains("IMG_context_priority");
|
||||
m_sExts.EXT_create_context_robustness = EGLEXTENSIONS.contains("EXT_create_context_robustness");
|
||||
m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
|
||||
m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
|
||||
|
||||
if (m_sExts.IMG_context_priority) {
|
||||
Debug::log(LOG, "EGL: IMG_context_priority supported, requesting high");
|
||||
attrs.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
|
||||
attrs.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
|
||||
}
|
||||
|
||||
if (m_sExts.EXT_create_context_robustness) {
|
||||
Debug::log(LOG, "EGL: EXT_create_context_robustness supported, requesting lose on reset");
|
||||
attrs.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
|
||||
attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT);
|
||||
}
|
||||
|
||||
attrs.push_back(EGL_CONTEXT_MAJOR_VERSION);
|
||||
attrs.push_back(3);
|
||||
attrs.push_back(EGL_CONTEXT_MINOR_VERSION);
|
||||
attrs.push_back(2);
|
||||
attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG);
|
||||
attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE);
|
||||
|
||||
attrs.push_back(EGL_NONE);
|
||||
|
||||
m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data());
|
||||
if (m_pEglContext == EGL_NO_CONTEXT)
|
||||
RASSERT(false, "EGL: failed to create a context");
|
||||
|
||||
if (m_sExts.IMG_context_priority) {
|
||||
EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
|
||||
eglQueryContext(m_pEglDisplay, m_pEglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority);
|
||||
if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG)
|
||||
Debug::log(ERR, "EGL: Failed to obtain a high priority context");
|
||||
else
|
||||
Debug::log(LOG, "EGL: Got a high priority context");
|
||||
}
|
||||
|
||||
eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext);
|
||||
}
|
||||
|
||||
CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
|
||||
"Couldn't unset current EGL!");
|
||||
const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
|
||||
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
|
||||
const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS);
|
||||
|
||||
RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
|
||||
Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS);
|
||||
|
||||
m_iDRMFD = g_pCompositor->m_iDRMFD;
|
||||
|
||||
m_sExts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference");
|
||||
|
||||
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
|
||||
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
|
||||
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
|
||||
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
|
||||
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
|
||||
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
|
||||
loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
|
||||
loadGLProc(&m_sProc.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT");
|
||||
loadGLProc(&m_sProc.eglCreateSyncKHR, "eglCreateSyncKHR");
|
||||
loadGLProc(&m_sProc.eglDestroySyncKHR, "eglDestroySyncKHR");
|
||||
loadGLProc(&m_sProc.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID");
|
||||
loadGLProc(&m_sProc.eglWaitSyncKHR, "eglWaitSyncKHR");
|
||||
|
||||
RASSERT(m_sProc.eglCreateSyncKHR, "Display driver doesn't support eglCreateSyncKHR");
|
||||
RASSERT(m_sProc.eglDupNativeFenceFDANDROID, "Display driver doesn't support eglDupNativeFenceFDANDROID");
|
||||
RASSERT(m_sProc.eglWaitSyncKHR, "Display driver doesn't support eglWaitSyncKHR");
|
||||
|
||||
if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration"))
|
||||
loadGLProc(&m_sProc.eglQueryDevicesEXT, "eglQueryDevicesEXT");
|
||||
|
||||
if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_query")) {
|
||||
loadGLProc(&m_sProc.eglQueryDeviceStringEXT, "eglQueryDeviceStringEXT");
|
||||
loadGLProc(&m_sProc.eglQueryDisplayAttribEXT, "eglQueryDisplayAttribEXT");
|
||||
}
|
||||
|
||||
if (EGLEXTENSIONS.contains("EGL_KHR_debug")) {
|
||||
loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
|
||||
static const EGLAttrib debugAttrs[] = {
|
||||
EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, EGL_NONE,
|
||||
};
|
||||
m_sProc.eglDebugMessageControlKHR(::eglLog, debugAttrs);
|
||||
}
|
||||
|
||||
RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue.");
|
||||
|
||||
// if (m_sProc.eglQueryDevicesEXT) {
|
||||
// // TODO:
|
||||
// }
|
||||
|
||||
if (EGLEXTENSIONS.contains("KHR_platform_gbm")) {
|
||||
m_iGBMFD = openRenderNode(m_iDRMFD);
|
||||
if (m_iGBMFD < 0)
|
||||
RASSERT(false, "Couldn't open a gbm fd");
|
||||
|
||||
m_pGbmDevice = gbm_create_device(m_iGBMFD);
|
||||
if (!m_pGbmDevice)
|
||||
RASSERT(false, "Couldn't open a gbm device");
|
||||
|
||||
initEGL(true);
|
||||
} else
|
||||
RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver.");
|
||||
|
||||
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
|
||||
RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
|
||||
|
||||
m_szExtensions = EXTENSIONS;
|
||||
|
||||
Debug::log(LOG, "Creating the Hypr OpenGL Renderer!");
|
||||
|
|
@ -38,16 +227,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
|||
Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
|
||||
Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions);
|
||||
|
||||
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
|
||||
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
|
||||
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
|
||||
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
|
||||
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
|
||||
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
|
||||
|
||||
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
|
||||
m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
|
||||
m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
|
||||
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
|
||||
|
||||
RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required");
|
||||
|
||||
|
|
@ -74,7 +254,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
|||
|
||||
static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); });
|
||||
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
|
||||
RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
|
||||
|
||||
m_tGlobalTimer.reset();
|
||||
}
|
||||
|
|
@ -86,7 +266,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
|
|||
return std::nullopt;
|
||||
|
||||
EGLint len = 0;
|
||||
if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) {
|
||||
if (!m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, 0, nullptr, nullptr, &len)) {
|
||||
Debug::log(ERR, "EGL: Failed to query mods");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
@ -100,7 +280,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
|
|||
mods.resize(len);
|
||||
external.resize(len);
|
||||
|
||||
m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len);
|
||||
m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len);
|
||||
|
||||
std::vector<uint64_t> result;
|
||||
bool linearIsExternal = false;
|
||||
|
|
@ -139,9 +319,9 @@ void CHyprOpenGLImpl::initDRMFormats() {
|
|||
Debug::log(WARN, "EGL: No mod support");
|
||||
} else {
|
||||
EGLint len = 0;
|
||||
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len);
|
||||
m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, 0, nullptr, &len);
|
||||
formats.resize(len);
|
||||
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len);
|
||||
m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, len, formats.data(), &len);
|
||||
}
|
||||
|
||||
if (formats.size() == 0) {
|
||||
|
|
@ -149,7 +329,7 @@ void CHyprOpenGLImpl::initDRMFormats() {
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:");
|
||||
Debug::log(LOG, "Supported DMA-BUF formats:");
|
||||
|
||||
std::vector<SDRMFormat> dmaFormats;
|
||||
|
||||
|
|
@ -170,8 +350,8 @@ void CHyprOpenGLImpl::initDRMFormats() {
|
|||
mods.push_back(DRM_FORMAT_MOD_INVALID);
|
||||
|
||||
dmaFormats.push_back(SDRMFormat{
|
||||
.format = fmt,
|
||||
.mods = mods,
|
||||
.drmFormat = fmt,
|
||||
.modifiers = mods,
|
||||
});
|
||||
|
||||
std::vector<std::pair<uint64_t, std::string>> modifierData;
|
||||
|
|
@ -209,7 +389,7 @@ void CHyprOpenGLImpl::initDRMFormats() {
|
|||
drmFormats = dmaFormats;
|
||||
}
|
||||
|
||||
EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
|
||||
EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attrs) {
|
||||
std::vector<uint32_t> attribs;
|
||||
|
||||
attribs.push_back(EGL_WIDTH);
|
||||
|
|
@ -251,7 +431,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
|
|||
|
||||
attribs.push_back(EGL_NONE);
|
||||
|
||||
EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
|
||||
EGLImageKHR image = m_sProc.eglCreateImageKHR(m_pEglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError());
|
||||
return EGL_NO_IMAGE_KHR;
|
||||
|
|
@ -342,7 +522,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool
|
|||
}
|
||||
|
||||
bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
|
||||
// passes requiring introspection are the ones that need to render blur.
|
||||
// passes requiring introspection are the ones that need to render blur,
|
||||
// or when we are rendering to a multigpu target
|
||||
|
||||
static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
|
||||
static auto PXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray");
|
||||
|
|
@ -446,7 +627,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) {
|
||||
void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP<CRenderbuffer> rb, CFramebuffer* fb) {
|
||||
m_RenderData.pMonitor = pMonitor;
|
||||
|
||||
#ifndef GLES2
|
||||
|
|
@ -472,12 +653,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRe
|
|||
|
||||
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
wlr_matrix_identity(m_RenderData.monitorProjection.data());
|
||||
matrixIdentity(m_RenderData.monitorProjection.data());
|
||||
if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
|
||||
const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize;
|
||||
wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
|
||||
wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform);
|
||||
wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
|
||||
matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
|
||||
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform));
|
||||
matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
|
||||
}
|
||||
|
||||
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
|
||||
|
|
@ -545,10 +726,10 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
|
|||
m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
|
||||
m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
|
||||
|
||||
m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
|
||||
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
|
||||
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
|
||||
m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
|
||||
}
|
||||
|
||||
if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty())
|
||||
|
|
@ -597,7 +778,7 @@ void CHyprOpenGLImpl::end() {
|
|||
|
||||
TRACY_GPU_ZONE("RenderEnd");
|
||||
|
||||
// end the render, copy the data to the WLR framebuffer
|
||||
// end the render, copy the data to the main framebuffer
|
||||
if (m_bOffloadedFramebuffer) {
|
||||
m_RenderData.damage = m_RenderData.finalDamage;
|
||||
m_bEndFrame = true;
|
||||
|
|
@ -915,11 +1096,8 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) {
|
|||
CBox newBox = *pBox;
|
||||
|
||||
if (transform) {
|
||||
int w, h;
|
||||
wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h);
|
||||
|
||||
const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform));
|
||||
newBox.transform(TR, w, h);
|
||||
const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
|
||||
newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
}
|
||||
|
||||
glScissor(newBox.x, newBox.y, newBox.width, newBox.height);
|
||||
|
|
@ -1008,18 +1186,18 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
|
|||
box = &newBox;
|
||||
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
|
||||
|
||||
#ifndef GLES2
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
|
||||
|
|
@ -1027,7 +1205,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
|
|||
glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a);
|
||||
|
||||
CBox transformedBox = *box;
|
||||
transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
|
||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||
|
|
@ -1072,16 +1250,17 @@ void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, CBox* pBox, float alpha, i
|
|||
scissor((CBox*)nullptr);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) {
|
||||
void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV,
|
||||
SP<CSyncTimeline> waitTimeline, uint64_t waitPoint) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
|
||||
|
||||
renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true);
|
||||
renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint);
|
||||
|
||||
scissor((CBox*)nullptr);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV,
|
||||
bool allowDim) {
|
||||
bool allowDim, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
|
||||
RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!");
|
||||
|
||||
|
|
@ -1099,12 +1278,19 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
|
|||
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
if (waitTimeline != nullptr) {
|
||||
if (!waitForTimelinePoint(waitTimeline, waitPoint)) {
|
||||
Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CShader* shader = nullptr;
|
||||
|
||||
|
|
@ -1151,7 +1337,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
|
|
@ -1187,7 +1373,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
|
|||
}
|
||||
|
||||
CBox transformedBox = newBox;
|
||||
transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
|
||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||
|
|
@ -1262,12 +1448,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
|
|||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
|
||||
|
||||
|
|
@ -1279,7 +1465,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
|
|
@ -1316,12 +1502,12 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
|
|||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE;
|
||||
|
||||
|
|
@ -1330,7 +1516,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
|
|
@ -1374,13 +1560,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
// get transforms for the full monitor
|
||||
const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform));
|
||||
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
|
||||
float matrix[9];
|
||||
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
// get the config settings
|
||||
static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size");
|
||||
|
|
@ -1390,9 +1576,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
|
||||
// prep damage
|
||||
CRegion damage{*originalDamage};
|
||||
wlr_region_transform(damage.pixman(), damage.pixman(), wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
wlr_region_expand(damage.pixman(), damage.pixman(), *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES));
|
||||
damage.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
damage.expand(*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES));
|
||||
|
||||
// helper
|
||||
const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB;
|
||||
|
|
@ -1419,7 +1605,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
|
||||
|
|
@ -1464,7 +1650,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
|
||||
|
|
@ -1511,13 +1697,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
|
||||
// and draw
|
||||
for (int i = 1; i <= *PBLURPASSES; ++i) {
|
||||
wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i));
|
||||
tempDamage = damage.copy().scale(1.f / (1 << i));
|
||||
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down
|
||||
}
|
||||
|
||||
for (int i = *PBLURPASSES - 1; i >= 0; --i) {
|
||||
wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); // when upsampling we make the region twice as big
|
||||
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
|
||||
tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big
|
||||
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
|
||||
}
|
||||
|
||||
// finalize the image
|
||||
|
|
@ -1541,7 +1727,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
|
||||
|
|
@ -1679,7 +1865,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
|
|||
const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage);
|
||||
|
||||
// render onto blurFB
|
||||
m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y,
|
||||
m_RenderData.pMonitor->output->state->state().drmFormat);
|
||||
m_RenderData.pCurrentMonData->blurFB.bind();
|
||||
|
||||
clear(CColor(0, 0, 0, 0));
|
||||
|
|
@ -1773,7 +1960,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float
|
|||
inverseOpaque = {0, 0, pBox->width, pBox->height};
|
||||
}
|
||||
|
||||
wlr_region_scale(inverseOpaque.pixman(), inverseOpaque.pixman(), m_RenderData.pMonitor->scale);
|
||||
inverseOpaque.scale(m_RenderData.pMonitor->scale);
|
||||
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_pCurrentLayer, m_pCurrentWindow.lock()) && !blockBlurOptimization;
|
||||
|
|
@ -1872,11 +2059,11 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
|
|||
round += round == 0 ? 0 : scaledBorderSize;
|
||||
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
const auto BLEND = m_bBlend;
|
||||
blend(true);
|
||||
|
|
@ -1886,7 +2073,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
|
||||
|
|
@ -1898,7 +2085,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
|
|||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
|
||||
|
||||
CBox transformedBox = *box;
|
||||
transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x,
|
||||
m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
|
||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||
|
|
@ -1949,14 +2136,14 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr
|
|||
|
||||
// we need to "damage" the entire monitor
|
||||
// so that we render the entire window
|
||||
// this is temporary, doesnt mess with the actual wlr damage
|
||||
// this is temporary, doesnt mess with the actual damage
|
||||
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
|
||||
|
||||
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
|
||||
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
|
||||
|
||||
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer);
|
||||
|
||||
|
|
@ -2000,7 +2187,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
|
|||
|
||||
// we need to "damage" the entire monitor
|
||||
// so that we render the entire window
|
||||
// this is temporary, doesnt mess with the actual wlr damage
|
||||
// this is temporary, doesnt mess with the actual damage
|
||||
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
|
||||
|
||||
PHLWINDOWREF ref{pWindow};
|
||||
|
|
@ -2009,7 +2196,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) {
|
|||
|
||||
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[ref];
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
|
||||
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
|
||||
|
||||
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
|
||||
|
||||
|
|
@ -2049,14 +2236,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) {
|
|||
|
||||
// we need to "damage" the entire monitor
|
||||
// so that we render the entire window
|
||||
// this is temporary, doesnt mess with the actual wlr damage
|
||||
// this is temporary, doesnt mess with the actual damage
|
||||
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer];
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
|
||||
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat);
|
||||
|
||||
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
|
||||
|
||||
|
|
@ -2178,11 +2365,11 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
|
|||
const auto col = color;
|
||||
|
||||
float matrix[9];
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
|
||||
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
|
||||
m_RenderData.monitorProjection.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
|
|
@ -2191,7 +2378,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
|
|||
#ifndef GLES2
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix);
|
||||
#else
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
matrixTranspose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a);
|
||||
|
|
@ -2238,7 +2425,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
|
|||
void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) {
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated())
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y,
|
||||
m_RenderData.pMonitor->output->state->state().drmFormat);
|
||||
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.bind();
|
||||
|
||||
|
|
@ -2270,11 +2458,11 @@ void CHyprOpenGLImpl::renderMirrored() {
|
|||
return;
|
||||
|
||||
// replace monitor projection to undo the mirrored monitor's projection
|
||||
wlr_matrix_identity(monitor->projMatrix.data());
|
||||
wlr_matrix_translate(monitor->projMatrix.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
|
||||
wlr_matrix_transform(monitor->projMatrix.data(), monitor->transform);
|
||||
wlr_matrix_transform(monitor->projMatrix.data(), wlr_output_transform_invert(mirrored->transform));
|
||||
wlr_matrix_translate(monitor->projMatrix.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
|
||||
matrixIdentity(m_RenderData.monitorProjection.data());
|
||||
matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
|
||||
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform));
|
||||
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform)));
|
||||
matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
|
||||
|
||||
// clear stuff outside of mirrored area (e.g. when changing to mirrored)
|
||||
clear(CColor(0, 0, 0, 0));
|
||||
|
|
@ -2282,7 +2470,7 @@ void CHyprOpenGLImpl::renderMirrored() {
|
|||
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
|
||||
|
||||
// reset matrix for further drawing
|
||||
monitor->updateMatrix();
|
||||
m_RenderData.monitorProjection = monitor->projMatrix;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
|
||||
|
|
@ -2338,7 +2526,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
|||
const auto PFB = &m_mMonitorBGFBs[pMonitor];
|
||||
PFB->release();
|
||||
|
||||
PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat);
|
||||
Debug::log(LOG, "Allocated texture for BGTex");
|
||||
|
||||
// TODO: use relative paths to the installation
|
||||
|
|
@ -2474,6 +2662,9 @@ void CHyprOpenGLImpl::clearWithTex() {
|
|||
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
if (!g_pHyprOpenGL)
|
||||
return;
|
||||
|
||||
auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor);
|
||||
if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) {
|
||||
RESIT->second.mirrorFB.release();
|
||||
|
|
@ -2500,8 +2691,8 @@ void CHyprOpenGLImpl::saveMatrix() {
|
|||
}
|
||||
|
||||
void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) {
|
||||
wlr_matrix_scale(m_RenderData.projection, scale, scale);
|
||||
wlr_matrix_translate(m_RenderData.projection, translate.x, translate.y);
|
||||
matrixScale(m_RenderData.projection, scale, scale);
|
||||
matrixTranslate(m_RenderData.projection, translate.x, translate.y);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::restoreMatrix() {
|
||||
|
|
@ -2533,29 +2724,63 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) {
|
|||
}
|
||||
|
||||
uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
|
||||
GLint glf = -1, glt = -1, as = 0;
|
||||
/*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf);
|
||||
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &glt);
|
||||
glGetIntegerv(GL_ALPHA_BITS, &as);*/
|
||||
|
||||
if (glf == 0 || glt == 0) {
|
||||
glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat);
|
||||
glt = FormatUtils::glFormatToType(glf);
|
||||
}
|
||||
|
||||
if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT)
|
||||
return FMT->drmFormat;
|
||||
|
||||
if (m_sExts.EXT_read_format_bgra)
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
|
||||
return DRM_FORMAT_XBGR8888;
|
||||
return pMonitor->output->state->state().drmFormat;
|
||||
}
|
||||
|
||||
std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
|
||||
return drmFormats;
|
||||
}
|
||||
|
||||
SP<CEGLSync> CHyprOpenGLImpl::createEGLSync(int fenceFD) {
|
||||
std::vector<EGLint> attribs;
|
||||
int dupFd = -1;
|
||||
if (fenceFD > 0) {
|
||||
int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0);
|
||||
if (dupFd < 0) {
|
||||
Debug::log(ERR, "createEGLSync: dup failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID);
|
||||
attribs.push_back(dupFd);
|
||||
attribs.push_back(EGL_NONE);
|
||||
}
|
||||
|
||||
EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data());
|
||||
if (sync == EGL_NO_SYNC_KHR) {
|
||||
Debug::log(ERR, "eglCreateSyncKHR failed");
|
||||
if (dupFd >= 0)
|
||||
close(dupFd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto eglsync = SP<CEGLSync>(new CEGLSync);
|
||||
eglsync->sync = sync;
|
||||
return eglsync;
|
||||
}
|
||||
|
||||
bool CHyprOpenGLImpl::waitForTimelinePoint(SP<CSyncTimeline> timeline, uint64_t point) {
|
||||
int fd = timeline->exportAsSyncFileFD(point);
|
||||
if (fd < 0) {
|
||||
Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sync = g_pHyprOpenGL->createEGLSync(fd);
|
||||
close(fd);
|
||||
if (!sync) {
|
||||
Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sync->wait()) {
|
||||
Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SRenderModifData::applyToBox(CBox& box) {
|
||||
if (!enabled)
|
||||
return;
|
||||
|
|
@ -2616,3 +2841,35 @@ float SRenderModifData::combinedScale() {
|
|||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
CEGLSync::~CEGLSync() {
|
||||
if (sync == EGL_NO_SYNC_KHR)
|
||||
return;
|
||||
|
||||
if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
|
||||
Debug::log(ERR, "eglDestroySyncKHR failed");
|
||||
}
|
||||
|
||||
int CEGLSync::dupFenceFD() {
|
||||
if (sync == EGL_NO_SYNC_KHR)
|
||||
return -1;
|
||||
|
||||
int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
|
||||
if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
|
||||
Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool CEGLSync::wait() {
|
||||
if (sync == EGL_NO_SYNC_KHR)
|
||||
return false;
|
||||
|
||||
if (g_pHyprOpenGL->m_sProc.eglWaitSyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync, 0) != EGL_TRUE) {
|
||||
Debug::log(ERR, "eglWaitSyncKHR failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "../helpers/Timer.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/Format.hpp"
|
||||
#include "../helpers/sync/SyncTimeline.hpp"
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
|
@ -18,10 +20,14 @@
|
|||
#include "Transformer.hpp"
|
||||
#include "Renderbuffer.hpp"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
#include "../debug/TracyDefines.hpp"
|
||||
|
||||
struct gbm_device;
|
||||
class CHyprRenderer;
|
||||
|
||||
inline const float fullVerts[] = {
|
||||
|
|
@ -119,6 +125,21 @@ struct SCurrentRenderData {
|
|||
float discardOpacity = 0.f;
|
||||
};
|
||||
|
||||
class CEGLSync {
|
||||
public:
|
||||
~CEGLSync();
|
||||
|
||||
EGLSyncKHR sync = nullptr;
|
||||
|
||||
int dupFenceFD();
|
||||
bool wait();
|
||||
|
||||
private:
|
||||
CEGLSync() = default;
|
||||
|
||||
friend class CHyprOpenGLImpl;
|
||||
};
|
||||
|
||||
class CGradientValueData;
|
||||
|
||||
class CHyprOpenGLImpl {
|
||||
|
|
@ -126,14 +147,15 @@ class CHyprOpenGLImpl {
|
|||
CHyprOpenGLImpl();
|
||||
|
||||
void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
|
||||
void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr);
|
||||
void beginSimple(CMonitor*, const CRegion& damage, SP<CRenderbuffer> rb = nullptr, CFramebuffer* fb = nullptr);
|
||||
void end();
|
||||
|
||||
void renderRect(CBox*, const CColor&, int round = 0);
|
||||
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
|
||||
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
|
||||
void renderTexture(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
|
||||
void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
|
||||
void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false,
|
||||
SP<CSyncTimeline> waitTimeline = nullptr, uint64_t waitPoint = 0);
|
||||
void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
|
||||
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
|
||||
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
|
||||
|
|
@ -182,12 +204,19 @@ class CHyprOpenGLImpl {
|
|||
|
||||
uint32_t getPreferredReadFormat(CMonitor* pMonitor);
|
||||
std::vector<SDRMFormat> getDRMFormats();
|
||||
EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs);
|
||||
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
|
||||
SP<CEGLSync> createEGLSync(int fenceFD);
|
||||
bool waitForTimelinePoint(SP<CSyncTimeline> timeline, uint64_t point);
|
||||
|
||||
SCurrentRenderData m_RenderData;
|
||||
|
||||
GLint m_iCurrentOutputFb = 0;
|
||||
|
||||
int m_iGBMFD = -1;
|
||||
gbm_device* m_pGbmDevice = nullptr;
|
||||
EGLContext m_pEglContext = nullptr;
|
||||
EGLDisplay m_pEglDisplay = nullptr;
|
||||
|
||||
bool m_bReloadScreenShader = true; // at launch it can be set
|
||||
|
||||
PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window
|
||||
|
|
@ -205,12 +234,24 @@ class CHyprOpenGLImpl {
|
|||
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
|
||||
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
|
||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
|
||||
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
|
||||
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
|
||||
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
|
||||
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
|
||||
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
|
||||
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
|
||||
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
|
||||
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
|
||||
} m_sProc;
|
||||
|
||||
struct {
|
||||
bool EXT_read_format_bgra = false;
|
||||
bool EXT_image_dma_buf_import = false;
|
||||
bool EXT_image_dma_buf_import_modifiers = false;
|
||||
bool KHR_display_reference = false;
|
||||
bool IMG_context_priority = false;
|
||||
bool EXT_create_context_robustness = false;
|
||||
} m_sExts;
|
||||
|
||||
private:
|
||||
|
|
@ -220,7 +261,7 @@ class CHyprOpenGLImpl {
|
|||
std::vector<SDRMFormat> drmFormats;
|
||||
bool m_bHasModifiers = false;
|
||||
|
||||
int m_iDRMFD;
|
||||
int m_iDRMFD = -1;
|
||||
std::string m_szExtensions;
|
||||
|
||||
bool m_bFakeFrame = false;
|
||||
|
|
@ -238,6 +279,7 @@ class CHyprOpenGLImpl {
|
|||
void createBGTextureForMonitor(CMonitor*);
|
||||
void initShaders();
|
||||
void initDRMFormats();
|
||||
void initEGL(bool gbm);
|
||||
|
||||
//
|
||||
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
|
||||
|
|
@ -246,7 +288,7 @@ class CHyprOpenGLImpl {
|
|||
CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);
|
||||
|
||||
void renderTextureInternalWithDamage(SP<CTexture>, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
|
||||
bool allowCustomUV = false, bool allowDim = false);
|
||||
bool allowCustomUV = false, bool allowDim = false, SP<CSyncTimeline> = nullptr, uint64_t waitPoint = 0);
|
||||
void renderTexturePrimitive(SP<CTexture> tex, CBox* pBox);
|
||||
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "OpenGL.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../protocols/types/Buffer.hpp"
|
||||
#include <hyprutils/signal/Listener.hpp>
|
||||
#include <hyprutils/signal/Signal.hpp>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
|
@ -15,58 +17,17 @@ CRenderbuffer::~CRenderbuffer() {
|
|||
m_sFramebuffer.release();
|
||||
glDeleteRenderbuffers(1, &m_iRBO);
|
||||
|
||||
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
|
||||
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_iImage);
|
||||
}
|
||||
|
||||
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) {
|
||||
|
||||
// EVIL, but we can't include a hidden header because nixos is fucking special
|
||||
static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*);
|
||||
static bool symbolFound = false;
|
||||
if (!symbolFound) {
|
||||
PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast<EGLImageKHR (*)(wlr_egl*, wlr_dmabuf_attributes*, bool*)>(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf"));
|
||||
|
||||
symbolFound = true;
|
||||
|
||||
RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!");
|
||||
|
||||
Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF);
|
||||
}
|
||||
// end evil hack
|
||||
|
||||
struct wlr_dmabuf_attributes dmabuf = {0};
|
||||
if (!wlr_buffer_get_dmabuf(buffer, &dmabuf))
|
||||
throw std::runtime_error("wlr_buffer_get_dmabuf failed");
|
||||
|
||||
bool externalOnly;
|
||||
m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly);
|
||||
if (m_iImage == EGL_NO_IMAGE_KHR)
|
||||
throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed");
|
||||
|
||||
glGenRenderbuffers(1, &m_iRBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
|
||||
g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
|
||||
m_sFramebuffer.m_vSize = {buffer->width, buffer->height};
|
||||
m_sFramebuffer.bind();
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer");
|
||||
}
|
||||
|
||||
CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
|
||||
CRenderbuffer::CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
|
||||
auto dma = buffer->dmabuf();
|
||||
|
||||
m_iImage = g_pHyprOpenGL->createEGLImage(dma);
|
||||
if (m_iImage == EGL_NO_IMAGE_KHR)
|
||||
throw std::runtime_error("createEGLImage failed");
|
||||
if (m_iImage == EGL_NO_IMAGE_KHR) {
|
||||
Debug::log(ERR, "rb: createEGLImage failed");
|
||||
return;
|
||||
}
|
||||
|
||||
glGenRenderbuffers(1, &m_iRBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
|
||||
|
|
@ -78,10 +39,20 @@ CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffe
|
|||
m_sFramebuffer.bind();
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
Debug::log(ERR, "rbo: glCheckFramebufferStatus failed");
|
||||
return;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); });
|
||||
|
||||
m_bGood = true;
|
||||
}
|
||||
|
||||
bool CRenderbuffer::good() {
|
||||
return m_bGood;
|
||||
}
|
||||
|
||||
void CRenderbuffer::bind() {
|
||||
|
|
|
|||
|
|
@ -1,30 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../helpers/WLListener.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
class CMonitor;
|
||||
class IWLBuffer;
|
||||
|
||||
class CRenderbuffer {
|
||||
public:
|
||||
CRenderbuffer(wlr_buffer* buffer, uint32_t format);
|
||||
CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format);
|
||||
CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
|
||||
~CRenderbuffer();
|
||||
|
||||
void bind();
|
||||
void bindFB();
|
||||
void unbind();
|
||||
CFramebuffer* getFB();
|
||||
uint32_t getFormat();
|
||||
bool good();
|
||||
void bind();
|
||||
void bindFB();
|
||||
void unbind();
|
||||
CFramebuffer* getFB();
|
||||
uint32_t getFormat();
|
||||
|
||||
wlr_buffer* m_pWlrBuffer = nullptr;
|
||||
WP<IWLBuffer> m_pHLBuffer = {};
|
||||
|
||||
DYNLISTENER(destroyBuffer);
|
||||
WP<Aquamarine::IBuffer> m_pHLBuffer;
|
||||
|
||||
private:
|
||||
EGLImageKHR m_iImage = 0;
|
||||
void* m_iImage = nullptr;
|
||||
GLuint m_iRBO = 0;
|
||||
CFramebuffer m_sFramebuffer;
|
||||
uint32_t m_uDrmFormat = 0;
|
||||
bool m_bGood = false;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroyBuffer;
|
||||
} listeners;
|
||||
};
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include <algorithm>
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <cstring>
|
||||
#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 <xf86drm.h>
|
||||
|
|
@ -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<CWLSurfaceResource> 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<CWLSurfaceResource> 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<CQueuedPresentationData>(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<CWLSurfaceResource> surface, int x, int y, void* da
|
|||
}
|
||||
|
||||
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
||||
surface->frame(RDATA->when);
|
||||
auto FEEDBACK = makeShared<CQueuedPresentationData>(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, SP<CWLSurfaceResour
|
|||
}
|
||||
}
|
||||
|
||||
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||
return false; // FIXME: fix when we move to new lib for backend.
|
||||
|
||||
// if (!pMonitor->mirrors.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<CQueuedPresentationData>(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<Hyprlang::INT>("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;
|
||||
void CHyprRenderer::setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, SP<CMonitor> monitor) {
|
||||
if (!PROTO::linuxDma)
|
||||
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);
|
||||
|
||||
// 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::vector<PHLL
|
|||
CBox full_area = {pMonitor->vecPosition.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<CWLSurfaceResource> 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>(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>(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;
|
||||
if (!pMonitor->output->modes.empty()) {
|
||||
for (auto& mode : pMonitor->output->modes) {
|
||||
pMonitor->output->state->setMode(mode);
|
||||
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), 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<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 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<std::pair<std::string, uint32_t>>{ /* 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<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 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<std::pair<std::string, uint32_t>>{ /* 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; });
|
||||
|
||||
if (it != m_vRenderbuffers.end())
|
||||
return it->get();
|
||||
|
||||
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
|
||||
}
|
||||
|
||||
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) {
|
||||
SP<CRenderbuffer> CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> 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<CRenderbuffer>(buffer, fmt)).get();
|
||||
auto buf = makeShared<CRenderbuffer>(buffer, fmt);
|
||||
|
||||
if (!buf->good())
|
||||
return nullptr;
|
||||
|
||||
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<IWLBuffer> buffer, CFramebuffer* fb, bool simple) {
|
||||
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> 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<Hyprlang::INT>("opengl:nvidia_anti_flicker");
|
||||
static auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("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);
|
||||
|
||||
wlr_buffer_unlock(m_pCurrentWlrBuffer);
|
||||
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;
|
||||
}
|
||||
|
||||
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<CRenderbuffer> CHyprRenderer::getCurrentRBO() {
|
||||
return m_pCurrentRenderbuffer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ struct SMonitorRule;
|
|||
class CWorkspace;
|
||||
class CWindow;
|
||||
class CInputPopup;
|
||||
class IWLBuffer;
|
||||
class IHLBuffer;
|
||||
|
||||
// TODO: add fuller damage tracking for updating only parts of a window
|
||||
enum DAMAGETRACKINGMODES {
|
||||
|
|
@ -69,35 +69,35 @@ class CHyprRenderer {
|
|||
void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
|
||||
void setCursorFromName(const std::string& name, bool force = false);
|
||||
void onRenderbufferDestroy(CRenderbuffer* rb);
|
||||
CRenderbuffer* getCurrentRBO();
|
||||
SP<CRenderbuffer> getCurrentRBO();
|
||||
bool isNvidia();
|
||||
void makeEGLCurrent();
|
||||
void unsetEGL();
|
||||
|
||||
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
||||
// otherwise, it will be the one used.
|
||||
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
|
||||
void endRender();
|
||||
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
|
||||
void endRender();
|
||||
|
||||
bool m_bBlockSurfaceFeedback = false;
|
||||
bool m_bRenderingSnapshot = false;
|
||||
PHLWINDOWREF m_pLastScanout;
|
||||
CMonitor* m_pMostHzMonitor = nullptr;
|
||||
bool m_bDirectScanoutBlocked = false;
|
||||
bool m_bBlockSurfaceFeedback = false;
|
||||
bool m_bRenderingSnapshot = false;
|
||||
CMonitor* m_pMostHzMonitor = nullptr;
|
||||
bool m_bDirectScanoutBlocked = false;
|
||||
|
||||
DAMAGETRACKINGMODES
|
||||
damageTrackingModeFromStr(const std::string&);
|
||||
|
||||
bool attemptDirectScanout(CMonitor*);
|
||||
void setWindowScanoutMode(PHLWINDOW);
|
||||
void initiateManualCrash();
|
||||
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, SP<CMonitor> monitor); // nullptr monitor resets
|
||||
void initiateManualCrash();
|
||||
|
||||
bool m_bCrashingInProgress = false;
|
||||
float m_fCrashingDistort = 0.5f;
|
||||
wl_event_source* m_pCrashingLoop = nullptr;
|
||||
wl_event_source* m_pCursorTicker = nullptr;
|
||||
bool m_bCrashingInProgress = false;
|
||||
float m_fCrashingDistort = 0.5f;
|
||||
wl_event_source* m_pCrashingLoop = nullptr;
|
||||
wl_event_source* m_pCursorTicker = nullptr;
|
||||
|
||||
CTimer m_tRenderTimer;
|
||||
CTimer m_tRenderTimer;
|
||||
|
||||
std::vector<SP<CWLSurfaceResource>> explicitPresented;
|
||||
|
||||
struct {
|
||||
int hotspotX;
|
||||
|
|
@ -107,26 +107,27 @@ class CHyprRenderer {
|
|||
} m_sLastCursorData;
|
||||
|
||||
private:
|
||||
void arrangeLayerArray(CMonitor*, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||
void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
|
||||
void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
|
||||
void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
|
||||
void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false);
|
||||
void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*);
|
||||
void renderDragIcon(CMonitor*, timespec*);
|
||||
void renderIMEPopup(CInputPopup*, CMonitor*, timespec*);
|
||||
void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry);
|
||||
void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything
|
||||
void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
|
||||
void arrangeLayerArray(CMonitor*, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||
void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
|
||||
void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
|
||||
void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
|
||||
void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false);
|
||||
void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*);
|
||||
void renderDragIcon(CMonitor*, timespec*);
|
||||
void renderIMEPopup(CInputPopup*, CMonitor*, timespec*);
|
||||
void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry);
|
||||
void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything
|
||||
void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
|
||||
|
||||
bool m_bCursorHidden = false;
|
||||
bool m_bCursorHasSurface = false;
|
||||
CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
|
||||
wlr_buffer* m_pCurrentWlrBuffer = nullptr;
|
||||
WP<IWLBuffer> m_pCurrentHLBuffer = {};
|
||||
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
|
||||
bool commitPendingAndDoExplicitSync(CMonitor* pMonitor);
|
||||
|
||||
bool m_bNvidia = false;
|
||||
bool m_bCursorHidden = false;
|
||||
bool m_bCursorHasSurface = false;
|
||||
SP<CRenderbuffer> m_pCurrentRenderbuffer = nullptr;
|
||||
SP<Aquamarine::IBuffer> m_pCurrentBuffer;
|
||||
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
|
||||
|
||||
bool m_bNvidia = false;
|
||||
|
||||
struct {
|
||||
bool hiddenOnTouch = false;
|
||||
|
|
@ -134,9 +135,8 @@ class CHyprRenderer {
|
|||
bool hiddenOnKeyboard = false;
|
||||
} m_sCursorHiddenConditions;
|
||||
|
||||
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
|
||||
CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt);
|
||||
std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
|
||||
SP<CRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
|
||||
std::vector<SP<CRenderbuffer>> m_vRenderbuffers;
|
||||
|
||||
friend class CHyprOpenGLImpl;
|
||||
friend class CToplevelExportProtocolManager;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ CTexture::CTexture() {
|
|||
}
|
||||
|
||||
CTexture::~CTexture() {
|
||||
if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
|
||||
if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
|
||||
return;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
|
@ -17,6 +17,45 @@ CTexture::~CTexture() {
|
|||
}
|
||||
|
||||
CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
|
||||
createFromShm(drmFormat, pixels, stride, size_);
|
||||
}
|
||||
|
||||
CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
|
||||
createFromDma(attrs, image);
|
||||
}
|
||||
|
||||
CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
auto attrs = buffer->dmabuf();
|
||||
|
||||
if (!attrs.success) {
|
||||
// attempt shm
|
||||
auto shm = buffer->shm();
|
||||
|
||||
if (!shm.success) {
|
||||
Debug::log(ERR, "Cannot create a texture: buffer has no dmabuf or shm");
|
||||
return;
|
||||
}
|
||||
|
||||
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0);
|
||||
|
||||
createFromShm(fmt, pixelData, bufLen, shm.size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf());
|
||||
|
||||
if (!image) {
|
||||
Debug::log(ERR, "Cannot create a texture: failed to create an EGLImage");
|
||||
return;
|
||||
}
|
||||
|
||||
createFromDma(attrs, image);
|
||||
}
|
||||
|
||||
void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat);
|
||||
|
|
@ -41,24 +80,7 @@ CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const V
|
|||
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
CTexture::CTexture(wlr_texture* tex) {
|
||||
RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!");
|
||||
wlr_gles2_texture_attribs attrs;
|
||||
wlr_gles2_texture_get_attribs(tex, &attrs);
|
||||
|
||||
m_iTarget = attrs.target;
|
||||
m_iTexID = attrs.tex;
|
||||
m_bNonOwning = true;
|
||||
|
||||
if (m_iTarget == GL_TEXTURE_2D)
|
||||
m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX;
|
||||
else
|
||||
m_iType = TEXTURE_EXTERNAL;
|
||||
|
||||
m_vSize = Vector2D((int)tex->width, (int)tex->height);
|
||||
}
|
||||
|
||||
CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) {
|
||||
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
|
||||
if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) {
|
||||
Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
|
||||
return;
|
||||
|
|
@ -119,7 +141,7 @@ void CTexture::destroyTexture() {
|
|||
}
|
||||
|
||||
if (m_pEglImage)
|
||||
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage);
|
||||
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_pEglImage);
|
||||
m_pEglImage = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
class IWLBuffer;
|
||||
struct SDMABUFAttrs;
|
||||
class IHLBuffer;
|
||||
HYPRUTILS_FORWARD(Math, CRegion);
|
||||
|
||||
enum TEXTURETYPE {
|
||||
|
|
@ -23,10 +23,10 @@ class CTexture {
|
|||
CTexture(const CTexture&) = delete;
|
||||
|
||||
CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
||||
CTexture(wlr_texture*);
|
||||
|
||||
CTexture(const SP<Aquamarine::IBuffer> buffer);
|
||||
// this ctor takes ownership of the eglImage.
|
||||
CTexture(const SDMABUFAttrs&, void* image);
|
||||
CTexture(const Aquamarine::SDMABUFAttrs&, void* image);
|
||||
~CTexture();
|
||||
|
||||
void destroyTexture();
|
||||
|
|
@ -37,6 +37,9 @@ class CTexture {
|
|||
GLenum m_iTarget = GL_TEXTURE_2D;
|
||||
GLuint m_iTexID = 0;
|
||||
Vector2D m_vSize;
|
||||
void* m_pEglImage = nullptr;
|
||||
bool m_bNonOwning = false; // wlr
|
||||
void* m_pEglImage = nullptr;
|
||||
|
||||
private:
|
||||
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
||||
void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue