diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9bcbdb0f..91a7705d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -425,7 +425,7 @@ void CCompositor::initAllSignals() { for (auto const& m : m_vMonitors) { scheduleFrameForMonitor(m); - g_pHyprRenderer->applyMonitorRule(m, &m->activeMonitorRule, true); + m->applyMonitorRule(&m->activeMonitorRule, true); } g_pConfigManager->m_bWantsMonitorReload = true; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f9ad54aa..a9796bdd 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1495,7 +1495,7 @@ void CConfigManager::performMonitorReload() { auto rule = getMonitorRuleFor(m); - if (!g_pHyprRenderer->applyMonitorRule(m, &rule)) { + if (!m->applyMonitorRule(&rule)) { overAgain = true; break; } @@ -1553,7 +1553,7 @@ void CConfigManager::ensureMonitorStatus() { auto rule = getMonitorRuleFor(rm); if (rule.disabled == rm->m_bEnabled) - g_pHyprRenderer->applyMonitorRule(rm, &rule); + rm->applyMonitorRule(&rule); } } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 89a833d4..3fb90959 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -21,6 +21,8 @@ #include "debug/Log.hpp" #include #include +#include +#include using namespace Hyprutils::String; using namespace Hyprutils::Utils; @@ -85,7 +87,7 @@ void CMonitor::onConnect(bool noRule) { return; Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); - g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true); + applyMonitorRule(&activeMonitorRule, true); return; } @@ -99,7 +101,7 @@ void CMonitor::onConnect(bool noRule) { SMonitorRule rule = activeMonitorRule; rule.resolution = SIZE; - g_pHyprRenderer->applyMonitorRule(self.lock(), &rule); + applyMonitorRule(&rule); }); tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; @@ -172,7 +174,7 @@ void CMonitor::onConnect(bool noRule) { // set mode, also applies if (!noRule) - g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true); + applyMonitorRule(&monitorRule, true); if (!state.commit()) Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); @@ -361,6 +363,379 @@ void CMonitor::onDisconnect(bool destroy) { std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; }); } +bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { + + static auto PDISABLESCALECHECKS = CConfigValue("debug:disable_scale_checks"); + + Debug::log(LOG, "Applying monitor rule for {}", szName); + + activeMonitorRule = *pMonitorRule; + + if (forceSize.has_value()) + activeMonitorRule.resolution = forceSize.value(); + + const auto RULE = &activeMonitorRule; + + // if it's disabled, disable and ignore + if (RULE->disabled) { + if (m_bEnabled) + onDisconnect(); + + events.modeChanged.emit(); + + return true; + } + + // don't touch VR headsets + if (output->nonDesktop) + return true; + + if (!m_bEnabled) { + onConnect(true); // enable it. + Debug::log(LOG, "Monitor {} is disabled but is requested to be enabled", szName); + force = true; + } + + // Check if the rule isn't already applied + // TODO: clean this up lol + if (!force && DELTALESSTHAN(vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(vecPixelSize.y, RULE->resolution.y, 1) && + DELTALESSTHAN(refreshRate, RULE->refreshRate, 1) && setScale == RULE->scale && + ((DELTALESSTHAN(vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(vecPosition.y, RULE->offset.y, 1)) || RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) && + transform == RULE->transform && RULE->enable10bit == enabled10bit && !std::memcmp(&customDrmMode, &RULE->drmMode, sizeof(customDrmMode))) { + + Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", szName); + + setMirror(RULE->mirrorOf); + + return true; + } + + bool autoScale = false; + + if (RULE->scale > 0.1) { + scale = RULE->scale; + } else { + autoScale = true; + const auto DEFAULTSCALE = getDefaultScale(); + scale = DEFAULTSCALE; + } + + setScale = scale; + transform = RULE->transform; + + // accumulate requested modes in reverse order (cause inesrting at front is inefficient) + std::vector> requestedModes; + std::string requestedStr = "preferred"; + + // use sortFunc, add best 3 to requestedModes in reverse, since we test in reverse + auto addBest3Modes = [&](auto const& sortFunc) { + auto sortedModes = output->modes; + std::ranges::sort(sortedModes, sortFunc); + if (sortedModes.size() > 3) + sortedModes.erase(sortedModes.begin() + 3, sortedModes.end()); + requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend()); + }; + + // last fallback is preferred mode, btw this covers resolution == Vector2D() + if (!output->preferredMode()) + Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", output->name); + else + requestedModes.push_back(output->preferredMode()); + + if (RULE->resolution == Vector2D(-1, -1)) { + requestedStr = "highrr"; + + // sort prioritizing refresh rate 1st and resolution 2nd, then add best 3 + addBest3Modes([](auto const& a, auto const& b) { + if (a->refreshRate > b->refreshRate) + return true; + else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1000) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) + return true; + return false; + }); + } else if (RULE->resolution == Vector2D(-1, -2)) { + requestedStr = "highres"; + + // sort prioritizing resultion 1st and refresh rate 2nd, then add best 3 + addBest3Modes([](auto const& a, auto const& b) { + if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) + return true; + else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) && a->refreshRate > b->refreshRate) + return true; + return false; + }); + } else if (RULE->resolution != Vector2D()) { + // user requested mode + requestedStr = std::format("{:X0}@{:.2f}Hz", RULE->resolution, RULE->refreshRate); + + // sort by closeness to requested, then add best 3 + addBest3Modes([&](auto const& a, auto const& b) { + if (abs(a->pixelSize.x - RULE->resolution.x) < abs(b->pixelSize.x - RULE->resolution.x)) + return true; + if (a->pixelSize.x == b->pixelSize.x && abs(a->pixelSize.y - RULE->resolution.y) < abs(b->pixelSize.y - RULE->resolution.y)) + return true; + if (a->pixelSize == b->pixelSize && abs((a->refreshRate / 1000.f) - RULE->refreshRate) < abs((b->refreshRate / 1000.f) - RULE->refreshRate)) + return true; + return false; + }); + + // then if requested is custom, try custom mode first + if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) { + if (output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) + Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); + else + requestedModes.push_back(makeShared( + Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode})); + } + } + + const auto WAS10B = enabled10bit; + const auto OLDRES = vecPixelSize; + bool success = false; + + // Needed in case we are switching from a custom modeline to a standard mode + customDrmMode = {}; + currentMode = nullptr; + + output->state->setFormat(DRM_FORMAT_XRGB8888); + prevDrmFormat = drmFormat; + drmFormat = DRM_FORMAT_XRGB8888; + output->state->resetExplicitFences(); + + if (Debug::trace) { + Debug::log(TRACE, "Monitor {} requested modes:", szName); + for (auto const& mode : requestedModes | std::views::reverse) { + Debug::log(TRACE, "| {:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f); + } + } + + for (auto const& mode : requestedModes | std::views::reverse) { + std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f); + + if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF) { + output->state->setCustomMode(mode); + + if (!state.test()) { + Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr); + continue; + } + + customDrmMode = mode->modeInfo.value(); + } else { + output->state->setMode(mode); + + if (!state.test()) { + Debug::log(ERR, "Monitor {}: REJECTED available mode {}!", szName, modeStr); + if (mode->preferred) + Debug::log(ERR, "Monitor {}: REJECTED preferred mode!!!", szName); + continue; + } + + customDrmMode = {}; + } + + refreshRate = mode->refreshRate / 1000.f; + vecSize = mode->pixelSize; + currentMode = mode; + + success = true; + + if (mode->preferred) + Debug::log(LOG, "Monitor {}: requested {}, using preferred mode {}", szName, requestedStr, modeStr); + else if (mode->modeInfo.has_value() && mode->modeInfo->type == DRM_MODE_TYPE_USERDEF) + Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr); + else + Debug::log(LOG, "Monitor {}: requested {}, using available mode {}", szName, requestedStr, modeStr); + + break; + } + + // try requested as custom mode jic it works + if (!success && RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) { + auto refreshRate = output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0; + auto mode = makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = refreshRate}); + std::string modeStr = std::format("{:X0}@{:.2f}Hz", mode->pixelSize, mode->refreshRate / 1000.f); + + output->state->setCustomMode(mode); + + if (state.test()) { + Debug::log(LOG, "Monitor {}: requested {}, using custom mode {}", szName, requestedStr, modeStr); + + refreshRate = mode->refreshRate / 1000.f; + vecSize = mode->pixelSize; + currentMode = mode; + customDrmMode = {}; + + success = true; + } else + Debug::log(ERR, "Monitor {}: REJECTED custom mode {}!", szName, modeStr); + } + + // try any of the modes if none of the above work + if (!success) { + for (auto const& mode : output->modes) { + output->state->setMode(mode); + + if (!state.test()) + continue; + + auto errorMessage = + std::format("Monitor {} failed to set any requested modes, falling back to mode {:X0}@{:.2f}Hz", szName, mode->pixelSize, mode->refreshRate / 1000.f); + Debug::log(WARN, errorMessage); + g_pHyprNotificationOverlay->addNotification(errorMessage, CHyprColor(0xff0000ff), 5000, ICON_WARNING); + + refreshRate = mode->refreshRate / 1000.f; + vecSize = mode->pixelSize; + currentMode = mode; + customDrmMode = {}; + + success = true; + + break; + } + } + + if (!success) { + Debug::log(ERR, "Monitor {} has NO FALLBACK MODES, and an INVALID one was requested: {:X0}@{:.2f}Hz", szName, RULE->resolution, RULE->refreshRate); + return true; + } + + vrrActive = output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR() + || createdByUser; // wayland backend doesn't allow for disabling adaptive_sync + + vecPixelSize = vecSize; + + // clang-format off + static const std::array>, 2> formats{ + std::vector>{ /* 10-bit */ + {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888} + }, + std::vector>{ /* 8-bit */ + {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888} + } + }; + // clang-format on + + bool set10bit = false; + + for (auto const& fmt : formats[(int)!RULE->enable10bit]) { + output->state->setFormat(fmt.second); + prevDrmFormat = drmFormat; + drmFormat = fmt.second; + + if (!state.test()) { + Debug::log(ERR, "output {} failed basic test on format {}", szName, fmt.first); + } else { + Debug::log(LOG, "output {} succeeded basic test on format {}", szName, fmt.first); + if (RULE->enable10bit && fmt.first.contains("101010")) + set10bit = true; + break; + } + } + + enabled10bit = set10bit; + + Vector2D logicalSize = vecPixelSize / scale; + if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { + // invalid scale, will produce fractional pixels. + // find the nearest valid. + + float searchScale = std::round(scale * 120.0); + bool found = false; + + double scaleZero = searchScale / 120.0; + + Vector2D logicalZero = vecPixelSize / scaleZero; + if (logicalZero == logicalZero.round()) + scale = scaleZero; + else { + for (size_t i = 1; i < 90; ++i) { + double scaleUp = (searchScale + i) / 120.0; + double scaleDown = (searchScale - i) / 120.0; + + Vector2D logicalUp = vecPixelSize / scaleUp; + Vector2D logicalDown = vecPixelSize / scaleDown; + + if (logicalUp == logicalUp.round()) { + found = true; + searchScale = scaleUp; + break; + } + if (logicalDown == logicalDown.round()) { + found = true; + searchScale = scaleDown; + break; + } + } + + if (!found) { + if (autoScale) + scale = std::round(scaleZero); + else { + Debug::log(ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", scale); + g_pConfigManager->addParseError("Invalid scale passed to monitor " + szName + ", failed to find a clean divisor"); + scale = getDefaultScale(); + } + } else { + if (!autoScale) { + Debug::log(ERR, "Invalid scale passed to monitor, {} found suggestion {}", scale, searchScale); + g_pConfigManager->addParseError( + std::format("Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f}", szName, searchScale)); + scale = getDefaultScale(); + } else + scale = searchScale; + } + } + } + + output->scheduleFrame(); + + if (!state.commit()) + Debug::log(ERR, "Couldn't commit output named {}", output->name); + + Vector2D xfmd = transform % 2 == 1 ? Vector2D{vecPixelSize.y, vecPixelSize.x} : vecPixelSize; + vecSize = (xfmd / scale).round(); + vecTransformedSize = xfmd; + + if (createdByUser) { + CBox transformedBox = {0, 0, vecTransformedSize.x, vecTransformedSize.y}; + transformedBox.transform(wlTransformToHyprutils(invertTransform(transform)), vecTransformedSize.x, vecTransformedSize.y); + + vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); + } + + updateMatrix(); + + if (WAS10B != enabled10bit || OLDRES != vecPixelSize) + g_pHyprOpenGL->destroyMonitorResources(self.lock()); + + g_pCompositor->arrangeMonitors(); + + damage.setSize(vecTransformedSize); + + // Set scale for all surfaces on this monitor, needed for some clients + // but not on unsafe state to avoid crashes + if (!g_pCompositor->m_bUnsafeState) { + for (auto const& w : g_pCompositor->m_vWindows) { + w->updateSurfaceScaleTransformDetails(); + } + } + // updato us + g_pHyprRenderer->arrangeLayersForMonitor(ID); + + // reload to fix mirrors + g_pConfigManager->m_bWantsMonitorReload = true; + + Debug::log(LOG, "Monitor {} data dump: res {:X}@{:.2f}Hz, scale {:.2f}, transform {}, pos {:X}, 10b {}", szName, vecPixelSize, refreshRate, scale, (int)transform, vecPosition, + (int)enabled10bit); + + EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); + + events.modeChanged.emit(); + + return true; +} + void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { @@ -530,7 +905,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { setupDefaultWS(RULE); - g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff + applyMonitorRule((SMonitorRule*)&RULE, true); // will apply the offset and stuff } else { PHLMONITOR BACKUPMON = nullptr; for (auto const& m : g_pCompositor->m_vMonitors) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 38c55572..d9f5e88c 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -163,6 +163,7 @@ class CMonitor { // methods void onConnect(bool noRule); void onDisconnect(bool destroy = false); + bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false); void addDamage(const pixman_region32_t* rg); void addDamage(const CRegion* rg); void addDamage(const CBox* box); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e1ad7d60..9e207fbe 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1992,7 +1992,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { continue; auto rule = g_pConfigManager->getMonitorRuleFor(m); - if (!g_pHyprRenderer->applyMonitorRule(m, &rule, true)) { + if (!m->applyMonitorRule(&rule, true)) { overAgain = true; break; } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d8b8a847..f3030d18 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -4,7 +4,6 @@ #include "../helpers/sync/SyncReleaser.hpp" #include #include -#include #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -1831,421 +1830,6 @@ void CHyprRenderer::renderDragIcon(PHLMONITOR pMonitor, timespec* time) { PROTO::data->renderDND(pMonitor, time); } -bool CHyprRenderer::applyMonitorRule(PHLMONITOR pMonitor, SMonitorRule* pMonitorRule, bool force) { - - static auto PDISABLESCALECHECKS = CConfigValue("debug:disable_scale_checks"); - - Debug::log(LOG, "Applying monitor rule for {}", pMonitor->szName); - - pMonitor->activeMonitorRule = *pMonitorRule; - - if (pMonitor->forceSize.has_value()) - pMonitor->activeMonitorRule.resolution = pMonitor->forceSize.value(); - - const auto RULE = &pMonitor->activeMonitorRule; - - // if it's disabled, disable and ignore - if (RULE->disabled) { - if (pMonitor->m_bEnabled) - pMonitor->onDisconnect(); - - pMonitor->events.modeChanged.emit(); - - return true; - } - - // don't touch VR headsets - if (pMonitor->output->nonDesktop) - return true; - - if (!pMonitor->m_bEnabled) { - pMonitor->onConnect(true); // enable it. - Debug::log(LOG, "Monitor {} is disabled but is requested to be enabled", pMonitor->szName); - force = true; - } - - // Check if the rule isn't already applied - // TODO: clean this up lol - if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, RULE->resolution.y, 1) && - DELTALESSTHAN(pMonitor->refreshRate, RULE->refreshRate, 1) && pMonitor->setScale == RULE->scale && - ((DELTALESSTHAN(pMonitor->vecPosition.x, RULE->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, RULE->offset.y, 1)) || - RULE->offset == Vector2D(-INT32_MAX, -INT32_MAX)) && - pMonitor->transform == RULE->transform && RULE->enable10bit == pMonitor->enabled10bit && - !memcmp(&pMonitor->customDrmMode, &RULE->drmMode, sizeof(pMonitor->customDrmMode))) { - - Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", pMonitor->szName); - - pMonitor->setMirror(RULE->mirrorOf); - - return true; - } - - const auto WAS10B = pMonitor->enabled10bit; - const auto OLDRES = pMonitor->vecPixelSize; - - // Needed in case we are switching from a custom modeline to a standard mode - pMonitor->customDrmMode = {}; - pMonitor->currentMode = nullptr; - - pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); - pMonitor->prevDrmFormat = pMonitor->drmFormat; - pMonitor->drmFormat = DRM_FORMAT_XRGB8888; - pMonitor->output->state->resetExplicitFences(); - - bool autoScale = false; - - if (RULE->scale > 0.1) { - pMonitor->scale = RULE->scale; - } else { - autoScale = true; - const auto DEFAULTSCALE = pMonitor->getDefaultScale(); - pMonitor->scale = DEFAULTSCALE; - } - - pMonitor->setScale = pMonitor->scale; - pMonitor->transform = RULE->transform; - - 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 (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { - bool found = false; - - for (auto const& mode : pMonitor->output->modes) { - // if delta of refresh rate, w and h chosen and mode is < 1 we accept it - 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 (!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->pixelSize.x, mode->pixelSize.y, mode->refreshRate); - - found = true; - - pMonitor->refreshRate = mode->refreshRate / 1000.f; - pMonitor->vecSize = mode->pixelSize; - pMonitor->currentMode = mode; - - break; - } - } - - if (!found) { - pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); - pMonitor->vecSize = RULE->resolution; - pMonitor->refreshRate = RULE->refreshRate; - - if (!pMonitor->state.test()) { - Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - - 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); - return true; - } - - // Preferred is valid - 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->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - - 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); - } - } - } else { - // custom resolution - bool fail = false; - - if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) { - 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 - pMonitor->output->state->setCustomMode(makeShared( - Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode})); - } else - pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); - - pMonitor->vecSize = RULE->resolution; - pMonitor->refreshRate = RULE->refreshRate; - - if (fail || !pMonitor->state.test()) { - Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - - 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, - (float)RULE->refreshRate); - return true; - } - - // Preferred is valid - 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->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - - pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; - pMonitor->vecSize = PREFERREDMODE->pixelSize; - pMonitor->customDrmMode = {}; - } 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 (!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)) { - for (auto const& 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 { - for (auto const& 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; - } - } - } - } - - if (!success) { - 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 = 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); - return true; - } - - // Preferred is valid - 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->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - - pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; - pMonitor->vecSize = PREFERREDMODE->pixelSize; - pMonitor->currentMode = PREFERREDMODE; - } else { - - Debug::log(LOG, "Monitor {}: Applying highest mode {}x{}@{:2f}.", pMonitor->output->name, (int)currentWidth, (int)currentHeight, (int)currentRefresh / 1000.f); - - pMonitor->refreshRate = currentRefresh / 1000.f; - pMonitor->vecSize = Vector2D(currentWidth, currentHeight); - } - } - } else { - const auto PREFERREDMODE = pMonitor->output->preferredMode(); - - if (!PREFERREDMODE) { - Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); - - if (!pMonitor->output->modes.empty()) { - for (auto const& mode : pMonitor->output->modes) { - pMonitor->output->state->setMode(mode); - - 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->pixelSize.x, mode->pixelSize.y, mode->refreshRate); - - pMonitor->refreshRate = mode->refreshRate / 1000.f; - pMonitor->vecSize = mode->pixelSize; - pMonitor->currentMode = mode; - - break; - } - } - } else { - // Preferred is valid - pMonitor->output->state->setMode(PREFERREDMODE); - - 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->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR() - || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync - - pMonitor->vecPixelSize = pMonitor->vecSize; - - // clang-format off - static const std::array>, 2> formats{ - std::vector>{ /* 10-bit */ - {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - }, - std::vector>{ /* 8-bit */ - {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - } - }; - // clang-format on - - bool set10bit = false; - - for (auto const& fmt : formats[(int)!RULE->enable10bit]) { - pMonitor->output->state->setFormat(fmt.second); - pMonitor->prevDrmFormat = pMonitor->drmFormat; - pMonitor->drmFormat = 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. - // find the nearest valid. - - float searchScale = std::round(pMonitor->scale * 120.0); - bool found = false; - - double scaleZero = searchScale / 120.0; - - Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero; - if (logicalZero == logicalZero.round()) - pMonitor->scale = scaleZero; - else { - for (size_t i = 1; i < 90; ++i) { - double scaleUp = (searchScale + i) / 120.0; - double scaleDown = (searchScale - i) / 120.0; - - Vector2D logicalUp = pMonitor->vecPixelSize / scaleUp; - Vector2D logicalDown = pMonitor->vecPixelSize / scaleDown; - - if (logicalUp == logicalUp.round()) { - found = true; - searchScale = scaleUp; - break; - } - if (logicalDown == logicalDown.round()) { - found = true; - searchScale = scaleDown; - break; - } - } - - if (!found) { - if (autoScale) - pMonitor->scale = std::round(scaleZero); - else { - Debug::log(ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", pMonitor->scale); - g_pConfigManager->addParseError("Invalid scale passed to monitor " + pMonitor->szName + ", failed to find a clean divisor"); - pMonitor->scale = pMonitor->getDefaultScale(); - } - } else { - if (!autoScale) { - Debug::log(ERR, "Invalid scale passed to monitor, {} found suggestion {}", pMonitor->scale, searchScale); - g_pConfigManager->addParseError( - std::format("Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f}", pMonitor->szName, searchScale)); - pMonitor->scale = pMonitor->getDefaultScale(); - } else - pMonitor->scale = searchScale; - } - } - } - - pMonitor->output->scheduleFrame(); - - if (!pMonitor->state.commit()) - Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name); - - 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(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); - - pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); - } - - pMonitor->updateMatrix(); - - if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize) - g_pHyprOpenGL->destroyMonitorResources(pMonitor); - - g_pCompositor->arrangeMonitors(); - - pMonitor->damage.setSize(pMonitor->vecTransformedSize); - - // Set scale for all surfaces on this monitor, needed for some clients - // but not on unsafe state to avoid crashes - if (!g_pCompositor->m_bUnsafeState) { - for (auto const& w : g_pCompositor->m_vWindows) { - w->updateSurfaceScaleTransformDetails(); - } - } - // updato us - arrangeLayersForMonitor(pMonitor->ID); - - // reload to fix mirrors - g_pConfigManager->m_bWantsMonitorReload = true; - - Debug::log(LOG, "Monitor {} data dump: res {:X}@{:.2f}Hz, scale {:.2f}, transform {}, pos {:X}, 10b {}", pMonitor->szName, pMonitor->vecPixelSize, pMonitor->refreshRate, - pMonitor->scale, (int)pMonitor->transform, pMonitor->vecPosition, (int)pMonitor->enabled10bit); - - EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); - - pMonitor->events.modeChanged.emit(); - - return true; -} - void CHyprRenderer::setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 054f0eea..6900c775 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -57,7 +57,6 @@ class CHyprRenderer { void damageRegion(const CRegion&); void damageMonitor(PHLMONITOR); void damageMirrorsWith(PHLMONITOR, const CRegion&); - bool applyMonitorRule(PHLMONITOR, SMonitorRule*, bool force = false); bool shouldRenderWindow(PHLWINDOW, PHLMONITOR); bool shouldRenderWindow(PHLWINDOW); void ensureCursorRenderingMode();