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
43
src/helpers/CursorShapes.hpp
Normal file
43
src/helpers/CursorShapes.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array<const char*, 35> CURSOR_SHAPE_NAMES = {
|
||||
"invalid",
|
||||
"default",
|
||||
"context-menu",
|
||||
"help",
|
||||
"pointer",
|
||||
"progress",
|
||||
"wait",
|
||||
"cell",
|
||||
"crosshair",
|
||||
"text",
|
||||
"vertical-text",
|
||||
"alias",
|
||||
"copy",
|
||||
"move",
|
||||
"no-drop",
|
||||
"not-allowed",
|
||||
"grab",
|
||||
"grabbing",
|
||||
"e-resize",
|
||||
"n-resize",
|
||||
"ne-resize",
|
||||
"nw-resize",
|
||||
"s-resize",
|
||||
"se-resize",
|
||||
"sw-resize",
|
||||
"w-resize",
|
||||
"ew-resize",
|
||||
"ns-resize",
|
||||
"nesw-resize",
|
||||
"nwse-resize",
|
||||
"col-resize",
|
||||
"row-resize",
|
||||
"all-scroll",
|
||||
"zoom-in",
|
||||
"zoom-out",
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#include "../includes.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include <xf86drm.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
/*
|
||||
DRM formats are LE, while OGL is BE. The two primary formats
|
||||
|
|
@ -309,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) {
|
|||
#endif
|
||||
GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
std::string FormatUtils::drmFormatName(DRMFormat drm) {
|
||||
auto n = drmGetFormatName(drm);
|
||||
std::string name = n;
|
||||
free(n);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string FormatUtils::drmModifierName(uint64_t mod) {
|
||||
auto n = drmGetFormatModifierName(mod);
|
||||
std::string name = n;
|
||||
free(n);
|
||||
return name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "math/Math.hpp"
|
||||
#include <aquamarine/backend/Misc.hpp>
|
||||
|
||||
typedef uint32_t DRMFormat;
|
||||
typedef uint32_t SHMFormat;
|
||||
|
|
@ -18,10 +20,7 @@ struct SPixelFormat {
|
|||
Vector2D blockSize;
|
||||
};
|
||||
|
||||
struct SDRMFormat {
|
||||
uint32_t format = 0;
|
||||
std::vector<uint64_t> mods;
|
||||
};
|
||||
typedef Aquamarine::SDRMFormat SDRMFormat;
|
||||
|
||||
namespace FormatUtils {
|
||||
SHMFormat drmToShm(DRMFormat drm);
|
||||
|
|
@ -34,4 +33,6 @@ namespace FormatUtils {
|
|||
int minStride(const SPixelFormat* const fmt, int32_t width);
|
||||
uint32_t drmFormatToGL(DRMFormat drm);
|
||||
uint32_t glFormatToType(uint32_t gl);
|
||||
std::string drmFormatName(DRMFormat drm);
|
||||
std::string drmModifierName(uint64_t mod);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include <optional>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <optional>
|
||||
#include <string>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "math/Math.hpp"
|
||||
#include <vector>
|
||||
#include <format>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
#include "Monitor.hpp"
|
||||
#include "MiscFunctions.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/GammaControl.hpp"
|
||||
#include "../devices/ITouch.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/PresentationTime.hpp"
|
||||
#include "../protocols/DRMLease.hpp"
|
||||
#include "../protocols/core/Output.hpp"
|
||||
#include "../managers/PointerManager.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "sync/SyncTimeline.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
|
|
@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) {
|
|||
}
|
||||
|
||||
CMonitor::~CMonitor() {
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
|
||||
events.destroy.emit();
|
||||
}
|
||||
|
||||
static void onPresented(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
auto E = (wlr_output_event_present*)data;
|
||||
|
||||
PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags);
|
||||
}
|
||||
|
||||
void CMonitor::onConnect(bool noRule) {
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
hyprListener_monitorPresented.removeCallback();
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor");
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor");
|
||||
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor");
|
||||
hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor");
|
||||
hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor");
|
||||
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor");
|
||||
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor");
|
||||
hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor");
|
||||
|
||||
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||
if (output->supportsExplicit) {
|
||||
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
}
|
||||
|
||||
listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); });
|
||||
listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); });
|
||||
listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); });
|
||||
listeners.needsFrame =
|
||||
output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); });
|
||||
listeners.presented = output->events.present.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d);
|
||||
PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags);
|
||||
});
|
||||
|
||||
listeners.state = output->events.state.registerListener([this](std::any d) {
|
||||
auto E = std::any_cast<Aquamarine::IOutput::SStateEvent>(d);
|
||||
|
||||
if (E.size == Vector2D{}) {
|
||||
// an indication to re-set state
|
||||
// we can't do much for createdByUser displays I think
|
||||
if (createdByUser)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
|
||||
g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!createdByUser)
|
||||
return;
|
||||
|
||||
const auto SIZE = E.size;
|
||||
|
||||
forceSize = SIZE;
|
||||
|
||||
SMonitorRule rule = activeMonitorRule;
|
||||
rule.resolution = SIZE;
|
||||
|
||||
g_pHyprRenderer->applyMonitorRule(this, &rule);
|
||||
});
|
||||
|
||||
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_state_set_enabled(state.wlr(), true);
|
||||
output->state->setEnabled(true);
|
||||
state.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
szName = output->name;
|
||||
|
||||
szDescription = output->description ? output->description : "";
|
||||
szDescription = output->description;
|
||||
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
|
||||
std::erase(szDescription, ',');
|
||||
|
||||
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
|
||||
szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
|
||||
szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial));
|
||||
std::erase(szShortDescription, ',');
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||
if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
|
||||
createdByUser = true; // should be true. WL and Headless backends should be addable / removable
|
||||
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
|
||||
|
|
@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) {
|
|||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_state_set_scale(state.wlr(), 1);
|
||||
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
auto PREFSTATE = wlr_output_preferred_mode(output);
|
||||
|
||||
if (!PREFSTATE) {
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &output->modes, link) {
|
||||
wlr_output_state_set_mode(state.wlr(), mode);
|
||||
|
||||
if (!wlr_output_test_state(output, state.wlr()))
|
||||
continue;
|
||||
|
||||
PREFSTATE = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREFSTATE)
|
||||
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
|
||||
else
|
||||
Debug::log(WARN, "No mode found for disabled output {}", output->name);
|
||||
|
||||
wlr_output_state_set_enabled(state.wlr(), 0);
|
||||
output->state->setEnabled(false);
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
|
||||
|
||||
m_bEnabled = false;
|
||||
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
listeners.frame.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->non_desktop) {
|
||||
if (output->nonDesktop) {
|
||||
Debug::log(LOG, "Not configuring non-desktop output");
|
||||
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
|
||||
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (PROTO::lease)
|
||||
PROTO::lease->offer(self.lock());
|
||||
|
||||
if (!m_bRenderingInitPassed) {
|
||||
output->allocator = nullptr;
|
||||
output->renderer = nullptr;
|
||||
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
|
||||
m_bRenderingInitPassed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SP<CMonitor>* thisWrapper = nullptr;
|
||||
|
|
@ -151,14 +137,14 @@ void CMonitor::onConnect(bool noRule) {
|
|||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_state_set_enabled(state.wlr(), 1);
|
||||
output->state->setEnabled(true);
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
|
||||
Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
|
||||
|
||||
damage.setSize(vecTransformedSize);
|
||||
|
||||
|
|
@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) {
|
|||
|
||||
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR);
|
||||
|
||||
PROTO::gamma->applyGammaToState(this);
|
||||
|
||||
|
|
@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorPresented.removeCallback();
|
||||
hyprListener_monitorDamage.removeCallback();
|
||||
hyprListener_monitorNeedsFrame.removeCallback();
|
||||
hyprListener_monitorCommit.removeCallback();
|
||||
hyprListener_monitorBind.removeCallback();
|
||||
listeners.frame.reset();
|
||||
listeners.presented.reset();
|
||||
listeners.needsFrame.reset();
|
||||
listeners.commit.reset();
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
for (auto& ls : m_aLayerSurfaceLayers[i]) {
|
||||
|
|
@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
|||
activeWorkspace->m_bVisible = false;
|
||||
activeWorkspace.reset();
|
||||
|
||||
wlr_output_state_set_enabled(state.wlr(), false);
|
||||
output->state->setEnabled(false);
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
|
||||
Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor.get() == this)
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
|
||||
|
|
@ -344,9 +328,9 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
|
|||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
damage.damageEntire();
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
} else if (damage.damage(rg))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(const CRegion* rg) {
|
||||
|
|
@ -357,11 +341,11 @@ void CMonitor::addDamage(const CBox* box) {
|
|||
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
|
||||
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
|
||||
damage.damageEntire();
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
if (damage.damage(*box))
|
||||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
|
||||
}
|
||||
|
||||
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
||||
|
|
@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
|||
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
|
||||
|
||||
// skip scheduling extra frames for fullsreen apps with vrr
|
||||
bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow &&
|
||||
activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
bool shouldSkip =
|
||||
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
// keep requested minimum refresh rate
|
||||
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
|
||||
|
|
@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() {
|
|||
static constexpr double MMPERINCH = 25.4;
|
||||
|
||||
const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2));
|
||||
const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2));
|
||||
const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2));
|
||||
|
||||
const auto PPI = DIAGONALPX / DIAGONALIN;
|
||||
|
||||
|
|
@ -767,11 +751,11 @@ Vector2D CMonitor::middle() {
|
|||
}
|
||||
|
||||
void CMonitor::updateMatrix() {
|
||||
wlr_matrix_identity(projMatrix.data());
|
||||
matrixIdentity(projMatrix.data());
|
||||
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
|
||||
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
|
||||
wlr_matrix_transform(projMatrix.data(), transform);
|
||||
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
|
||||
matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
|
||||
matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() {
|
|||
return {vecPosition, vecSize};
|
||||
}
|
||||
|
||||
static void onDoneSource(void* data) {
|
||||
auto pMonitor = (CMonitor*)data;
|
||||
|
||||
if (!PROTO::outputs.contains(pMonitor->szName))
|
||||
return;
|
||||
|
||||
PROTO::outputs.at(pMonitor->szName)->sendDone();
|
||||
}
|
||||
|
||||
void CMonitor::scheduleDone() {
|
||||
if (doneSource)
|
||||
return;
|
||||
|
||||
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
|
||||
}
|
||||
|
||||
bool CMonitor::attemptDirectScanout() {
|
||||
if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked)
|
||||
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
|
||||
|
||||
if (g_pPointerManager->softwareLockedFor(self.lock()))
|
||||
return false;
|
||||
|
||||
const auto PCANDIDATE = solitaryClient.lock();
|
||||
|
||||
if (!PCANDIDATE)
|
||||
return false;
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||
|
||||
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform)
|
||||
return false;
|
||||
|
||||
// we can't scanout shm buffers.
|
||||
if (!PSURFACE->current.buffer->dmabuf().success)
|
||||
return false;
|
||||
|
||||
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
|
||||
// and comes from the appropriate device. This may implode on multi-gpu!!
|
||||
|
||||
output->state->setBuffer(PSURFACE->current.buffer);
|
||||
output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
||||
|
||||
if (!state.test())
|
||||
return false;
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
Debug::log(TRACE, "presentFeedback for DS");
|
||||
PSURFACE->presentFeedback(&now, this, true);
|
||||
|
||||
if (state.commit()) {
|
||||
if (lastScanout.expired()) {
|
||||
lastScanout = PCANDIDATE;
|
||||
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
|
||||
}
|
||||
} else {
|
||||
lastScanout.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CMonitorState::CMonitorState(CMonitor* owner) {
|
||||
m_pOwner = owner;
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
CMonitorState::~CMonitorState() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
;
|
||||
}
|
||||
|
||||
wlr_output_state* CMonitorState::wlr() {
|
||||
return &m_state;
|
||||
}
|
||||
void CMonitorState::ensureBufferPresent() {
|
||||
if (!m_pOwner->output->state->state().enabled) {
|
||||
Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
void CMonitorState::clear() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
m_state = {0};
|
||||
wlr_output_state_init(&m_state);
|
||||
if (m_pOwner->output->state->state().buffer)
|
||||
return;
|
||||
|
||||
// this is required for modesetting being possible and might be missing in case of first tests in the renderer
|
||||
// where we test modes and buffers
|
||||
Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible");
|
||||
m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr));
|
||||
m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain
|
||||
}
|
||||
|
||||
bool CMonitorState::commit() {
|
||||
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
|
||||
clear();
|
||||
if (!updateSwapchain())
|
||||
return false;
|
||||
|
||||
ensureBufferPresent();
|
||||
|
||||
bool ret = m_pOwner->output->commit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CMonitorState::test() {
|
||||
return wlr_output_test_state(m_pOwner->output, &m_state);
|
||||
if (!updateSwapchain())
|
||||
return false;
|
||||
|
||||
ensureBufferPresent();
|
||||
|
||||
return m_pOwner->output->test();
|
||||
}
|
||||
|
||||
bool CMonitorState::updateSwapchain() {
|
||||
auto options = m_pOwner->output->swapchain->currentOptions();
|
||||
const auto& STATE = m_pOwner->output->state->state();
|
||||
const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode;
|
||||
if (!MODE) {
|
||||
Debug::log(WARN, "updateSwapchain: No mode?");
|
||||
return true;
|
||||
}
|
||||
options.format = STATE.drmFormat;
|
||||
options.scanout = true;
|
||||
options.length = 2;
|
||||
options.size = MODE->pixelSize;
|
||||
return m_pOwner->output->swapchain->reconfigure(options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include <optional>
|
||||
#include "signal/Signal.hpp"
|
||||
#include "DamageRing.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <aquamarine/allocator/Swapchain.hpp>
|
||||
|
||||
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
|
||||
enum eAutoDirs {
|
||||
|
|
@ -38,22 +40,21 @@ struct SMonitorRule {
|
|||
};
|
||||
|
||||
class CMonitor;
|
||||
class CSyncTimeline;
|
||||
|
||||
// Class for wrapping the wlr state
|
||||
class CMonitorState {
|
||||
public:
|
||||
CMonitorState(CMonitor* owner);
|
||||
~CMonitorState();
|
||||
|
||||
wlr_output_state* wlr();
|
||||
void clear();
|
||||
// commit() will also clear()
|
||||
bool commit();
|
||||
bool test();
|
||||
bool updateSwapchain();
|
||||
|
||||
private:
|
||||
wlr_output_state m_state = {0};
|
||||
CMonitor* m_pOwner;
|
||||
void ensureBufferPresent();
|
||||
|
||||
CMonitor* m_pOwner;
|
||||
};
|
||||
|
||||
class CMonitor {
|
||||
|
|
@ -61,61 +62,69 @@ class CMonitor {
|
|||
CMonitor();
|
||||
~CMonitor();
|
||||
|
||||
Vector2D vecPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecSize = Vector2D(0, 0);
|
||||
Vector2D vecPixelSize = Vector2D(0, 0);
|
||||
Vector2D vecTransformedSize = Vector2D(0, 0);
|
||||
Vector2D vecPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
|
||||
Vector2D vecSize = Vector2D(0, 0);
|
||||
Vector2D vecPixelSize = Vector2D(0, 0);
|
||||
Vector2D vecTransformedSize = Vector2D(0, 0);
|
||||
|
||||
bool primary = false;
|
||||
bool primary = false;
|
||||
|
||||
uint64_t ID = -1;
|
||||
PHLWORKSPACE activeWorkspace = nullptr;
|
||||
PHLWORKSPACE activeSpecialWorkspace = nullptr;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
uint64_t ID = -1;
|
||||
PHLWORKSPACE activeWorkspace = nullptr;
|
||||
PHLWORKSPACE activeSpecialWorkspace = nullptr;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
std::string szShortDescription = "";
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
std::string szShortDescription = "";
|
||||
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
Vector2D vecReservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D vecReservedBottomRight = Vector2D(0, 0);
|
||||
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
CMonitorState state;
|
||||
CDamageRing damage;
|
||||
CMonitorState state;
|
||||
CDamageRing damage;
|
||||
|
||||
wlr_output* output = nullptr;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
std::optional<Vector2D> forceSize;
|
||||
wlr_output_mode* currentMode = nullptr;
|
||||
SP<Aquamarine::IOutput> output;
|
||||
float refreshRate = 60;
|
||||
int framesToSkip = 0;
|
||||
int forceFullFrames = 0;
|
||||
bool noFrameSchedule = false;
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float xwaylandScale = 1.f;
|
||||
std::array<float, 9> projMatrix = {0};
|
||||
std::optional<Vector2D> forceSize;
|
||||
SP<Aquamarine::SOutputMode> currentMode;
|
||||
SP<Aquamarine::CSwapchain> cursorSwapchain;
|
||||
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
uint32_t drmFormat = DRM_FORMAT_INVALID;
|
||||
bool isUnsafeFallback = false;
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
bool isUnsafeFallback = false;
|
||||
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||
bool renderingActive = false;
|
||||
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
wl_event_source* renderTimer = nullptr; // for RAT
|
||||
bool RATScheduled = false;
|
||||
CTimer lastPresentationTimer;
|
||||
|
||||
SMonitorRule activeMonitorRule;
|
||||
bool isBeingLeased = false;
|
||||
|
||||
WP<CMonitor> self;
|
||||
SMonitorRule activeMonitorRule;
|
||||
|
||||
// explicit sync
|
||||
SP<CSyncTimeline> inTimeline;
|
||||
SP<CSyncTimeline> outTimeline;
|
||||
uint64_t lastWaitPoint = 0;
|
||||
uint64_t commitSeq = 0;
|
||||
|
||||
WP<CMonitor> self;
|
||||
|
||||
// mirroring
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
|
|
@ -124,6 +133,9 @@ class CMonitor {
|
|||
// for tearing
|
||||
PHLWINDOWREF solitaryClient;
|
||||
|
||||
// for direct scanout
|
||||
PHLWINDOWREF lastScanout;
|
||||
|
||||
struct {
|
||||
bool canTear = false;
|
||||
bool nextRenderTorn = false;
|
||||
|
|
@ -143,15 +155,6 @@ class CMonitor {
|
|||
|
||||
std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers;
|
||||
|
||||
DYNLISTENER(monitorFrame);
|
||||
DYNLISTENER(monitorDestroy);
|
||||
DYNLISTENER(monitorStateRequest);
|
||||
DYNLISTENER(monitorDamage);
|
||||
DYNLISTENER(monitorNeedsFrame);
|
||||
DYNLISTENER(monitorCommit);
|
||||
DYNLISTENER(monitorBind);
|
||||
DYNLISTENER(monitorPresented);
|
||||
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect(bool destroy = false);
|
||||
|
|
@ -173,6 +176,8 @@ class CMonitor {
|
|||
int64_t activeWorkspaceID();
|
||||
int64_t activeSpecialWorkspaceID();
|
||||
CBox logicalBox();
|
||||
void scheduleDone();
|
||||
bool attemptDirectScanout();
|
||||
|
||||
bool m_bEnabled = false;
|
||||
bool m_bRenderingInitPassed = false;
|
||||
|
|
@ -184,6 +189,17 @@ class CMonitor {
|
|||
}
|
||||
|
||||
private:
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
int findAvailableDefaultWS();
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
int findAvailableDefaultWS();
|
||||
|
||||
wl_event_source* doneSource = nullptr;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener frame;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener state;
|
||||
CHyprSignalListener needsFrame;
|
||||
CHyprSignalListener presented;
|
||||
CHyprSignalListener commit;
|
||||
} listeners;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ class IPointer;
|
|||
class IKeyboard;
|
||||
class CWLSurfaceResource;
|
||||
|
||||
AQUAMARINE_FORWARD(ISwitch);
|
||||
|
||||
struct SRenderData {
|
||||
CMonitor* pMonitor;
|
||||
timespec* when;
|
||||
|
|
@ -70,14 +72,14 @@ struct SSwipeGesture {
|
|||
};
|
||||
|
||||
struct SSwitchDevice {
|
||||
wlr_input_device* pWlrDevice = nullptr;
|
||||
WP<Aquamarine::ISwitch> pDevice;
|
||||
|
||||
int status = -1; // uninitialized
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(toggle);
|
||||
struct {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener fire;
|
||||
} listeners;
|
||||
|
||||
bool operator==(const SSwitchDevice& other) const {
|
||||
return pWlrDevice == other.pWlrDevice;
|
||||
return pDevice == other.pDevice;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
inline bool wlr_backend_is_x11(void*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void wlr_x11_output_create(void*) {}
|
||||
|
|
@ -17,14 +17,14 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
|
|||
return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL;
|
||||
}
|
||||
|
||||
static void matrixIdentity(float mat[9]) {
|
||||
void matrixIdentity(float mat[9]) {
|
||||
static const float identity[9] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
memcpy(mat, identity, sizeof(identity));
|
||||
}
|
||||
|
||||
static void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
|
||||
void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
|
||||
float product[9];
|
||||
|
||||
product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
|
||||
|
|
@ -42,141 +42,56 @@ static void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
|
|||
memcpy(mat, product, sizeof(product));
|
||||
}
|
||||
|
||||
static void matrixTranspose(float mat[9], const float a[9]) {
|
||||
void matrixTranspose(float mat[9], const float a[9]) {
|
||||
float transposition[9] = {
|
||||
a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8],
|
||||
};
|
||||
memcpy(mat, transposition, sizeof(transposition));
|
||||
}
|
||||
|
||||
static void matrixTranslate(float mat[9], float x, float y) {
|
||||
void matrixTranslate(float mat[9], float x, float y) {
|
||||
float translate[9] = {
|
||||
1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, translate);
|
||||
}
|
||||
|
||||
static void matrixScale(float mat[9], float x, float y) {
|
||||
void matrixScale(float mat[9], float x, float y) {
|
||||
float scale[9] = {
|
||||
x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, scale);
|
||||
}
|
||||
|
||||
static void matrixRotate(float mat[9], float rad) {
|
||||
void matrixRotate(float mat[9], float rad) {
|
||||
float rotate[9] = {
|
||||
cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
};
|
||||
matrixMultiply(mat, mat, rotate);
|
||||
}
|
||||
|
||||
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
|
||||
{HYPRUTILS_TRANSFORM_NORMAL,
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_90,
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_180,
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_270,
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED,
|
||||
{
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_90,
|
||||
{
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_180,
|
||||
{
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_270,
|
||||
{
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
}},
|
||||
};
|
||||
|
||||
static void matrixTransform(float mat[9], eTransform transform) {
|
||||
matrixMultiply(mat, mat, transforms.at(transform).data());
|
||||
const std::unordered_map<eTransform, std::array<float, 9>>& getTransforms() {
|
||||
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
|
||||
{HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
};
|
||||
return transforms;
|
||||
}
|
||||
|
||||
static void matrixProjection(float mat[9], int width, int height, eTransform transform) {
|
||||
void matrixTransform(float mat[9], eTransform transform) {
|
||||
matrixMultiply(mat, mat, getTransforms().at(transform).data());
|
||||
}
|
||||
|
||||
void matrixProjection(float mat[9], int width, int height, eTransform transform) {
|
||||
memset(mat, 0, sizeof(*mat) * 9);
|
||||
|
||||
const float* t = transforms.at(transform).data();
|
||||
const float* t = getTransforms().at(transform).data();
|
||||
float x = 2.0f / width;
|
||||
float y = 2.0f / height;
|
||||
|
||||
|
|
@ -219,3 +134,10 @@ void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, c
|
|||
|
||||
matrixMultiply(mat, projection, mat);
|
||||
}
|
||||
|
||||
wl_output_transform invertTransform(wl_output_transform tr) {
|
||||
if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED))
|
||||
tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,14 @@
|
|||
|
||||
using namespace Hyprutils::Math;
|
||||
|
||||
eTransform wlTransformToHyprutils(wl_output_transform t);
|
||||
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
|
||||
eTransform wlTransformToHyprutils(wl_output_transform t);
|
||||
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
|
||||
void matrixProjection(float mat[9], int width, int height, eTransform transform);
|
||||
void matrixTransform(float mat[9], eTransform transform);
|
||||
void matrixRotate(float mat[9], float rad);
|
||||
void matrixScale(float mat[9], float x, float y);
|
||||
void matrixTranslate(float mat[9], float x, float y);
|
||||
void matrixTranspose(float mat[9], const float a[9]);
|
||||
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
|
||||
void matrixIdentity(float mat[9]);
|
||||
wl_output_transform invertTransform(wl_output_transform tr);
|
||||
|
|
|
|||
190
src/helpers/sync/SyncTimeline.cpp
Normal file
190
src/helpers/sync/SyncTimeline.cpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
#include "SyncTimeline.hpp"
|
||||
#include "../../defines.hpp"
|
||||
#include "../../managers/eventLoop/EventLoopManager.hpp"
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
|
||||
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
|
||||
timeline->drmFD = drmFD_;
|
||||
timeline->self = timeline;
|
||||
|
||||
if (drmSyncobjCreate(drmFD_, 0, &timeline->handle)) {
|
||||
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj??");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
|
||||
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
|
||||
timeline->drmFD = drmFD_;
|
||||
timeline->self = timeline;
|
||||
|
||||
if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
|
||||
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
CSyncTimeline::~CSyncTimeline() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
drmSyncobjDestroy(drmFD, handle);
|
||||
}
|
||||
|
||||
std::optional<bool> CSyncTimeline::check(uint64_t point, uint32_t flags) {
|
||||
#ifdef __FreeBSD__
|
||||
constexpr int ETIME_ERR = ETIMEDOUT;
|
||||
#else
|
||||
constexpr int ETIME_ERR = ETIME;
|
||||
#endif
|
||||
|
||||
uint32_t signaled = 0;
|
||||
int ret = drmSyncobjTimelineWait(drmFD, &handle, &point, 1, 0, flags, &signaled);
|
||||
if (ret != 0 && ret != -ETIME_ERR) {
|
||||
Debug::log(ERR, "CSyncTimeline::check: drmSyncobjTimelineWait failed");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
static int handleWaiterFD(int fd, uint32_t mask, void* data) {
|
||||
auto waiter = (CSyncTimeline::SWaiter*)data;
|
||||
|
||||
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
|
||||
Debug::log(ERR, "handleWaiterFD: eventfd error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
uint64_t value = 0;
|
||||
if (read(fd, &value, sizeof(value)) <= 0)
|
||||
Debug::log(ERR, "handleWaiterFD: failed to read from eventfd");
|
||||
}
|
||||
|
||||
wl_event_source_remove(waiter->source);
|
||||
waiter->source = nullptr;
|
||||
|
||||
if (waiter->fn)
|
||||
waiter->fn();
|
||||
|
||||
if (waiter->timeline)
|
||||
waiter->timeline->removeWaiter(waiter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CSyncTimeline::addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags) {
|
||||
auto w = makeShared<SWaiter>();
|
||||
w->fn = waiter;
|
||||
w->timeline = self;
|
||||
|
||||
int eventFD = eventfd(0, EFD_CLOEXEC);
|
||||
|
||||
if (eventFD < 0) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd");
|
||||
return false;
|
||||
}
|
||||
|
||||
drm_syncobj_eventfd syncobjEventFD = {
|
||||
.handle = handle,
|
||||
.flags = flags,
|
||||
.point = point,
|
||||
.fd = eventFD,
|
||||
};
|
||||
|
||||
if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed");
|
||||
close(eventFD);
|
||||
return false;
|
||||
}
|
||||
|
||||
w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get());
|
||||
if (!w->source) {
|
||||
Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed");
|
||||
close(eventFD);
|
||||
return false;
|
||||
}
|
||||
|
||||
waiters.emplace_back(w);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSyncTimeline::removeWaiter(SWaiter* w) {
|
||||
if (w->source) {
|
||||
wl_event_source_remove(w->source);
|
||||
w->source = nullptr;
|
||||
}
|
||||
std::erase_if(waiters, [w](const auto& e) { return e.get() == w; });
|
||||
}
|
||||
|
||||
int CSyncTimeline::exportAsSyncFileFD(uint64_t src) {
|
||||
int sync = -1;
|
||||
|
||||
uint32_t syncHandle = 0;
|
||||
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) {
|
||||
Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return sync;
|
||||
}
|
||||
|
||||
bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) {
|
||||
uint32_t syncHandle = 0;
|
||||
|
||||
if (drmSyncobjCreate(drmFD, 0, &syncHandle)) {
|
||||
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjCreate failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) {
|
||||
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) {
|
||||
Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed");
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
drmSyncobjDestroy(drmFD, syncHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSyncTimeline::transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint) {
|
||||
if (drmFD != from->drmFD) {
|
||||
Debug::log(ERR, "CSyncTimeline::transfer: cannot transfer timelines between gpus, {} -> {}", from->drmFD, drmFD);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmSyncobjTransfer(drmFD, handle, toPoint, from->handle, fromPoint, 0)) {
|
||||
Debug::log(ERR, "CSyncTimeline::transfer: drmSyncobjTransfer failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
47
src/helpers/sync/SyncTimeline.hpp
Normal file
47
src/helpers/sync/SyncTimeline.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "../memory/Memory.hpp"
|
||||
|
||||
/*
|
||||
Hyprland synchronization timelines are based on the wlroots' ones, which
|
||||
are based on Vk timeline semaphores: https://www.khronos.org/blog/vulkan-timeline-semaphores
|
||||
*/
|
||||
|
||||
struct wl_event_source;
|
||||
|
||||
class CSyncTimeline {
|
||||
public:
|
||||
static SP<CSyncTimeline> create(int drmFD_);
|
||||
static SP<CSyncTimeline> create(int drmFD_, int drmSyncobjFD);
|
||||
~CSyncTimeline();
|
||||
|
||||
struct SWaiter {
|
||||
std::function<void()> fn;
|
||||
wl_event_source* source = nullptr;
|
||||
WP<CSyncTimeline> timeline;
|
||||
};
|
||||
|
||||
// check if the timeline point has been signaled
|
||||
// flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
|
||||
// std::nullopt on fail
|
||||
std::optional<bool> check(uint64_t point, uint32_t flags);
|
||||
|
||||
bool addWaiter(const std::function<void()>& waiter, uint64_t point, uint32_t flags);
|
||||
void removeWaiter(SWaiter*);
|
||||
int exportAsSyncFileFD(uint64_t src);
|
||||
bool importFromSyncFileFD(uint64_t dst, int fd);
|
||||
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
|
||||
|
||||
int drmFD = -1;
|
||||
uint32_t handle = 0;
|
||||
WP<CSyncTimeline> self;
|
||||
|
||||
private:
|
||||
CSyncTimeline() = default;
|
||||
|
||||
std::vector<SP<SWaiter>> waiters;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue