From 75af34da96b80a3d228a25e8c75ba1137df9e058 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Thu, 14 Apr 2022 16:43:29 +0200 Subject: [PATCH] added basic damage tracking --- src/config/ConfigManager.cpp | 12 +++- src/defines.hpp | 5 ++ src/events/Monitors.cpp | 51 ++++++++++++++++- src/helpers/SubsurfaceTree.cpp | 3 + src/hyprerror/HyprError.cpp | 5 +- src/managers/AnimationManager.cpp | 52 +++++++++++++++-- src/managers/AnimationManager.hpp | 2 + src/render/OpenGL.cpp | 94 +++++++++++++++++++++++-------- src/render/OpenGL.hpp | 14 +++-- src/render/Renderer.cpp | 90 +++++++++++++++-------------- src/render/Renderer.hpp | 15 ++++- 11 files changed, 259 insertions(+), 84 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 14f20470..18c78b8f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -16,6 +16,9 @@ CConfigManager::CConfigManager() { configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated + configValues["general:damage_tracking"].strValue = "full"; + configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL; + configValues["general:border_size"].intValue = 1; configValues["general:gaps_in"].intValue = 5; configValues["general:gaps_out"].intValue = 20; @@ -357,8 +360,15 @@ void CConfigManager::loadConfigLoadVars() { if (!isFirstLaunch) g_pInputManager->setKeyboardLayout(); - // Calculate the mod mask for main_mod + // Calculate the internal vars configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue); + const auto DAMAGETRACKINGMODE = g_pHyprRenderer->damageTrackingModeFromStr(configValues["general:damage_tracking"].strValue); + if (DAMAGETRACKINGMODE != DAMAGE_TRACKING_INVALID) + configValues["general:damage_tracking_internal"].intValue = DAMAGETRACKINGMODE; + else { + parseError = "invalid value for general:damage_tracking, supported: full, monitor, none"; + configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE; + } // parseError will be displayed next frame if (parseError != "") diff --git a/src/defines.hpp b/src/defines.hpp index 8b810fd5..ee3a6ccf 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -23,6 +23,11 @@ #define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < delta) +#define PIXMAN_DAMAGE_FOREACH(region) int rectsNum = 0; \ + const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \ + for (int i = 0; i < rectsNum; ++i) + + #define interface class #define STICKS(a, b) abs((a) - (b)) < 2 diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 85b76abd..a6315a68 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -134,6 +134,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { // add a WLR workspace group PNEWMONITOR->pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr); + // add damage + PNEWMONITOR->damage = wlr_output_damage_create(OUTPUT); + // Workspace const auto WORKSPACEID = monitorRule.defaultWorkspaceID == -1 ? g_pCompositor->m_lWorkspaces.size() : monitorRule.defaultWorkspaceID; g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID); @@ -169,10 +172,39 @@ void Events::listener_monitorFrame(void* owner, void* data) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if (!wlr_output_attach_render(PMONITOR->output, nullptr)) - return; + // check the damage + pixman_region32_t damage; + bool hasChanged; + pixman_region32_init(&damage); - g_pHyprOpenGL->begin(PMONITOR); + const auto DTMODE = g_pConfigManager->getInt("general:damage_tracking_internal"); + + if (DTMODE == -1) { + Debug::log(CRIT, "Damage tracking mode -1 ????"); + return; + } + + if (!wlr_output_damage_attach_render(PMONITOR->damage, &hasChanged, &damage)){ + Debug::log(ERR, "Couldn't attach render to display %s ???", PMONITOR->szName.c_str()); + return; + } + + if (!hasChanged && DTMODE != DAMAGE_TRACKING_NONE) { + pixman_region32_fini(&damage); + wlr_output_rollback(PMONITOR->output); + wlr_output_schedule_frame(PMONITOR->output); // we update shit at the monitor's Hz so we need to schedule frames because rollback wont + return; + } + + // if we have no tracking or full tracking, invalidate the entire monitor + if (DTMODE == DAMAGE_TRACKING_NONE || DTMODE == DAMAGE_TRACKING_MONITOR) { + pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y); + } + + // TODO: this is getting called with extents being 0,0,0,0 should it be? + // potentially can save on resources. + + g_pHyprOpenGL->begin(PMONITOR, &damage); g_pHyprOpenGL->clear(CColor(11, 11, 11, 255)); g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" @@ -186,7 +218,20 @@ void Events::listener_monitorFrame(void* owner, void* data) { g_pHyprOpenGL->end(); + // calc frame damage + pixman_region32_t frameDamage; + pixman_region32_init(&frameDamage); + + const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform); + wlr_region_transform(&frameDamage, &PMONITOR->damage->current, TRANSFORM, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y); + + wlr_output_set_damage(PMONITOR->output, &frameDamage); + pixman_region32_fini(&frameDamage); + pixman_region32_fini(&damage); + wlr_output_commit(PMONITOR->output); + + wlr_output_schedule_frame(PMONITOR->output); } void Events::listener_monitorDestroy(void* owner, void* data) { diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp index d1325102..86373ced 100644 --- a/src/helpers/SubsurfaceTree.cpp +++ b/src/helpers/SubsurfaceTree.cpp @@ -1,5 +1,6 @@ #include "SubsurfaceTree.hpp" #include "../events/Events.hpp" +#include "../Compositor.hpp" void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) { *lx += node->pSurface->sx; @@ -164,6 +165,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) { int lx = 0, ly = 0; addSurfaceGlobalOffset(pNode, &lx, &ly); + + g_pHyprRenderer->damageSurface(pNode->pSurface, lx, ly); } void Events::listener_destroySubsurface(void* owner, void* data) { diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index f02260d0..a26ad4c3 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -101,12 +101,9 @@ void CHyprError::draw() { if (g_pHyprOpenGL->m_RenderData.pMonitor != PMONITOR) return; // wrong mon - const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); - float matrix[9]; wlr_box windowBox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, PMONITOR->output->transform_matrix); - g_pHyprOpenGL->renderTexture(m_tTexture, matrix, 255.f, 0); + g_pHyprOpenGL->renderTexture(m_tTexture, &windowBox, 255.f, 0); } void CHyprError::destroy() { diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 8c1f6e38..f77c3d7c 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -21,8 +21,14 @@ void CAnimationManager::tick() { const auto BORDERACTIVECOL = CColor(g_pConfigManager->getInt("general:col.active_border")); const auto BORDERINACTIVECOL = CColor(g_pConfigManager->getInt("general:col.inactive_border")); + const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); + for (auto& w : g_pCompositor->m_lWindows) { + // get the box before transforms, for damage tracking later + wlr_box WLRBOXPREV = { w.m_vRealPosition.x - BORDERSIZE - 1, w.m_vRealPosition.y - BORDERSIZE - 1, w.m_vRealSize.x + 2 * BORDERSIZE + 2, w.m_vRealSize.y + 2 * BORDERSIZE + 2}; + bool needsDamage = false; + // process fadeinout if (FADEENABLED) { const auto GOALALPHA = w.m_bIsMapped ? 255.f : 0.f; @@ -36,21 +42,34 @@ void CAnimationManager::tick() { w.m_bFadingOut = true; w.m_fAlpha = parabolic(w.m_fAlpha, GOALALPHA, FADESPEED); } + + needsDamage = true; } } else { - if (w.m_bIsMapped) - w.m_fAlpha = 255.f; - else { - w.m_fAlpha = 0.f; - w.m_bFadingOut = false; + const auto GOALALPHA = w.m_bIsMapped ? 255.f : 0.f; + + if (!deltazero(GOALALPHA, w.m_fAlpha)) { + if (w.m_bIsMapped) + w.m_fAlpha = 255.f; + else { + w.m_fAlpha = 0.f; + w.m_bFadingOut = false; + } + + needsDamage = true; } } // process fadein/out for unmapped windows, but nothing else. // we can't use windowValidMapped because we want to animate hidden windows too. - if (!g_pCompositor->windowExists(&w) || !w.m_bIsMapped || !g_pXWaylandManager->getWindowSurface(&w)) + if (!g_pCompositor->windowExists(&w) || !w.m_bIsMapped || !g_pXWaylandManager->getWindowSurface(&w)){ + if (needsDamage) { + g_pHyprRenderer->damageWindow(&w); // only window, it didnt move cuz its unmappy + } + continue; + } // process the borders const auto RENDERHINTS = g_pLayoutManager->getCurrentLayout()->requestRenderHints(&w); @@ -64,8 +83,11 @@ void CAnimationManager::tick() { } else { w.m_cRealBorderColor = parabolic(BORDERSPEED, w.m_cRealBorderColor, COLOR); } + needsDamage = true; } } else { + if (!deltazero(w.m_cRealBorderColor, COLOR)) + needsDamage = true; w.m_cRealBorderColor = COLOR; } @@ -81,11 +103,21 @@ void CAnimationManager::tick() { w.m_vRealPosition = Vector2D(parabolic(w.m_vRealPosition.x, w.m_vEffectivePosition.x, WINDOWSPEED), parabolic(w.m_vRealPosition.y, w.m_vEffectivePosition.y, WINDOWSPEED)); w.m_vRealSize = Vector2D(parabolic(w.m_vRealSize.x, w.m_vEffectiveSize.x, WINDOWSPEED), parabolic(w.m_vRealSize.y, w.m_vEffectiveSize.y, WINDOWSPEED)); } + + needsDamage = true; } } else { + if (!deltazero(w.m_vRealPosition, w.m_vEffectivePosition) || !deltazero(w.m_vRealSize, w.m_vEffectiveSize)) + needsDamage = true; + w.m_vRealPosition = w.m_vEffectivePosition; w.m_vRealSize = w.m_vEffectiveSize; } + + if (needsDamage) { + g_pHyprRenderer->damageBox(&WLRBOXPREV); + g_pHyprRenderer->damageWindow(&w); + } } } @@ -97,10 +129,18 @@ bool CAnimationManager::deltaSmallToFlip(const CColor& a, const CColor& b) { return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f; } +bool CAnimationManager::deltaSmallToFlip(const float& a, const float& b) { + return std::abs(a - b) < 0.5f; +} + bool CAnimationManager::deltazero(const Vector2D& a, const Vector2D& b) { return a.x == b.x && a.y == b.y; } +bool CAnimationManager::deltazero(const float& a, const float& b) { + return a == b; +} + bool CAnimationManager::deltazero(const CColor& a, const CColor& b) { return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; } diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 450bbe2c..8d2c86b6 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -11,8 +11,10 @@ public: private: bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b); bool deltaSmallToFlip(const CColor& a, const CColor& b); + bool deltaSmallToFlip(const float& a, const float& b); bool deltazero(const Vector2D& a, const Vector2D& b); bool deltazero(const CColor& a, const CColor& b); + bool deltazero(const float& a, const float& b); double parabolic(const double, const double, const double); CColor parabolic(const double, const CColor&, const CColor&); }; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index f34b84fc..e9fbe7fe 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -118,7 +118,7 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) { return shader; } -void CHyprOpenGLImpl::begin(SMonitor* pMonitor) { +void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage) { m_RenderData.pMonitor = pMonitor; glViewport(0, 0, pMonitor->vecSize.x, pMonitor->vecSize.y); @@ -145,20 +145,21 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor) { // bind the primary Hypr Framebuffer m_mMonitorRenderResources[pMonitor].primaryFB.bind(); + + m_RenderData.pDamage = pDamage; + + // clear clear(CColor(11, 11, 11, 255)); } void CHyprOpenGLImpl::end() { // end the render, copy the data to the WLR framebuffer glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb); - const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); - float matrix[9]; wlr_box windowBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y}; - wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); clear(CColor(11, 11, 11, 255)); - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, matrix, 255.f, 0); + renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &windowBox, 255.f, 0); // reset our data m_RenderData.pMonitor = nullptr; @@ -169,7 +170,15 @@ void CHyprOpenGLImpl::clear(const CColor& color) { RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!"); glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); - glClear(GL_COLOR_BUFFER_BIT); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + + glClear(GL_COLOR_BUFFER_BIT); + } + } } void CHyprOpenGLImpl::scissor(const wlr_box* pBox) { @@ -184,10 +193,24 @@ void CHyprOpenGLImpl::scissor(const wlr_box* pBox) { glEnable(GL_SCISSOR_TEST); } +void CHyprOpenGLImpl::scissor(const pixman_box32* pBox) { + RASSERT(m_RenderData.pMonitor, "Tried to scissor without begin()!"); + + if (!pBox) { + glDisable(GL_SCISSOR_TEST); + return; + } + + glScissor(pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1); + glEnable(GL_SCISSOR_TEST); +} + void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); + // TODO: respect damage + float matrix[9]; wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here @@ -216,16 +239,34 @@ void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col) { glDisableVertexAttribArray(m_shQUAD.posAttrib); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex,float matrix[9], float alpha, int round) { +void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTexture(CTexture(tex), matrix, alpha, round); + renderTexture(CTexture(tex), pBox, alpha, round); } -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float alpha, int round) { +void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round) { + RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + + renderTextureInternal(tex, pBox, alpha, round); + } + } +} + +void CHyprOpenGLImpl::renderTextureInternal(const CTexture& tex, wlr_box* pBox, float alpha, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + // get transform + const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); + float matrix[9]; + wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); + float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix); @@ -293,16 +334,21 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float // cheers. // 2-pass pseudo-gaussian blur -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9], float a, int round) { +void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); // if blur disabled, just render the texture if (g_pConfigManager->getInt("decoration:blur") == 0) { - renderTexture(tex, matrix, a, round); + renderTexture(tex, pBox, a, round); return; } + // get transform + const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); + float matrix[9]; + wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); + // bind the mirror FB and clear it. m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.bind(); clear(CColor(0, 0, 0, 0)); @@ -317,7 +363,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9] glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // render our window to the mirror FB while also writing to the stencil - renderTexture(tex, matrix, a, round); + renderTexture(tex, pBox, a, round); // then we disable writing to the mask and ONLY accept writing within the stencil glStencilFunc(GL_EQUAL, 1, -1); @@ -332,7 +378,6 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9] // now we make the blur by blurring the main framebuffer (it will only affect the stencil) // matrix - const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); float matrixFull[9]; wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y}; wlr_matrix_project_box(matrixFull, &fullMonBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); @@ -382,7 +427,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9] // when the blur is done, let's render the window itself // we get it from the mirrored FB full because it's the FB 255 alpha cuz we rendered with a before, same for rounding - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex, matrixFull, 255.f, 0); + renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex, &fullMonBox, 255.f, 0); // and disable the stencil glStencilMask(-1); @@ -485,7 +530,16 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); wlr_output_attach_render(PMONITOR->output, nullptr); - begin(PMONITOR); + // we need to "damage" the entire monitor + // so that we render the entire window + // this is temporary, doesnt mess with the actual wlr damage + pixman_region32_t fakeDamage; + pixman_region32_init(&fakeDamage); + pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y); + + begin(PMONITOR, &fakeDamage); + + pixman_region32_fini(&fakeDamage); const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow]; @@ -541,12 +595,9 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); - const auto TRANSFORM = wlr_output_transform_invert(it->second.m_tTransform); - float matrix[9]; wlr_box windowBox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, PMONITOR->output->transform_matrix); - renderTexture(it->second.m_cTex, matrix, PWINDOW->m_fAlpha, 0); + renderTexture(it->second.m_cTex, &windowBox, PWINDOW->m_fAlpha, 0); } void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { @@ -603,10 +654,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { void CHyprOpenGLImpl::clearWithTex() { RASSERT(m_RenderData.pMonitor, "Tried to render BGtex without begin()!"); - const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL); - float matrix[9]; wlr_box box = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y}; - wlr_matrix_project_box(matrix, &box, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); - renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], matrix, 255, 0); + renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0); } \ No newline at end of file diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index c2dded11..97a27997 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -27,6 +27,8 @@ inline const float fullVerts[] = { struct SCurrentRenderData { SMonitor* pMonitor = nullptr; float projection[9]; + + pixman_region32_t* pDamage = nullptr; }; struct SMonitorRenderData { @@ -41,13 +43,13 @@ public: CHyprOpenGLImpl(); - void begin(SMonitor*); + void begin(SMonitor*, pixman_region32_t*); void end(); void renderRect(wlr_box*, const CColor&); - void renderTexture(wlr_texture*, float matrix[9], float a, int round = 0); - void renderTexture(const CTexture&, float matrix[9], float a, int round = 0); - void renderTextureWithBlur(const CTexture&, float matrix[9], float a, int round = 0); + void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); + void renderTexture(const CTexture&, wlr_box*, float a, int round = 0); + void renderTextureWithBlur(const CTexture&, wlr_box*, float a, int round = 0); void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0); void makeWindowSnapshot(CWindow*); @@ -56,6 +58,7 @@ public: void clear(const CColor&); void clearWithTex(); void scissor(const wlr_box*); + void scissor(const pixman_box32*); SCurrentRenderData m_RenderData; @@ -85,6 +88,9 @@ private: GLuint createProgram(const std::string&, const std::string&); GLuint compileShader(const GLuint&, std::string); void createBGTextureForMonitor(SMonitor*); + + void renderTextureInternal(const CTexture&, wlr_box* pBox, float a, int round = 0); + }; inline std::unique_ptr g_pHyprOpenGL; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 922229ea..f7eb1dbe 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -27,20 +27,14 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { } scaleBox(&windowBox, RDATA->output->scale); - const auto TRANSFORM = wlr_output_transform_invert(surface->current.transform); - float matrix[9]; - wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, RDATA->output->transform_matrix); - if (RDATA->surface && surface == RDATA->surface) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); else - g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); wlr_surface_send_frame_done(surface, RDATA->when); wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output); - - g_pHyprOpenGL->scissor(nullptr); } bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) { @@ -432,51 +426,52 @@ void CHyprRenderer::drawBorderForWindow(CWindow* pWindow, SMonitor* pMonitor, fl g_pHyprOpenGL->renderBorder(&border, BORDERCOL, BORDERSIZE, g_pConfigManager->getInt("decoration:rounding")); } -void damageSurfaceIter(struct wlr_surface* surface, int x, int y, void* data) { - auto* renderdata = (SRenderData*)data; - bool entire = (bool*)renderdata->data; +void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { + if (!pSurface) + return; // wut? - wlr_box box = {.x = renderdata->x, .y = renderdata->y, .width = renderdata->w, .height = renderdata->h}; - scaleBox(&box, renderdata->output->scale); + pixman_region32_t damageBox; + pixman_region32_init(&damageBox); + wlr_surface_get_effective_damage(pSurface, &damageBox); - pixman_region32_t damageRegion; - pixman_region32_init(&damageRegion); - wlr_surface_get_effective_damage(renderdata->surface, &damageRegion); - wlr_region_scale(&damageRegion, &damageRegion, renderdata->output->scale); + pixman_region32_translate(&damageBox, x, y); - if (std::ceil(renderdata->output->scale) > renderdata->surface->current.scale) { - wlr_region_expand(&damageRegion, &damageRegion, std::ceil(renderdata->output->scale) - renderdata->surface->current.scale); + for (auto& m : g_pCompositor->m_lMonitors) { + double lx = 0, ly = 0; + wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m.output, &lx, &ly); + pixman_region32_translate(&damageBox, lx, ly); + wlr_output_damage_add(m.damage, &damageBox); + pixman_region32_translate(&damageBox, -lx, -ly); } - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(renderdata->output); + pixman_region32_fini(&damageBox); +} - pixman_region32_translate(&damageRegion, box.x, box.y); - wlr_output_damage_add(PMONITOR->damage, &damageRegion); - pixman_region32_fini(&damageRegion); +void CHyprRenderer::damageWindow(CWindow* pWindow) { + if (!pWindow->m_bIsFloating) { + // damage by size & pos + // TODO TEMP: revise when added shadows/etc - if (entire) - wlr_output_damage_add_box(PMONITOR->damage, &box); - - if (!wl_list_empty(&surface->current.frame_callback_list)) { - wlr_output_schedule_frame(renderdata->output); + wlr_box damageBox = {pWindow->m_vPosition.x, pWindow->m_vPosition.y, pWindow->m_vSize.x, pWindow->m_vSize.y}; + for (auto& m : g_pCompositor->m_lMonitors) + wlr_output_damage_add_box(m.damage, &damageBox); + } else { + // damage by effective size & pos + border size + 1 (JIC) + const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); + wlr_box damageBox = { pWindow->m_vEffectivePosition.x - BORDERSIZE - 1, pWindow->m_vEffectivePosition.y - BORDERSIZE - 1, pWindow->m_vEffectiveSize.x + 2 * BORDERSIZE + 2, pWindow->m_vEffectiveSize.y + 2 * BORDERSIZE + 2}; + for (auto& m : g_pCompositor->m_lMonitors) + wlr_output_damage_add_box(m.damage, &damageBox); } } -void CHyprRenderer::damageSurface(SMonitor* pMonitor, double x, double y, wlr_surface* pSurface, void* data) { - if (!pSurface || !pMonitor) - return; // wut? +void CHyprRenderer::damageMonitor(SMonitor* pMonitor) { + wlr_box damageBox = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; + wlr_output_damage_add_box(pMonitor->damage, &damageBox); +} - SRenderData renderData = { - .output = pMonitor->output, - .x = x, - .y = y, - .data = data, - .surface = pSurface, - .w = pSurface->current.width, - .h = pSurface->current.height - }; - - wlr_surface_for_each_surface(pSurface, damageSurfaceIter, &renderData); +void CHyprRenderer::damageBox(wlr_box* pBox) { + for (auto& m : g_pCompositor->m_lMonitors) + wlr_output_damage_add_box(m.damage, pBox); } void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) { @@ -489,4 +484,15 @@ void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) { renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height; wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata); +} + +DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) { + if (mode == "full") + return DAMAGE_TRACKING_FULL; + if (mode == "monitor") + return DAMAGE_TRACKING_MONITOR; + if (mode == "none") + return DAMAGE_TRACKING_NONE; + + return DAMAGE_TRACKING_INVALID; } \ No newline at end of file diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index feca37aa..27fe9cf6 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -7,13 +7,26 @@ #include "../Window.hpp" #include "OpenGL.hpp" +// TODO: add fuller damage tracking for updating only parts of a window +enum DAMAGETRACKINGMODES { + DAMAGE_TRACKING_INVALID = -1, + DAMAGE_TRACKING_NONE = 0, + DAMAGE_TRACKING_MONITOR, + DAMAGE_TRACKING_FULL +}; + class CHyprRenderer { public: void renderAllClientsForMonitor(const int&, timespec*); void outputMgrApplyTest(wlr_output_configuration_v1*, bool); void arrangeLayersForMonitor(const int&); - void damageSurface(SMonitor*, double, double, wlr_surface*, void*); + void damageSurface(wlr_surface*, double, double); + void damageWindow(CWindow*); + void damageBox(wlr_box*); + void damageMonitor(SMonitor*); + + DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); private: void arrangeLayerArray(SMonitor*, const std::list&, bool, wlr_box*);