Compare commits
58 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
561f50bfae | |
|
|
23c7925dd3 | |
|
|
7cc3d3179c | |
|
|
abb3c81c59 | |
|
|
3989aa9b2f | |
|
|
ddf6987b53 | |
|
|
31e692b20d | |
|
|
9a3161ad4c | |
|
|
a17f9218d9 | |
|
|
41d842669b | |
|
|
1c3256287c | |
|
|
2cd1f78241 | |
|
|
b02d4f4d72 | |
|
|
b474796cdb | |
|
|
1e43d9a719 | |
|
|
8079098326 | |
|
|
00d51a053c | |
|
|
696a5ad4ec | |
|
|
71da3e00a0 | |
|
|
7f8df01d42 | |
|
|
2bff4a4521 | |
|
|
2d29c86d69 | |
|
|
71d49670fe | |
|
|
cd152140fd | |
|
|
05f4efca81 | |
|
|
4f6642808b | |
|
|
e947af7894 | |
|
|
589346162f | |
|
|
9312aa2827 | |
|
|
9b33a38f86 | |
|
|
295d37df17 | |
|
|
daf96f0da7 | |
|
|
c94060b22c | |
|
|
1a7ca38fa3 | |
|
|
131ed05f99 | |
|
|
940980244e | |
|
|
21f9c44789 | |
|
|
8a8afd3896 | |
|
|
6f5adc0568 | |
|
|
a70fc6a2fd | |
|
|
18c6a8ccaf | |
|
|
339337cc7b | |
|
|
7c3565f9be | |
|
|
9ccb4411ee | |
|
|
544395c1b0 | |
|
|
4918e57979 | |
|
|
f95d150937 | |
|
|
0ab8ffa67d | |
|
|
a7d77c60ee | |
|
|
0720a5cbae | |
|
|
353dc1b729 | |
|
|
744a383a52 | |
|
|
e569340c6b | |
|
|
4a1424e85b | |
|
|
07eb70afb1 | |
|
|
4c72cd4d0b | |
|
|
601f6cf95c | |
|
|
7a84686b4a |
|
|
@ -59,8 +59,8 @@ target_include_directories(
|
|||
PUBLIC "./include"
|
||||
PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}")
|
||||
set_target_properties(aquamarine PROPERTIES VERSION ${AQUAMARINE_VERSION}
|
||||
SOVERSION 0)
|
||||
target_link_libraries(aquamarine OpenGL::EGL OpenGL::GL PkgConfig::deps)
|
||||
SOVERSION 2)
|
||||
target_link_libraries(aquamarine OpenGL::EGL OpenGL::OpenGL PkgConfig::deps)
|
||||
|
||||
check_include_file("sys/timerfd.h" HAS_TIMERFD)
|
||||
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
|
||||
|
|
@ -71,8 +71,8 @@ endif()
|
|||
# Protocols
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||
pkg_get_variable(WAYLAND_CLIENT_DIR wayland-client pkgdatadir)
|
||||
message(STATUS "Found wayland-client at ${WAYLAND_CLIENT_DIR}")
|
||||
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
|
||||
message(STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
|
||||
|
||||
function(protocolNew protoPath protoName external)
|
||||
if(external)
|
||||
|
|
@ -94,7 +94,7 @@ function(protocolWayland)
|
|||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||
COMMAND hyprwayland-scanner --wayland-enums --client
|
||||
${WAYLAND_CLIENT_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(aquamarine PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ Unless specified otherwise, a variable is enabled if and only if it's set to `1`
|
|||
|
||||
### DRM
|
||||
|
||||
`AQ_DRM_DEVICES` -> Set an explicit list of DRM devices (GPUs) to use. It's a colon-separated list of paths, with the first being the primary. E.g. `/dev/dri/card1:/dev/dri/card0`
|
||||
`AQ_NO_ATOMIC` -> Disables drm atomic modesetting
|
||||
`AQ_MGPU_NO_EXPLICIT` -> Disables explicit syncing on mgpu buffers
|
||||
|
||||
### Debugging
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@
|
|||
localSystem.system = system;
|
||||
overlays = with self.overlays; [aquamarine];
|
||||
});
|
||||
pkgsCrossFor = eachSystem (system: crossSystem:
|
||||
import nixpkgs {
|
||||
localSystem = system;
|
||||
crossSystem = crossSystem;
|
||||
overlays = with self.overlays; [aquamarine];
|
||||
});
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
(builtins.substring 4 2 longDate)
|
||||
|
|
@ -72,6 +78,7 @@
|
|||
packages = eachSystem (system: {
|
||||
default = self.packages.${system}.aquamarine;
|
||||
inherit (pkgsFor.${system}) aquamarine aquamarine-with-tests;
|
||||
aquamarine-cross = (pkgsCrossFor.${system} "aarch64-linux").aquamarine;
|
||||
});
|
||||
|
||||
formatter = eachSystem (system: pkgsFor.${system}.alejandra);
|
||||
|
|
|
|||
|
|
@ -14,11 +14,16 @@ namespace Aquamarine {
|
|||
bool scanout = false, cursor = false, multigpu = false;
|
||||
};
|
||||
|
||||
enum eAllocatorType {
|
||||
AQ_ALLOCATOR_TYPE_GBM = 0,
|
||||
};
|
||||
|
||||
class IAllocator {
|
||||
public:
|
||||
virtual ~IAllocator() = default;
|
||||
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain) = 0;
|
||||
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
|
||||
virtual int drmFD() = 0;
|
||||
virtual eAllocatorType type() = 0;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ namespace Aquamarine {
|
|||
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain_);
|
||||
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
|
||||
virtual int drmFD();
|
||||
virtual eAllocatorType type();
|
||||
|
||||
//
|
||||
Hyprutils::Memory::CWeakPointer<CGBMAllocator> self;
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ namespace Aquamarine {
|
|||
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
|
||||
virtual bool createOutput(const std::string& name = "") = 0; // "" means auto
|
||||
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator() = 0;
|
||||
virtual std::vector<SDRMFormat> getRenderableFormats(); // empty = use getRenderFormats
|
||||
};
|
||||
|
||||
class CBackend {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ namespace Aquamarine {
|
|||
struct SDRMCRTC {
|
||||
uint32_t id = 0;
|
||||
std::vector<SDRMLayer> layers;
|
||||
int32_t refresh = 0;
|
||||
int32_t refresh = 0; // unused
|
||||
|
||||
struct {
|
||||
int gammaSize = 0;
|
||||
|
|
@ -194,7 +194,7 @@ namespace Aquamarine {
|
|||
virtual bool test();
|
||||
virtual Hyprutils::Memory::CSharedPointer<IBackendImplementation> getBackend();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord);
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord, bool skipSchedule = false);
|
||||
virtual void scheduleFrame(const scheduleFrameReason reason = AQ_SCHEDULE_UNKNOWN);
|
||||
virtual void setCursorVisible(bool visible);
|
||||
virtual Hyprutils::Math::Vector2D cursorPlaneSize();
|
||||
|
|
@ -209,6 +209,8 @@ namespace Aquamarine {
|
|||
Hyprutils::Math::Vector2D cursorPos; // without hotspot
|
||||
Hyprutils::Math::Vector2D cursorHotspot;
|
||||
|
||||
bool enabledState = true; // actual enabled state. Should be synced with state->state().enabled after a new frame
|
||||
|
||||
private:
|
||||
CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_);
|
||||
|
||||
|
|
@ -265,6 +267,7 @@ namespace Aquamarine {
|
|||
void applyCommit(const SDRMConnectorCommitData& data);
|
||||
void rollbackCommit(const SDRMConnectorCommitData& data);
|
||||
void onPresent();
|
||||
void recheckCRTCProps();
|
||||
|
||||
Hyprutils::Memory::CSharedPointer<CDRMOutput> output;
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
|
||||
|
|
@ -320,11 +323,12 @@ namespace Aquamarine {
|
|||
|
||||
class IDRMImplementation {
|
||||
public:
|
||||
virtual ~IDRMImplementation() = default;
|
||||
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) = 0;
|
||||
virtual bool reset() = 0;
|
||||
|
||||
// moving a cursor IIRC is almost instant on most hardware so we don't have to wait for a commit.
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) = 0;
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, bool skipSchedule = false) = 0;
|
||||
};
|
||||
|
||||
class CDRMBackend : public IBackendImplementation {
|
||||
|
|
@ -342,6 +346,7 @@ namespace Aquamarine {
|
|||
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||
virtual bool createOutput(const std::string& name = "");
|
||||
virtual Hyprutils::Memory::CSharedPointer<IAllocator> preferredAllocator();
|
||||
virtual std::vector<SDRMFormat> getRenderableFormats();
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
|
||||
|
||||
|
|
@ -362,20 +367,20 @@ namespace Aquamarine {
|
|||
bool initMgpu();
|
||||
bool grabFormats();
|
||||
bool shouldBlit();
|
||||
void scanConnectors();
|
||||
void scanConnectors(bool allowConnect = true);
|
||||
void scanLeases();
|
||||
void restoreAfterVT();
|
||||
void recheckCRTCs();
|
||||
void buildGlFormats(const std::vector<SGLFormat>& fmts);
|
||||
|
||||
Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu;
|
||||
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;
|
||||
|
||||
// multigpu state, only present if this backend is not primary, aka if this->primary != nullptr
|
||||
struct {
|
||||
Hyprutils::Memory::CSharedPointer<IAllocator> allocator;
|
||||
Hyprutils::Memory::CSharedPointer<CDRMRenderer> renderer;
|
||||
} mgpu;
|
||||
Hyprutils::Memory::CSharedPointer<CDRMRenderer> renderer; // may be null if creation fails
|
||||
} rendererState;
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||
|
||||
|
|
@ -383,6 +388,7 @@ namespace Aquamarine {
|
|||
std::vector<Hyprutils::Memory::CSharedPointer<SDRMPlane>> planes;
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SDRMConnector>> connectors;
|
||||
std::vector<SDRMFormat> formats;
|
||||
std::vector<SDRMFormat> glFormats;
|
||||
|
||||
bool atomic = false;
|
||||
|
||||
|
|
@ -411,5 +417,6 @@ namespace Aquamarine {
|
|||
friend class CDRMAtomicImpl;
|
||||
friend class CDRMAtomicRequest;
|
||||
friend class CDRMLease;
|
||||
friend class CGBMBuffer;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
#include <vector>
|
||||
|
||||
namespace Aquamarine {
|
||||
struct SGLFormat {
|
||||
uint32_t drmFormat = 0;
|
||||
uint64_t modifier = 0;
|
||||
bool external = false;
|
||||
};
|
||||
|
||||
struct SDRMFormat {
|
||||
uint32_t drmFormat = 0; /* DRM_FORMAT_INVALID */
|
||||
std::vector<uint64_t> modifiers;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ namespace Aquamarine {
|
|||
virtual bool test();
|
||||
virtual Hyprutils::Memory::CSharedPointer<IBackendImplementation> getBackend();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord);
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord, bool skipSchedule = false);
|
||||
virtual void scheduleFrame(const scheduleFrameReason reason = AQ_SCHEDULE_UNKNOWN);
|
||||
virtual Hyprutils::Math::Vector2D cursorPlaneSize();
|
||||
virtual bool destroy();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Aquamarine {
|
|||
CDRMAtomicImpl(Hyprutils::Memory::CSharedPointer<CDRMBackend> backend_);
|
||||
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
virtual bool reset();
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, bool skipSchedule = false);
|
||||
|
||||
private:
|
||||
bool prepareConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ namespace Aquamarine {
|
|||
CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDRMBackend> backend_);
|
||||
virtual bool commit(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
virtual bool reset();
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);
|
||||
virtual bool moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, bool skipSchedule = false);
|
||||
|
||||
private:
|
||||
|
||||
bool commitInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
bool testInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
bool commitInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
bool testInternal(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data);
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ namespace Aquamarine {
|
|||
AQ_SCHEDULE_NEW_MONITOR,
|
||||
AQ_SCHEDULE_RENDER_MONITOR,
|
||||
AQ_SCHEDULE_NEEDS_FRAME,
|
||||
AQ_SCHEDULE_ANIMATION,
|
||||
AQ_SCHEDULE_ANIMATION_DAMAGE,
|
||||
};
|
||||
|
||||
virtual bool commit() = 0;
|
||||
|
|
@ -121,7 +123,7 @@ namespace Aquamarine {
|
|||
virtual std::vector<SDRMFormat> getRenderFormats() = 0;
|
||||
virtual Hyprutils::Memory::CSharedPointer<SOutputMode> preferredMode();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord); // includes the hotspot
|
||||
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord, bool skipSchedule = false); // includes the hotspot
|
||||
virtual void setCursorVisible(bool visible); // moving the cursor will make it visible again without this util
|
||||
virtual Hyprutils::Math::Vector2D cursorPlaneSize(); // -1, -1 means no set size, 0, 0 means error
|
||||
virtual void scheduleFrame(const scheduleFrameReason reason = AQ_SCHEDULE_UNKNOWN);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
udev,
|
||||
wayland,
|
||||
wayland-protocols,
|
||||
# wayland-scanner,
|
||||
version ? "git",
|
||||
doCheck ? false,
|
||||
}:
|
||||
|
|
@ -25,13 +26,18 @@ stdenv.mkDerivation {
|
|||
inherit version doCheck;
|
||||
src = ../.;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
hyprwayland-scanner
|
||||
pkg-config
|
||||
# re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable
|
||||
# wayland-scanner
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
hwdata
|
||||
hyprutils
|
||||
libdisplay-info
|
||||
libdrm
|
||||
|
|
@ -46,10 +52,6 @@ stdenv.mkDerivation {
|
|||
wayland-protocols
|
||||
];
|
||||
|
||||
depsBuildBuild = [
|
||||
hwdata
|
||||
];
|
||||
|
||||
outputs = ["out" "dev"];
|
||||
|
||||
cmakeBuildType = "RelWithDebInfo";
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
#include <aquamarine/allocator/GBM.hpp>
|
||||
#include <aquamarine/backend/Backend.hpp>
|
||||
#include <aquamarine/backend/DRM.hpp>
|
||||
#include <aquamarine/allocator/Swapchain.hpp>
|
||||
#include "FormatUtils.hpp"
|
||||
#include "Shared.hpp"
|
||||
#include <xf86drm.h>
|
||||
#include <gbm.h>
|
||||
#include <unistd.h>
|
||||
#include "../backend/drm/Renderer.hpp"
|
||||
|
||||
using namespace Aquamarine;
|
||||
using namespace Hyprutils::Memory;
|
||||
#define SP CSharedPointer
|
||||
|
||||
static SDRMFormat guessFormatFrom(std::vector<SDRMFormat> formats, bool cursor) {
|
||||
static SDRMFormat guessFormatFrom(std::vector<SDRMFormat> formats, bool cursor, bool scanout) {
|
||||
if (formats.empty())
|
||||
return SDRMFormat{};
|
||||
|
||||
|
|
@ -20,20 +22,29 @@ static SDRMFormat guessFormatFrom(std::vector<SDRMFormat> formats, bool cursor)
|
|||
Try to find 10bpp formats first, as they offer better color precision.
|
||||
For cursors, don't, as these almost never support that.
|
||||
*/
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_ARGB2101010; }); it != formats.end())
|
||||
return *it;
|
||||
if (!scanout) {
|
||||
if (auto it =
|
||||
std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_ARGB2101010 || f.drmFormat == DRM_FORMAT_ABGR2101010; });
|
||||
it != formats.end())
|
||||
return *it;
|
||||
}
|
||||
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_XRGB2101010; }); it != formats.end())
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_XRGB2101010 || f.drmFormat == DRM_FORMAT_XBGR2101010; });
|
||||
it != formats.end())
|
||||
return *it;
|
||||
}
|
||||
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_ARGB8888; }); it != formats.end())
|
||||
if (!scanout) {
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_ARGB8888 || f.drmFormat == DRM_FORMAT_ABGR8888; });
|
||||
it != formats.end())
|
||||
return *it;
|
||||
}
|
||||
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_XRGB8888 || f.drmFormat == DRM_FORMAT_XBGR8888; });
|
||||
it != formats.end())
|
||||
return *it;
|
||||
|
||||
if (auto it = std::find_if(formats.begin(), formats.end(), [](const auto& f) { return f.drmFormat == DRM_FORMAT_XRGB8888; }); it != formats.end())
|
||||
return *it;
|
||||
|
||||
for (auto& f : formats) {
|
||||
for (auto const& f : formats) {
|
||||
auto name = fourccToName(f.drmFormat);
|
||||
|
||||
/* 10 bpp RGB */
|
||||
|
|
@ -41,7 +52,7 @@ static SDRMFormat guessFormatFrom(std::vector<SDRMFormat> formats, bool cursor)
|
|||
return f;
|
||||
}
|
||||
|
||||
for (auto& f : formats) {
|
||||
for (auto const& f : formats) {
|
||||
auto name = fourccToName(f.drmFormat);
|
||||
|
||||
/* 8 bpp RGB */
|
||||
|
|
@ -65,14 +76,18 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
|
|||
const bool MULTIGPU = params.multigpu && params.scanout;
|
||||
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE,
|
||||
std::format("GBM: Allocating a buffer: size {}, format {}, cursor: {}, multigpu: {}", attrs.size, fourccToName(attrs.format), CURSOR, MULTIGPU)));
|
||||
std::format("GBM: Allocating a buffer: size {}, format {}, cursor: {}, multigpu: {}, scanout: {}", attrs.size, fourccToName(attrs.format), CURSOR,
|
||||
MULTIGPU, params.scanout)));
|
||||
|
||||
const auto FORMATS = CURSOR ? swapchain->backendImpl->getCursorFormats() : swapchain->backendImpl->getRenderFormats();
|
||||
const auto FORMATS = CURSOR ? swapchain->backendImpl->getCursorFormats() : swapchain->backendImpl->getRenderFormats();
|
||||
const auto RENDERABLE = swapchain->backendImpl->getRenderableFormats();
|
||||
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Available formats: {}", FORMATS.size())));
|
||||
|
||||
std::vector<uint64_t> explicitModifiers;
|
||||
|
||||
if (attrs.format == DRM_FORMAT_INVALID) {
|
||||
attrs.format = guessFormatFrom(FORMATS, CURSOR).drmFormat;
|
||||
attrs.format = guessFormatFrom(FORMATS, CURSOR, params.scanout).drmFormat;
|
||||
if (attrs.format != DRM_FORMAT_INVALID)
|
||||
allocator->backend->log(AQ_LOG_DEBUG, std::format("GBM: Automatically selected format {} for new GBM buffer", fourccToName(attrs.format)));
|
||||
}
|
||||
|
|
@ -84,15 +99,34 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
|
|||
|
||||
// check if we can use modifiers. If the requested support has any explicit modifier
|
||||
// supported by the primary backend, we can.
|
||||
for (auto& f : FORMATS) {
|
||||
if (f.drmFormat != attrs.format)
|
||||
continue;
|
||||
if (!RENDERABLE.empty()) {
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Renderable has {} formats, clipping", RENDERABLE.size())));
|
||||
|
||||
for (auto& m : f.modifiers) {
|
||||
if (m == DRM_FORMAT_MOD_INVALID)
|
||||
for (auto const& f : FORMATS) {
|
||||
if (f.drmFormat != attrs.format)
|
||||
continue;
|
||||
|
||||
explicitModifiers.push_back(m);
|
||||
for (auto const& m : f.modifiers) {
|
||||
if (m == DRM_FORMAT_MOD_INVALID)
|
||||
continue;
|
||||
|
||||
if (params.scanout && !CURSOR && !MULTIGPU) {
|
||||
// regular scanout plane, check if the format is renderable
|
||||
auto rformat = std::find_if(RENDERABLE.begin(), RENDERABLE.end(), [f](const auto& e) { return e.drmFormat == f.drmFormat; });
|
||||
|
||||
if (rformat == RENDERABLE.end()) {
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Dropping format {} as it's not renderable", fourccToName(f.drmFormat))));
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::find(rformat->modifiers.begin(), rformat->modifiers.end(), m) == rformat->modifiers.end()) {
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Dropping modifier 0x{:x} as it's not renderable", m)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
explicitModifiers.push_back(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,13 +150,23 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
|
|||
bo = gbm_bo_create(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, flags);
|
||||
} else {
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: Using modifier-based allocation, modifiers: {}", explicitModifiers.size())));
|
||||
for (auto& mod : explicitModifiers) {
|
||||
for (auto const& mod : explicitModifiers) {
|
||||
TRACE(allocator->backend->log(AQ_LOG_TRACE, std::format("GBM: | mod 0x{:x}", mod)));
|
||||
}
|
||||
bo = gbm_bo_create_with_modifiers(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size());
|
||||
bo = gbm_bo_create_with_modifiers2(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size(), flags);
|
||||
|
||||
if (!bo && CURSOR) {
|
||||
// allow non-renderable cursor buffer for nvidia
|
||||
allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers and flags failed, falling back to modifiers without flags");
|
||||
bo = gbm_bo_create_with_modifiers(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, explicitModifiers.data(), explicitModifiers.size());
|
||||
}
|
||||
|
||||
if (!bo) {
|
||||
allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers failed, falling back to implicit");
|
||||
if (explicitModifiers.size() == 1 && explicitModifiers[0] == DRM_FORMAT_MOD_LINEAR) {
|
||||
flags |= GBM_BO_USE_LINEAR;
|
||||
allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers failed, falling back to modifier-less allocation");
|
||||
} else
|
||||
allocator->backend->log(AQ_LOG_ERROR, "GBM: Allocating with modifiers failed, falling back to implicit");
|
||||
bo = gbm_bo_create(allocator->gbmDevice, attrs.size.x, attrs.size.y, attrs.format, flags);
|
||||
}
|
||||
}
|
||||
|
|
@ -133,7 +177,7 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
|
|||
}
|
||||
|
||||
attrs.planes = gbm_bo_get_plane_count(bo);
|
||||
attrs.modifier = gbm_bo_get_modifier(bo);
|
||||
attrs.modifier = (flags & GBM_BO_USE_LINEAR) ? DRM_FORMAT_MOD_LINEAR : gbm_bo_get_modifier(bo);
|
||||
|
||||
for (size_t i = 0; i < (size_t)attrs.planes; ++i) {
|
||||
attrs.strides.at(i) = gbm_bo_get_stride_for_plane(bo, i);
|
||||
|
|
@ -159,6 +203,13 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
|
|||
modName ? modName : "Unknown"));
|
||||
|
||||
free(modName);
|
||||
|
||||
if (params.scanout && swapchain->backendImpl->type() == AQ_BACKEND_DRM) {
|
||||
// clear the buffer using the DRM renderer to avoid uninitialized mem
|
||||
auto impl = (CDRMBackend*)swapchain->backendImpl.get();
|
||||
if (impl->rendererState.renderer)
|
||||
impl->rendererState.renderer->clearBuffer(this);
|
||||
}
|
||||
}
|
||||
|
||||
Aquamarine::CGBMBuffer::~CGBMBuffer() {
|
||||
|
|
@ -189,7 +240,7 @@ bool Aquamarine::CGBMBuffer::isSynchronous() {
|
|||
}
|
||||
|
||||
bool Aquamarine::CGBMBuffer::good() {
|
||||
return true;
|
||||
return bo;
|
||||
}
|
||||
|
||||
SDMABUFAttrs Aquamarine::CGBMBuffer::dmabuf() {
|
||||
|
|
@ -197,13 +248,13 @@ SDMABUFAttrs Aquamarine::CGBMBuffer::dmabuf() {
|
|||
}
|
||||
|
||||
std::tuple<uint8_t*, uint32_t, size_t> Aquamarine::CGBMBuffer::beginDataPtr(uint32_t flags) {
|
||||
uint32_t dst_stride = 0;
|
||||
uint32_t stride = 0;
|
||||
if (boBuffer)
|
||||
allocator->backend->log(AQ_LOG_ERROR, "beginDataPtr is called a second time without calling endDataPtr first. Returning old mapping");
|
||||
else
|
||||
boBuffer = gbm_bo_map(bo, 0, 0, attrs.size.x, attrs.size.y, flags, &dst_stride, &gboMapping);
|
||||
// FIXME: assumes a 32-bit pixel format
|
||||
return {(uint8_t*)boBuffer, attrs.format, attrs.size.x * attrs.size.y * 4};
|
||||
boBuffer = gbm_bo_map(bo, 0, 0, attrs.size.x, attrs.size.y, flags, &stride, &gboMapping);
|
||||
|
||||
return {(uint8_t*)boBuffer, attrs.format, stride * attrs.size.y};
|
||||
}
|
||||
|
||||
void Aquamarine::CGBMBuffer::endDataPtr() {
|
||||
|
|
@ -278,3 +329,7 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CGBMAllocator::getBacken
|
|||
int Aquamarine::CGBMAllocator::drmFD() {
|
||||
return fd;
|
||||
}
|
||||
|
||||
eAllocatorType Aquamarine::CGBMAllocator::type() {
|
||||
return AQ_ALLOCATOR_TYPE_GBM;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ using namespace Hyprutils::Memory;
|
|||
using namespace Aquamarine;
|
||||
#define SP CSharedPointer
|
||||
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000LL
|
||||
|
||||
static void timespecAddNs(timespec* pTimespec, int64_t delta) {
|
||||
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
|
||||
|
|
@ -67,7 +67,7 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
|
|||
|
||||
backend->log(AQ_LOG_DEBUG, "Creating an Aquamarine backend!");
|
||||
|
||||
for (auto& b : backends) {
|
||||
for (auto const& b : backends) {
|
||||
if (b.backendType == AQ_BACKEND_WAYLAND) {
|
||||
auto ref = SP<CWaylandBackend>(new CWaylandBackend(backend));
|
||||
backend->implementations.emplace_back(ref);
|
||||
|
|
@ -79,7 +79,7 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
|
|||
continue;
|
||||
}
|
||||
|
||||
for (auto& r : ref) {
|
||||
for (auto const& r : ref) {
|
||||
backend->implementations.emplace_back(r);
|
||||
}
|
||||
} else if (b.backendType == AQ_BACKEND_HEADLESS) {
|
||||
|
|
@ -109,7 +109,7 @@ bool Aquamarine::CBackend::start() {
|
|||
int started = 0;
|
||||
|
||||
auto optionsForType = [this](eBackendType type) -> SBackendImplementationOptions {
|
||||
for (auto& o : implementationOptions) {
|
||||
for (auto const& o : implementationOptions) {
|
||||
if (o.backendType == type)
|
||||
return o;
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ bool Aquamarine::CBackend::start() {
|
|||
});
|
||||
|
||||
// TODO: obviously change this when (if) we add different allocators.
|
||||
for (auto& b : implementations) {
|
||||
for (auto const& b : implementations) {
|
||||
if (b->drmFD() >= 0) {
|
||||
auto fd = reopenDRMNode(b->drmFD());
|
||||
if (fd < 0) {
|
||||
|
|
@ -162,7 +162,7 @@ bool Aquamarine::CBackend::start() {
|
|||
return false;
|
||||
|
||||
ready = true;
|
||||
for (auto& b : implementations) {
|
||||
for (auto const& b : implementations) {
|
||||
b->onReady();
|
||||
}
|
||||
|
||||
|
|
@ -180,15 +180,15 @@ void Aquamarine::CBackend::log(eBackendLogLevel level, const std::string& msg) {
|
|||
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::getPollFDs() {
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> result;
|
||||
for (auto& i : implementations) {
|
||||
for (auto const& i : implementations) {
|
||||
auto pollfds = i->pollFDs();
|
||||
for (auto& p : pollfds) {
|
||||
for (auto const& p : pollfds) {
|
||||
log(AQ_LOG_DEBUG, std::format("backend: poll fd {} for implementation {}", p->fd, backendTypeToName(i->type())));
|
||||
result.emplace_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& sfd : sessionFDs) {
|
||||
for (auto const& sfd : sessionFDs) {
|
||||
log(AQ_LOG_DEBUG, std::format("backend: poll fd {} for session", sfd->fd));
|
||||
result.emplace_back(sfd);
|
||||
}
|
||||
|
|
@ -200,7 +200,7 @@ std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::ge
|
|||
}
|
||||
|
||||
int Aquamarine::CBackend::drmFD() {
|
||||
for (auto& i : implementations) {
|
||||
for (auto const& i : implementations) {
|
||||
int fd = i->drmFD();
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
|
@ -215,14 +215,14 @@ bool Aquamarine::CBackend::hasSession() {
|
|||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::CBackend::getPrimaryRenderFormats() {
|
||||
for (auto& b : implementations) {
|
||||
for (auto const& b : implementations) {
|
||||
if (b->type() != AQ_BACKEND_DRM && b->type() != AQ_BACKEND_WAYLAND)
|
||||
continue;
|
||||
|
||||
return b->getRenderFormats();
|
||||
}
|
||||
|
||||
for (auto& b : implementations) {
|
||||
for (auto const& b : implementations) {
|
||||
return b->getRenderFormats();
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ void Aquamarine::CBackend::dispatchIdle() {
|
|||
auto cpy = idle.pending;
|
||||
idle.pending.clear();
|
||||
|
||||
for (auto& i : cpy) {
|
||||
for (auto const& i : cpy) {
|
||||
if (i && *i)
|
||||
(*i)();
|
||||
}
|
||||
|
|
@ -328,3 +328,7 @@ int Aquamarine::CBackend::reopenDRMNode(int drmFD, bool allowRenderNode) {
|
|||
|
||||
return newFD;
|
||||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::IBackendImplementation::getRenderableFormats() {
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using namespace Hyprutils::Memory;
|
|||
using namespace Hyprutils::Math;
|
||||
#define SP CSharedPointer
|
||||
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000LL
|
||||
|
||||
static void timespecAddNs(timespec* pTimespec, int64_t delta) {
|
||||
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
|
||||
|
|
@ -73,6 +73,7 @@ void Aquamarine::CHeadlessOutput::scheduleFrame(const scheduleFrameReason reason
|
|||
}
|
||||
|
||||
bool Aquamarine::CHeadlessOutput::destroy() {
|
||||
events.destroy.emit();
|
||||
std::erase(backend->outputs, self.lock());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -148,7 +149,7 @@ void Aquamarine::CHeadlessBackend::dispatchTimers() {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto& copy : toFire) {
|
||||
for (auto const& copy : toFire) {
|
||||
if (copy.what)
|
||||
copy.what();
|
||||
}
|
||||
|
|
@ -161,7 +162,7 @@ void Aquamarine::CHeadlessBackend::updateTimerFD() {
|
|||
const auto clocknow = std::chrono::steady_clock::now();
|
||||
bool any = false;
|
||||
|
||||
for (auto& t : timers.timers) {
|
||||
for (auto const& t : timers.timers) {
|
||||
auto delta = std::chrono::duration_cast<std::chrono::microseconds>(t.when - clocknow).count() * 1000 /* µs -> ns */;
|
||||
|
||||
if (delta < lowestNs)
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ static bool isDRMCard(const char* sysname) {
|
|||
}
|
||||
|
||||
void Aquamarine::CSession::onReady() {
|
||||
for (auto& d : libinputDevices) {
|
||||
for (auto const& d : libinputDevices) {
|
||||
if (d->keyboard)
|
||||
backend->events.newKeyboard.emit(SP<IKeyboard>(d->keyboard));
|
||||
if (d->mouse)
|
||||
|
|
@ -278,7 +278,7 @@ void Aquamarine::CSession::onReady() {
|
|||
if (d->tabletPad)
|
||||
backend->events.newTabletPad.emit(SP<ITabletPad>(d->tabletPad));
|
||||
|
||||
for (auto& t : d->tabletTools) {
|
||||
for (auto const& t : d->tabletTools) {
|
||||
backend->events.newTabletTool.emit(SP<ITabletTool>(t));
|
||||
}
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ void Aquamarine::CSession::dispatchUdevEvents() {
|
|||
|
||||
dev_t deviceNum = udev_device_get_devnum(device);
|
||||
SP<CSessionDevice> sessionDevice;
|
||||
for (auto& sDev : sessionDevices) {
|
||||
for (auto const& sDev : sessionDevices) {
|
||||
if (sDev->dev == deviceNum) {
|
||||
sessionDevice = sDev;
|
||||
break;
|
||||
|
|
@ -498,7 +498,7 @@ void Aquamarine::CSession::handleLibinputEvent(libinput_event* e) {
|
|||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
|
||||
};
|
||||
|
||||
for (auto& axis : LAXES) {
|
||||
for (auto const& axis : LAXES) {
|
||||
if (!libinput_event_pointer_has_axis(pe, axis))
|
||||
continue;
|
||||
|
||||
|
|
@ -596,6 +596,7 @@ void Aquamarine::CSession::handleLibinputEvent(libinput_event* e) {
|
|||
hlDevice->touch->events.down.emit(ITouch::SDownEvent{
|
||||
.timeMs = (uint32_t)(libinput_event_touch_get_time_usec(te) / 1000),
|
||||
.touchID = libinput_event_touch_get_seat_slot(te),
|
||||
.pos = {libinput_event_touch_get_x_transformed(te, 1), libinput_event_touch_get_y_transformed(te, 1)},
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
@ -639,6 +640,7 @@ void Aquamarine::CSession::handleLibinputEvent(libinput_event* e) {
|
|||
|
||||
if (ENABLED == hlDevice->switchy->state)
|
||||
return;
|
||||
hlDevice->switchy->state = ENABLED;
|
||||
|
||||
switch (libinput_event_switch_get_switch(se)) {
|
||||
case LIBINPUT_SWITCH_LID: hlDevice->switchy->type = ISwitch::AQ_SWITCH_TYPE_LID; break;
|
||||
|
|
@ -858,7 +860,7 @@ Aquamarine::CLibinputDevice::~CLibinputDevice() {
|
|||
}
|
||||
|
||||
SP<CLibinputTabletTool> Aquamarine::CLibinputDevice::toolFrom(libinput_tablet_tool* tool) {
|
||||
for (auto& t : tabletTools) {
|
||||
for (auto const& t : tabletTools) {
|
||||
if (t->libinputTool == tool)
|
||||
return t;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ bool Aquamarine::CWaylandBackend::start() {
|
|||
TRACE(backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 1, id)));
|
||||
waylandState.shm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_shm_interface, 1));
|
||||
} else if (NAME == "zwp_linux_dmabuf_v1") {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 5, id)));
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 4, id)));
|
||||
waylandState.dmabuf =
|
||||
makeShared<CCZwpLinuxDmabufV1>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &zwp_linux_dmabuf_v1_interface, 5));
|
||||
makeShared<CCZwpLinuxDmabufV1>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &zwp_linux_dmabuf_v1_interface, 4));
|
||||
if (!initDmabuf()) {
|
||||
backend->log(AQ_LOG_ERROR, "Wayland backend cannot start: zwp_linux_dmabuf_v1 init failed");
|
||||
waylandState.dmabufFailed = true;
|
||||
|
|
@ -168,7 +168,7 @@ bool Aquamarine::CWaylandBackend::dispatchEvents() {
|
|||
|
||||
// dispatch frames
|
||||
if (backend->ready) {
|
||||
for (auto& f : idleCallbacks) {
|
||||
for (auto const& f : idleCallbacks) {
|
||||
f();
|
||||
}
|
||||
idleCallbacks.clear();
|
||||
|
|
@ -187,7 +187,7 @@ bool Aquamarine::CWaylandBackend::setCursor(Hyprutils::Memory::CSharedPointer<IB
|
|||
}
|
||||
|
||||
void Aquamarine::CWaylandBackend::onReady() {
|
||||
for (auto& o : outputs) {
|
||||
for (auto const& o : outputs) {
|
||||
o->swapchain = CSwapchain::create(backend->primaryAllocator, self.lock());
|
||||
if (!o->swapchain) {
|
||||
backend->log(AQ_LOG_ERROR, std::format("Output {} failed: swapchain creation failed", o->name));
|
||||
|
|
@ -257,7 +257,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CCWlPointer> pointer_, Hyprutils
|
|||
pointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_proxy* surface, wl_fixed_t x, wl_fixed_t y) {
|
||||
backend->lastEnterSerial = serial;
|
||||
|
||||
for (auto& o : backend->outputs) {
|
||||
for (auto const& o : backend->outputs) {
|
||||
if (o->waylandState.surface->resource() != surface)
|
||||
continue;
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CCWlPointer> pointer_, Hyprutils
|
|||
});
|
||||
|
||||
pointer->setLeave([this](CCWlPointer* r, uint32_t serial, wl_proxy* surface) {
|
||||
for (auto& o : backend->outputs) {
|
||||
for (auto const& o : backend->outputs) {
|
||||
if (o->waylandState.surface->resource() != surface)
|
||||
continue;
|
||||
|
||||
|
|
@ -496,6 +496,7 @@ Aquamarine::CWaylandOutput::CWaylandOutput(const std::string& name_, Hyprutils::
|
|||
|
||||
Aquamarine::CWaylandOutput::~CWaylandOutput() {
|
||||
backend->idleCallbacks.clear(); // FIXME: mega hack to avoid a UAF in frame events
|
||||
events.destroy.emit();
|
||||
if (waylandState.xdgToplevel)
|
||||
waylandState.xdgToplevel->sendDestroy();
|
||||
if (waylandState.xdgSurface)
|
||||
|
|
@ -598,7 +599,7 @@ SP<IBackendImplementation> Aquamarine::CWaylandOutput::getBackend() {
|
|||
SP<CWaylandBuffer> Aquamarine::CWaylandOutput::wlBufferFromBuffer(SP<IBuffer> buffer) {
|
||||
std::erase_if(backendState.buffers, [this](const auto& el) { return el.first.expired() || !swapchain->contains(el.first.lock()); });
|
||||
|
||||
for (auto& [k, v] : backendState.buffers) {
|
||||
for (auto const& [k, v] : backendState.buffers) {
|
||||
if (k != buffer)
|
||||
continue;
|
||||
|
||||
|
|
@ -654,7 +655,8 @@ bool Aquamarine::CWaylandOutput::setCursor(Hyprutils::Memory::CSharedPointer<IBu
|
|||
if (!buffer) {
|
||||
cursorState.cursorBuffer.reset();
|
||||
cursorState.cursorWlBuffer.reset();
|
||||
backend->pointers.at(0)->pointer->sendSetCursor(cursorState.serial, nullptr, cursorState.hotspot.x, cursorState.hotspot.y);
|
||||
if (!backend->pointers.empty())
|
||||
backend->pointers.at(0)->pointer->sendSetCursor(cursorState.serial, nullptr, cursorState.hotspot.x, cursorState.hotspot.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -724,7 +726,7 @@ bool Aquamarine::CWaylandOutput::setCursor(Hyprutils::Memory::CSharedPointer<IBu
|
|||
return true;
|
||||
}
|
||||
|
||||
void Aquamarine::CWaylandOutput::moveCursor(const Hyprutils::Math::Vector2D& coord) {
|
||||
void Aquamarine::CWaylandOutput::moveCursor(const Hyprutils::Math::Vector2D& coord, bool skipSchedule) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <thread>
|
||||
#include <deque>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
|
@ -135,9 +137,25 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
|
|||
backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit device list {}", explicitGpus));
|
||||
Hyprutils::String::CVarList explicitDevices(explicitGpus, 0, ':', true);
|
||||
|
||||
// Iterate over GPUs and canonicalize the paths
|
||||
for (auto& d : explicitDevices) {
|
||||
std::error_code ec;
|
||||
|
||||
auto canonicalFilePath = std::filesystem::canonical(d, ec);
|
||||
|
||||
// If there is an error, log and continue.
|
||||
// TODO: Verify that the path is a valid DRM device. (https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/backend/session/session.c?ref_type=heads#L369-387)
|
||||
if (ec) {
|
||||
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to canonicalize path {}", d));
|
||||
continue;
|
||||
}
|
||||
|
||||
d = canonicalFilePath.string();
|
||||
}
|
||||
|
||||
for (auto const& d : explicitDevices) {
|
||||
bool found = false;
|
||||
for (auto& vd : devices) {
|
||||
for (auto const& vd : devices) {
|
||||
if (vd->path == d) {
|
||||
vecDevices.emplace_back(vd);
|
||||
found = true;
|
||||
|
|
@ -151,7 +169,7 @@ static std::vector<SP<CSessionDevice>> scanGPUs(SP<CBackend> backend) {
|
|||
backend->log(AQ_LOG_ERROR, std::format("drm: Explicit device {} not found", d));
|
||||
}
|
||||
} else {
|
||||
for (auto& d : devices) {
|
||||
for (auto const& d : devices) {
|
||||
vecDevices.push_back(d);
|
||||
}
|
||||
}
|
||||
|
|
@ -201,7 +219,7 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
|
|||
std::vector<SP<CDRMBackend>> backends;
|
||||
SP<CDRMBackend> newPrimary;
|
||||
|
||||
for (auto& gpu : gpus) {
|
||||
for (auto const& gpu : gpus) {
|
||||
auto drmBackend = SP<CDRMBackend>(new CDRMBackend(backend));
|
||||
drmBackend->self = drmBackend;
|
||||
|
||||
|
|
@ -228,7 +246,7 @@ std::vector<SP<CDRMBackend>> Aquamarine::CDRMBackend::attempt(SP<CBackend> backe
|
|||
|
||||
drmBackend->grabFormats();
|
||||
|
||||
drmBackend->scanConnectors();
|
||||
drmBackend->scanConnectors(false);
|
||||
|
||||
drmBackend->recheckCRTCs();
|
||||
|
||||
|
|
@ -261,7 +279,7 @@ bool Aquamarine::CDRMBackend::sessionActive() {
|
|||
void Aquamarine::CDRMBackend::restoreAfterVT() {
|
||||
backend->log(AQ_LOG_DEBUG, "drm: Restoring after VT switch");
|
||||
|
||||
scanConnectors();
|
||||
scanConnectors(false);
|
||||
recheckCRTCs();
|
||||
|
||||
backend->log(AQ_LOG_DEBUG, "drm: Rescanned connectors");
|
||||
|
|
@ -271,7 +289,7 @@ void Aquamarine::CDRMBackend::restoreAfterVT() {
|
|||
|
||||
std::vector<SP<SDRMConnector>> noMode;
|
||||
|
||||
for (auto& c : connectors) {
|
||||
for (auto const& c : connectors) {
|
||||
if (!c->crtc || !c->output)
|
||||
continue;
|
||||
|
||||
|
|
@ -284,15 +302,16 @@ void Aquamarine::CDRMBackend::restoreAfterVT() {
|
|||
};
|
||||
|
||||
auto& STATE = c->output->state->state();
|
||||
auto& MODE = STATE.customMode ? STATE.customMode : STATE.mode;
|
||||
|
||||
if (!STATE.customMode && !STATE.mode) {
|
||||
if (!MODE) {
|
||||
backend->log(AQ_LOG_WARNING, "drm: Connector {} has output but state has no mode, will send a reset state event later.");
|
||||
noMode.emplace_back(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (STATE.mode && STATE.mode->modeInfo.has_value())
|
||||
data.modeInfo = *STATE.mode->modeInfo;
|
||||
if (MODE->modeInfo.has_value())
|
||||
data.modeInfo = *MODE->modeInfo;
|
||||
else
|
||||
data.calculateMode(c);
|
||||
|
||||
|
|
@ -323,7 +342,7 @@ void Aquamarine::CDRMBackend::restoreAfterVT() {
|
|||
backend->log(AQ_LOG_ERROR, std::format("drm: crtc {} failed restore", c->crtc->id));
|
||||
}
|
||||
|
||||
for (auto& c : noMode) {
|
||||
for (auto const& c : noMode) {
|
||||
if (!c->output)
|
||||
continue;
|
||||
|
||||
|
|
@ -475,29 +494,55 @@ bool Aquamarine::CDRMBackend::shouldBlit() {
|
|||
}
|
||||
|
||||
bool Aquamarine::CDRMBackend::initMgpu() {
|
||||
if (!primary)
|
||||
return true;
|
||||
SP<CGBMAllocator> newAllocator;
|
||||
if (primary || backend->primaryAllocator->type() != AQ_ALLOCATOR_TYPE_GBM) {
|
||||
newAllocator = CGBMAllocator::create(backend->reopenDRMNode(gpu->fd), backend);
|
||||
rendererState.allocator = newAllocator;
|
||||
} else {
|
||||
newAllocator = ((CGBMAllocator*)backend->primaryAllocator.get())->self.lock();
|
||||
rendererState.allocator = newAllocator;
|
||||
}
|
||||
|
||||
auto newAllocator = CGBMAllocator::create(backend->reopenDRMNode(gpu->fd), backend);
|
||||
mgpu.allocator = newAllocator;
|
||||
|
||||
if (!mgpu.allocator) {
|
||||
if (!rendererState.allocator) {
|
||||
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no allocator");
|
||||
return false;
|
||||
}
|
||||
|
||||
mgpu.renderer = CDRMRenderer::attempt(newAllocator, backend.lock());
|
||||
rendererState.renderer = CDRMRenderer::attempt(newAllocator, backend.lock());
|
||||
|
||||
if (!mgpu.renderer) {
|
||||
if (!rendererState.renderer) {
|
||||
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
mgpu.renderer->self = mgpu.renderer;
|
||||
rendererState.renderer->self = rendererState.renderer;
|
||||
|
||||
buildGlFormats(rendererState.renderer->formats);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Aquamarine::CDRMBackend::buildGlFormats(const std::vector<SGLFormat>& fmts) {
|
||||
std::vector<SDRMFormat> result;
|
||||
|
||||
for (auto const& fmt : fmts) {
|
||||
if (fmt.external)
|
||||
continue;
|
||||
|
||||
if (auto it = std::find_if(result.begin(), result.end(), [fmt](const auto& e) { return fmt.drmFormat == e.drmFormat; }); it != result.end()) {
|
||||
it->modifiers.emplace_back(fmt.modifier);
|
||||
continue;
|
||||
}
|
||||
|
||||
result.emplace_back(SDRMFormat{
|
||||
fmt.drmFormat,
|
||||
{fmt.modifier},
|
||||
});
|
||||
}
|
||||
|
||||
glFormats = result;
|
||||
}
|
||||
|
||||
void Aquamarine::CDRMBackend::recheckCRTCs() {
|
||||
if (connectors.empty() || crtcs.empty())
|
||||
return;
|
||||
|
|
@ -505,7 +550,7 @@ void Aquamarine::CDRMBackend::recheckCRTCs() {
|
|||
backend->log(AQ_LOG_DEBUG, "drm: Rechecking CRTCs");
|
||||
|
||||
std::vector<SP<SDRMConnector>> recheck, changed;
|
||||
for (auto& c : connectors) {
|
||||
for (auto const& c : connectors) {
|
||||
if (c->crtc && c->status == DRM_MODE_CONNECTED) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Skipping connector {}, has crtc {} and is connected", c->szName, c->crtc->id));
|
||||
continue;
|
||||
|
|
@ -517,7 +562,7 @@ void Aquamarine::CDRMBackend::recheckCRTCs() {
|
|||
|
||||
for (size_t i = 0; i < crtcs.size(); ++i) {
|
||||
bool taken = false;
|
||||
for (auto& c : connectors) {
|
||||
for (auto const& c : connectors) {
|
||||
if (c->crtc != crtcs.at(i))
|
||||
continue;
|
||||
|
||||
|
|
@ -535,7 +580,7 @@ void Aquamarine::CDRMBackend::recheckCRTCs() {
|
|||
bool assigned = false;
|
||||
|
||||
// try to use a connected connector
|
||||
for (auto& c : recheck) {
|
||||
for (auto const& c : recheck) {
|
||||
if (!(c->possibleCrtcs & (1 << i)))
|
||||
continue;
|
||||
|
||||
|
|
@ -561,7 +606,7 @@ void Aquamarine::CDRMBackend::recheckCRTCs() {
|
|||
backend->log(AQ_LOG_DEBUG, std::format("drm: slot {} crtc {} unassigned", i, crtcs.at(i)->id));
|
||||
}
|
||||
|
||||
for (auto& c : connectors) {
|
||||
for (auto const& c : connectors) {
|
||||
if (c->status == DRM_MODE_CONNECTED)
|
||||
continue;
|
||||
|
||||
|
|
@ -570,7 +615,7 @@ void Aquamarine::CDRMBackend::recheckCRTCs() {
|
|||
|
||||
// if any connectors get a crtc and are connected, we need to rescan to assign them outputs.
|
||||
bool rescan = false;
|
||||
for (auto& c : changed) {
|
||||
for (auto const& c : changed) {
|
||||
if (!c->output && c->status == DRM_MODE_CONNECTED) {
|
||||
rescan = true;
|
||||
continue;
|
||||
|
|
@ -599,8 +644,12 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
|
|||
|
||||
gpuName = drmName;
|
||||
|
||||
auto drmVerName = drmVer->name ? drmVer->name : "unknown";
|
||||
if (std::string_view(drmVerName) == "evdi")
|
||||
primary = {};
|
||||
|
||||
backend->log(AQ_LOG_DEBUG,
|
||||
std::format("drm: Starting backend for {}, with driver {}{}", drmName ? drmName : "unknown", drmVer->name ? drmVer->name : "unknown",
|
||||
std::format("drm: Starting backend for {}, with driver {}{}", drmName ? drmName : "unknown", drmVerName,
|
||||
(primary ? std::format(" with primary {}", primary->gpu->path) : "")));
|
||||
|
||||
drmFreeVersion(drmVer);
|
||||
|
|
@ -609,7 +658,7 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
|
|||
auto E = std::any_cast<CSessionDevice::SChangeEvent>(d);
|
||||
if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Got a hotplug event for {}", gpuName));
|
||||
scanConnectors();
|
||||
scanConnectors(false);
|
||||
recheckCRTCs();
|
||||
} else if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_LEASE) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Got a lease event for {}", gpuName));
|
||||
|
|
@ -627,7 +676,7 @@ eBackendType Aquamarine::CDRMBackend::type() {
|
|||
return eBackendType::AQ_BACKEND_DRM;
|
||||
}
|
||||
|
||||
void Aquamarine::CDRMBackend::scanConnectors() {
|
||||
void Aquamarine::CDRMBackend::scanConnectors(bool allowConnect) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Scanning connectors for {}", gpu->path));
|
||||
|
||||
auto resources = drmModeGetResources(gpu->fd);
|
||||
|
|
@ -668,19 +717,19 @@ void Aquamarine::CDRMBackend::scanConnectors() {
|
|||
|
||||
conn->status = drmConn->connection;
|
||||
|
||||
if (!conn->crtc) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Ignoring connector {} because it has no CRTC", connectorID));
|
||||
continue;
|
||||
}
|
||||
if (conn->crtc)
|
||||
conn->recheckCRTCProps();
|
||||
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connection state: {}", connectorID, (int)drmConn->connection));
|
||||
|
||||
if (conn->status == DRM_MODE_CONNECTED && !conn->output) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connected", conn->szName));
|
||||
conn->connect(drmConn);
|
||||
} else if (conn->status != DRM_MODE_CONNECTED && conn->output) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} disconnected", conn->szName));
|
||||
conn->disconnect();
|
||||
if (allowConnect) {
|
||||
if (conn->status == DRM_MODE_CONNECTED && !conn->output) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} connected", conn->szName));
|
||||
conn->connect(drmConn);
|
||||
} else if (conn->status != DRM_MODE_CONNECTED && conn->output) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} disconnected", conn->szName));
|
||||
conn->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
drmModeFreeConnector(drmConn);
|
||||
|
|
@ -696,7 +745,7 @@ void Aquamarine::CDRMBackend::scanLeases() {
|
|||
return;
|
||||
}
|
||||
|
||||
for (auto& c : connectors) {
|
||||
for (auto const& c : connectors) {
|
||||
if (!c->output || !c->output->lease)
|
||||
continue;
|
||||
|
||||
|
|
@ -718,7 +767,7 @@ void Aquamarine::CDRMBackend::scanLeases() {
|
|||
|
||||
auto l = c->output->lease;
|
||||
|
||||
for (auto& c2 : connectors) {
|
||||
for (auto const& c2 : connectors) {
|
||||
if (!c2->output || c2->output->lease != c->output->lease)
|
||||
continue;
|
||||
|
||||
|
|
@ -775,7 +824,7 @@ static void handlePF(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, un
|
|||
.flags = flags,
|
||||
});
|
||||
|
||||
if (BACKEND->sessionActive() && !pageFlip->connector->frameEventScheduled)
|
||||
if (BACKEND->sessionActive() && !pageFlip->connector->frameEventScheduled && pageFlip->connector->output->enabledState)
|
||||
pageFlip->connector->output->events.frame.emit();
|
||||
}
|
||||
|
||||
|
|
@ -792,6 +841,8 @@ bool Aquamarine::CDRMBackend::dispatchEvents() {
|
|||
}
|
||||
|
||||
uint32_t Aquamarine::CDRMBackend::capabilities() {
|
||||
if (getCursorFormats().empty())
|
||||
return 0;
|
||||
return eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER;
|
||||
}
|
||||
|
||||
|
|
@ -802,7 +853,26 @@ bool Aquamarine::CDRMBackend::setCursor(SP<IBuffer> buffer, const Hyprutils::Mat
|
|||
void Aquamarine::CDRMBackend::onReady() {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: Connectors size2 {}", connectors.size()));
|
||||
|
||||
for (auto& c : connectors) {
|
||||
// init a drm renderer to gather gl formats.
|
||||
// if we are secondary, initMgpu will have done that
|
||||
if (!primary) {
|
||||
auto a = CGBMAllocator::create(backend->reopenDRMNode(gpu->fd), backend);
|
||||
if (!a)
|
||||
backend->log(AQ_LOG_ERROR, "drm: onReady: no renderer for gl formats");
|
||||
else {
|
||||
auto r = CDRMRenderer::attempt(a, backend.lock());
|
||||
if (!r)
|
||||
backend->log(AQ_LOG_ERROR, "drm: onReady: no renderer for gl formats");
|
||||
else {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("drm: onReady: gathered {} gl formats", r->formats.size())));
|
||||
buildGlFormats(r->formats);
|
||||
r.reset();
|
||||
a.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& c : connectors) {
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm: onReady: connector {}", c->id));
|
||||
if (!c->output)
|
||||
continue;
|
||||
|
|
@ -824,7 +894,7 @@ void Aquamarine::CDRMBackend::onReady() {
|
|||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
|
||||
for (auto& p : planes) {
|
||||
for (auto const& p : planes) {
|
||||
if (p->type != DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
|
|
@ -834,8 +904,12 @@ std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderFormats() {
|
|||
return {};
|
||||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::CDRMBackend::getRenderableFormats() {
|
||||
return glFormats;
|
||||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::CDRMBackend::getCursorFormats() {
|
||||
for (auto& p : planes) {
|
||||
for (auto const& p : planes) {
|
||||
if (p->type != DRM_PLANE_TYPE_CURSOR)
|
||||
continue;
|
||||
|
||||
|
|
@ -1089,13 +1163,30 @@ void Aquamarine::SDRMConnector::parseEDID(std::vector<uint8_t> data) {
|
|||
di_info_destroy(info);
|
||||
}
|
||||
|
||||
void Aquamarine::SDRMConnector::recheckCRTCProps() {
|
||||
if (!crtc || !output)
|
||||
return;
|
||||
|
||||
uint64_t prop = 0;
|
||||
canDoVrr = props.vrr_capable && crtc->props.vrr_enabled && getDRMProp(backend->gpu->fd, id, props.vrr_capable, &prop) && prop;
|
||||
output->vrrCapable = canDoVrr;
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG,
|
||||
std::format("drm: connector {} crtc is {} of vrr: props.vrr_capable -> {}, crtc->props.vrr_enabled -> {}", szName, (canDoVrr ? "capable" : "incapable"),
|
||||
props.vrr_capable, crtc->props.vrr_enabled));
|
||||
|
||||
output->supportsExplicit = backend->drmProps.supportsTimelines && crtc->props.out_fence_ptr && crtc->primary->props.in_fence_fd;
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit sync {}", output->supportsExplicit ? "supported" : "unsupported"));
|
||||
}
|
||||
|
||||
void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
|
||||
if (output) {
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Not connecting connector {} because it's already connected", szName));
|
||||
return;
|
||||
}
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Connecting connector {}, CRTC ID {}", szName, crtc ? crtc->id : -1));
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Connecting connector {}, {}", szName, crtc ? std::format("CRTC ID {}", crtc->id) : "no CRTC"));
|
||||
|
||||
output = SP<CDRMOutput>(new CDRMOutput(szName, backend, self.lock()));
|
||||
output->self = output;
|
||||
|
|
@ -1129,8 +1220,6 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
|
|||
|
||||
//uint64_t modeID = 0;
|
||||
// getDRMProp(backend->gpu->fd, crtc->id, crtc->props.mode_id, &modeID);
|
||||
|
||||
crtc->refresh = calculateRefresh(drmMode);
|
||||
}
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG,
|
||||
|
|
@ -1138,10 +1227,8 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
|
|||
aqMode->preferred ? " (preferred)" : ""));
|
||||
}
|
||||
|
||||
if (!currentModeInfo && fallbackMode) {
|
||||
if (!currentModeInfo && fallbackMode)
|
||||
output->state->setMode(fallbackMode);
|
||||
crtc->refresh = calculateRefresh(fallbackMode->modeInfo.value());
|
||||
}
|
||||
|
||||
output->physicalSize = {(double)connector->mmWidth, (double)connector->mmHeight};
|
||||
|
||||
|
|
@ -1164,13 +1251,6 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
|
|||
output->nonDesktop = prop;
|
||||
}
|
||||
|
||||
canDoVrr = props.vrr_capable && crtc->props.vrr_enabled && getDRMProp(backend->gpu->fd, id, props.vrr_capable, &prop) && prop;
|
||||
output->vrrCapable = canDoVrr;
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG,
|
||||
std::format("drm: crtc is {} of vrr: props.vrr_capable -> {}, crtc->props.vrr_enabled -> {}", (canDoVrr ? "capable" : "incapable"), props.vrr_capable,
|
||||
crtc->props.vrr_enabled));
|
||||
|
||||
maxBpcBounds.fill(0);
|
||||
|
||||
if (props.max_bpc && !introspectDRMPropRange(backend->gpu->fd, props.max_bpc, maxBpcBounds.data(), &maxBpcBounds[1]))
|
||||
|
|
@ -1187,23 +1267,24 @@ void Aquamarine::SDRMConnector::connect(drmModeConnector* connector) {
|
|||
|
||||
// TODO: subconnectors
|
||||
|
||||
output->make = make;
|
||||
output->model = model;
|
||||
output->serial = serial;
|
||||
output->description = std::format("{} {} {} ({})", make, model, serial, szName);
|
||||
output->needsFrame = true;
|
||||
output->supportsExplicit = backend->drmProps.supportsTimelines && crtc->props.out_fence_ptr && crtc->primary->props.in_fence_fd;
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Explicit sync {}", output->supportsExplicit ? "supported" : "unsupported"));
|
||||
output->make = make;
|
||||
output->model = model;
|
||||
output->serial = serial;
|
||||
output->description = std::format("{} {} {} ({})", make, model, serial, szName);
|
||||
output->needsFrame = true;
|
||||
|
||||
backend->backend->log(AQ_LOG_DEBUG, std::format("drm: Description {}", output->description));
|
||||
|
||||
status = DRM_MODE_CONNECTED;
|
||||
|
||||
recheckCRTCProps();
|
||||
|
||||
if (!backend->backend->ready)
|
||||
return;
|
||||
|
||||
output->swapchain = CSwapchain::create(backend->backend->primaryAllocator, backend->self.lock());
|
||||
output->swapchain->reconfigure(SSwapchainOptions{.length = 0, .scanout = true, .multigpu = !!backend->primary}); // mark the swapchain for scanout
|
||||
output->needsFrame = true;
|
||||
backend->backend->events.newOutput.emit(SP<IOutput>(output));
|
||||
output->scheduleFrame(IOutput::AQ_SCHEDULE_NEW_CONNECTOR);
|
||||
}
|
||||
|
|
@ -1245,10 +1326,16 @@ void Aquamarine::SDRMConnector::applyCommit(const SDRMConnectorCommitData& data)
|
|||
|
||||
if (output->state->state().committed & COutputState::AQ_OUTPUT_STATE_MODE)
|
||||
refresh = calculateRefresh(data.modeInfo);
|
||||
|
||||
output->enabledState = output->state->state().enabled;
|
||||
}
|
||||
|
||||
void Aquamarine::SDRMConnector::rollbackCommit(const SDRMConnectorCommitData& data) {
|
||||
// cursors are applied regardless.
|
||||
// cursors are applied regardless,
|
||||
// unless this was a test
|
||||
if (data.test)
|
||||
return;
|
||||
|
||||
if (crtc->cursor && data.cursorFB)
|
||||
crtc->cursor->back = data.cursorFB;
|
||||
|
||||
|
|
@ -1289,7 +1376,6 @@ bool Aquamarine::CDRMOutput::test() {
|
|||
|
||||
void Aquamarine::CDRMOutput::setCursorVisible(bool visible) {
|
||||
cursorVisible = visible;
|
||||
needsFrame = true;
|
||||
scheduleFrame(AQ_SCHEDULE_CURSOR_VISIBLE);
|
||||
}
|
||||
|
||||
|
|
@ -1308,12 +1394,33 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
const uint32_t COMMITTED = STATE.committed;
|
||||
|
||||
if ((COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_ENABLED) && STATE.enabled) {
|
||||
if (!STATE.mode && STATE.customMode) {
|
||||
if (!STATE.mode && !STATE.customMode) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: No mode on enable commit");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (STATE.drmFormat == DRM_FORMAT_INVALID) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: No format for output");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_FORMAT) {
|
||||
// verify the format is valid for the primary plane
|
||||
bool ok = false;
|
||||
for (auto const& f : getRenderFormats()) {
|
||||
if (f.drmFormat == STATE.drmFormat) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: Selected format is not supported by the primary KMS plane");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (STATE.adaptiveSync && !connector->canDoVrr) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: No Adaptive sync support for output");
|
||||
return false;
|
||||
|
|
@ -1347,7 +1454,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
if (!MODE) // modeless commits are invalid
|
||||
return false;
|
||||
|
||||
uint32_t flags = 0;
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (!onlyTest) {
|
||||
if (NEEDS_RECONFIG) {
|
||||
|
|
@ -1385,7 +1492,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
|
||||
if (!mgpu.swapchain) {
|
||||
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: No swapchain for blit, creating"));
|
||||
mgpu.swapchain = CSwapchain::create(backend->mgpu.allocator, backend.lock());
|
||||
mgpu.swapchain = CSwapchain::create(backend->rendererState.allocator, backend.lock());
|
||||
}
|
||||
|
||||
auto OPTIONS = swapchain->currentOptions();
|
||||
|
|
@ -1401,12 +1508,22 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto NEWAQBUF = mgpu.swapchain->next(nullptr);
|
||||
if (!backend->mgpu.renderer->blit(STATE.buffer, NEWAQBUF)) {
|
||||
auto NEWAQBUF = mgpu.swapchain->next(nullptr);
|
||||
auto blitResult = backend->rendererState.renderer->blit(
|
||||
STATE.buffer, NEWAQBUF, (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE) ? STATE.explicitInFence : -1);
|
||||
if (!blitResult.success) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but blit failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// replace the explicit in fence if the blitting backend returned one, otherwise discard old. Passed fence from the client is wrong.
|
||||
// if the commit doesn't have an explicit fence, don't use the one we created, just fallback to implicit
|
||||
static auto NO_EXPLICIT = envEnabled("AQ_MGPU_NO_EXPLICIT");
|
||||
if (blitResult.syncFD.has_value() && !NO_EXPLICIT && (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE))
|
||||
state->setExplicitInFence(blitResult.syncFD.value());
|
||||
else
|
||||
state->setExplicitInFence(-1);
|
||||
|
||||
drmFB = CDRMFB::create(NEWAQBUF, backend, nullptr); // will return attachment if present
|
||||
} else
|
||||
drmFB = CDRMFB::create(STATE.buffer, backend, nullptr); // will return attachment if present
|
||||
|
|
@ -1434,6 +1551,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
fourccToName(STATE.drmFormat), fourccToName(params.format)));
|
||||
state->setFormat(params.format);
|
||||
formatMismatch = true;
|
||||
// TODO: reject if tearing? We will miss a frame event!
|
||||
flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; // we cannot modeset with async pf
|
||||
}
|
||||
}
|
||||
|
|
@ -1470,7 +1588,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
// to avoid doing this over and over.
|
||||
data.modeset = true;
|
||||
data.blocking = true;
|
||||
data.flags = DRM_MODE_PAGE_FLIP_EVENT;
|
||||
data.flags = onlyTest ? 0 : DRM_MODE_PAGE_FLIP_EVENT;
|
||||
ok = connector->commitState(data);
|
||||
|
||||
if (!ok)
|
||||
|
|
@ -1489,6 +1607,28 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
|
|||
if (ok)
|
||||
connector->commitTainted = false;
|
||||
|
||||
if (data.flags & DRM_MODE_PAGE_FLIP_ASYNC) {
|
||||
// for tearing commits, we will send presentation feedback instantly, and rotate
|
||||
// drm framebuffers to properly send backendRelease events.
|
||||
// the last FB should already be gone from KMS because it's been immediately replaced
|
||||
|
||||
// no completion and no vsync, because tearing
|
||||
uint32_t flags = IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK | IOutput::AQ_OUTPUT_PRESENT_ZEROCOPY;
|
||||
|
||||
timespec presented;
|
||||
clock_gettime(CLOCK_MONOTONIC, &presented);
|
||||
|
||||
connector->output->events.present.emit(IOutput::SPresentEvent{
|
||||
.presented = backend->sessionActive(),
|
||||
.when = &presented,
|
||||
.seq = 0, /* unknown sequence for tearing */
|
||||
.refresh = (int)(connector->refresh ? (1000000000000LL / connector->refresh) : 0),
|
||||
.flags = flags,
|
||||
});
|
||||
|
||||
connector->onPresent();
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
@ -1502,6 +1642,9 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!connector->crtc)
|
||||
return false;
|
||||
|
||||
if (!buffer)
|
||||
setCursorVisible(false);
|
||||
else {
|
||||
|
|
@ -1512,7 +1655,7 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
|
|||
|
||||
if (!mgpu.cursorSwapchain) {
|
||||
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: No cursorSwapchain for blit, creating"));
|
||||
mgpu.cursorSwapchain = CSwapchain::create(backend->mgpu.allocator, backend.lock());
|
||||
mgpu.cursorSwapchain = CSwapchain::create(backend->rendererState.allocator, backend.lock());
|
||||
}
|
||||
|
||||
auto OPTIONS = mgpu.cursorSwapchain->currentOptions();
|
||||
|
|
@ -1529,7 +1672,7 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
|
|||
}
|
||||
|
||||
auto NEWAQBUF = mgpu.cursorSwapchain->next(nullptr);
|
||||
if (!backend->mgpu.renderer->blit(buffer, NEWAQBUF)) {
|
||||
if (!backend->rendererState.renderer->blit(buffer, NEWAQBUF).success) {
|
||||
backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but cursor blit failed");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1552,15 +1695,14 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
|
|||
cursorVisible = true;
|
||||
}
|
||||
|
||||
needsFrame = true;
|
||||
scheduleFrame(AQ_SCHEDULE_CURSOR_SHAPE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Aquamarine::CDRMOutput::moveCursor(const Vector2D& coord) {
|
||||
cursorPos = coord;
|
||||
cursorVisible = true;
|
||||
backend->impl->moveCursor(connector);
|
||||
void Aquamarine::CDRMOutput::moveCursor(const Vector2D& coord, bool skipSchedule) {
|
||||
cursorPos = coord;
|
||||
// cursorVisible = true;
|
||||
backend->impl->moveCursor(connector, skipSchedule);
|
||||
}
|
||||
|
||||
void Aquamarine::CDRMOutput::scheduleFrame(const scheduleFrameReason reason) {
|
||||
|
|
@ -1569,7 +1711,7 @@ void Aquamarine::CDRMOutput::scheduleFrame(const scheduleFrameReason reason) {
|
|||
connector->isPageFlipPending, connector->frameEventScheduled)));
|
||||
needsFrame = true;
|
||||
|
||||
if (connector->isPageFlipPending || connector->frameEventScheduled)
|
||||
if (connector->isPageFlipPending || connector->frameEventScheduled || !enabledState)
|
||||
return;
|
||||
|
||||
connector->frameEventScheduled = true;
|
||||
|
|
@ -1597,6 +1739,10 @@ size_t Aquamarine::CDRMOutput::getGammaSize() {
|
|||
}
|
||||
|
||||
std::vector<SDRMFormat> Aquamarine::CDRMOutput::getRenderFormats() {
|
||||
if (!connector->crtc || !connector->crtc->primary || connector->crtc->primary->formats.empty()) {
|
||||
backend->log(AQ_LOG_ERROR, "Can't get formats: no crtc");
|
||||
return {};
|
||||
}
|
||||
return connector->crtc->primary->formats;
|
||||
}
|
||||
|
||||
|
|
@ -1816,14 +1962,14 @@ void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CShar
|
|||
|
||||
di_cvt_compute(&timing, &options);
|
||||
|
||||
uint16_t hsync_start = (int)MODE->pixelSize.y + timing.h_front_porch;
|
||||
uint16_t hsync_start = (int)MODE->pixelSize.x + timing.h_front_porch;
|
||||
uint16_t vsync_start = timing.v_lines_rnd + timing.v_front_porch;
|
||||
uint16_t hsync_end = hsync_start + timing.h_sync;
|
||||
uint16_t vsync_end = vsync_start + timing.v_sync;
|
||||
|
||||
modeInfo = (drmModeModeInfo){
|
||||
.clock = (uint32_t)std::round(timing.act_pixel_freq * 1000),
|
||||
.hdisplay = (uint16_t)MODE->pixelSize.y,
|
||||
.hdisplay = (uint16_t)MODE->pixelSize.x,
|
||||
.hsync_start = hsync_start,
|
||||
.hsync_end = hsync_end,
|
||||
.htotal = (uint16_t)(hsync_end + timing.h_back_porch),
|
||||
|
|
@ -1835,6 +1981,11 @@ void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CShar
|
|||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
|
||||
};
|
||||
snprintf(modeInfo.name, sizeof(modeInfo.name), "%dx%d", (int)MODE->pixelSize.x, (int)MODE->pixelSize.y);
|
||||
|
||||
TRACE(connector->backend->log(AQ_LOG_TRACE,
|
||||
std::format("drm: calculateMode: modeline dump: {} {} {} {} {} {} {} {} {} {} {}", modeInfo.clock, modeInfo.hdisplay, modeInfo.hsync_start,
|
||||
modeInfo.hsync_end, modeInfo.htotal, modeInfo.vdisplay, modeInfo.vsync_start, modeInfo.vsync_end, modeInfo.vtotal, modeInfo.vrefresh,
|
||||
modeInfo.flags)));
|
||||
}
|
||||
|
||||
Aquamarine::CDRMBufferAttachment::CDRMBufferAttachment(SP<CDRMFB> fb_) : fb(fb_) {
|
||||
|
|
@ -1850,7 +2001,7 @@ SP<CDRMLease> Aquamarine::CDRMLease::create(std::vector<SP<IOutput>> outputs) {
|
|||
|
||||
auto backend = ((CDRMBackend*)outputs.at(0)->getBackend().get())->self.lock();
|
||||
|
||||
for (auto& o : outputs) {
|
||||
for (auto const& o : outputs) {
|
||||
if (o->getBackend() != backend) {
|
||||
backend->log(AQ_LOG_ERROR, "drm lease: Mismatched backends");
|
||||
return nullptr;
|
||||
|
|
@ -1861,7 +2012,7 @@ SP<CDRMLease> Aquamarine::CDRMLease::create(std::vector<SP<IOutput>> outputs) {
|
|||
|
||||
auto lease = SP<CDRMLease>(new CDRMLease);
|
||||
|
||||
for (auto& o : outputs) {
|
||||
for (auto const& o : outputs) {
|
||||
auto drmo = ((CDRMOutput*)o.get())->self.lock();
|
||||
backend->log(AQ_LOG_DEBUG, std::format("drm lease: output {}, connector {}", drmo->name, drmo->connector->id));
|
||||
|
||||
|
|
@ -1890,7 +2041,7 @@ SP<CDRMLease> Aquamarine::CDRMLease::create(std::vector<SP<IOutput>> outputs) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto& o : lease->outputs) {
|
||||
for (auto const& o : lease->outputs) {
|
||||
o->lease = lease;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <xf86drmMode.h>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "Math.hpp"
|
||||
#include "Shared.hpp"
|
||||
#include "FormatUtils.hpp"
|
||||
|
|
@ -153,9 +154,9 @@ bool CDRMRenderer::initDRMFormats() {
|
|||
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL: Supported formats:"));
|
||||
|
||||
std::vector<GLFormat> dmaFormats;
|
||||
std::vector<SGLFormat> dmaFormats;
|
||||
|
||||
for (auto& fmt : formats) {
|
||||
for (auto const& fmt : formats) {
|
||||
std::vector<std::pair<uint64_t, bool>> mods;
|
||||
|
||||
auto ret = getModsForFormat(fmt);
|
||||
|
|
@ -169,8 +170,8 @@ bool CDRMRenderer::initDRMFormats() {
|
|||
// EGL can always do implicit modifiers.
|
||||
mods.push_back({DRM_FORMAT_MOD_INVALID, true});
|
||||
|
||||
for (auto& [mod, external] : mods) {
|
||||
dmaFormats.push_back(GLFormat{
|
||||
for (auto const& [mod, external] : mods) {
|
||||
dmaFormats.push_back(SGLFormat{
|
||||
.drmFormat = (uint32_t)fmt,
|
||||
.modifier = mod,
|
||||
.external = external,
|
||||
|
|
@ -178,7 +179,7 @@ bool CDRMRenderer::initDRMFormats() {
|
|||
}
|
||||
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL: GPU Supports Format {} (0x{:x})", fourccToName((uint32_t)fmt), fmt)));
|
||||
for (auto& [mod, external] : mods) {
|
||||
for (auto const& [mod, external] : mods) {
|
||||
auto modName = drmGetFormatModifierName(mod);
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL: | {}with modifier 0x{:x}: {}", (external ? "external only " : ""), mod, modName ? modName : "?unknown?")));
|
||||
free(modName);
|
||||
|
|
@ -223,6 +224,20 @@ SP<CDRMRenderer> CDRMRenderer::attempt(Hyprutils::Memory::CSharedPointer<CGBMAll
|
|||
loadGLProc(&renderer->egl.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
|
||||
loadGLProc(&renderer->egl.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
|
||||
loadGLProc(&renderer->egl.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
|
||||
loadGLProc(&renderer->egl.eglDestroySyncKHR, "eglDestroySyncKHR");
|
||||
loadGLProc(&renderer->egl.eglWaitSyncKHR, "eglWaitSyncKHR");
|
||||
loadGLProc(&renderer->egl.eglCreateSyncKHR, "eglCreateSyncKHR");
|
||||
loadGLProc(&renderer->egl.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID");
|
||||
|
||||
if (!renderer->egl.eglCreateSyncKHR) {
|
||||
backend_->log(AQ_LOG_ERROR, "CDRMRenderer: fail, no eglCreateSyncKHR");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!renderer->egl.eglDupNativeFenceFDANDROID) {
|
||||
backend_->log(AQ_LOG_ERROR, "CDRMRenderer: fail, no eglDupNativeFenceFDANDROID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!renderer->egl.eglGetPlatformDisplayEXT) {
|
||||
backend_->log(AQ_LOG_ERROR, "CDRMRenderer: fail, no eglGetPlatformDisplayEXT");
|
||||
|
|
@ -440,7 +455,7 @@ SGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buffa) {
|
|||
}
|
||||
|
||||
bool external = false;
|
||||
for (auto& fmt : formats) {
|
||||
for (auto const& fmt : formats) {
|
||||
if (fmt.drmFormat != dma.format || fmt.modifier != dma.modifier)
|
||||
continue;
|
||||
|
||||
|
|
@ -469,12 +484,140 @@ inline const float fullVerts[] = {
|
|||
0, 1, // bottom left
|
||||
};
|
||||
|
||||
bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||
void CDRMRenderer::waitOnSync(int fd) {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (waitOnSync): attempting to wait on fd {}", fd)));
|
||||
|
||||
std::vector<EGLint> attribs;
|
||||
int dupFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
if (dupFd < 0) {
|
||||
backend->log(AQ_LOG_TRACE, "EGL (waitOnSync): failed to dup fd for wait");
|
||||
return;
|
||||
}
|
||||
|
||||
attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID);
|
||||
attribs.push_back(dupFd);
|
||||
attribs.push_back(EGL_NONE);
|
||||
|
||||
EGLSyncKHR sync = egl.eglCreateSyncKHR(egl.display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data());
|
||||
if (sync == EGL_NO_SYNC_KHR) {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (waitOnSync): failed to create an egl sync for explicit"));
|
||||
if (dupFd >= 0)
|
||||
close(dupFd);
|
||||
return;
|
||||
}
|
||||
|
||||
// we got a sync, now we just tell egl to wait before sampling
|
||||
if (egl.eglWaitSyncKHR(egl.display, sync, 0) != EGL_TRUE) {
|
||||
if (egl.eglDestroySyncKHR(egl.display, sync) != EGL_TRUE)
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (waitOnSync): failed to destroy sync"));
|
||||
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (waitOnSync): failed to wait on the sync object"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (egl.eglDestroySyncKHR(egl.display, sync) != EGL_TRUE)
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (waitOnSync): failed to destroy sync"));
|
||||
}
|
||||
|
||||
int CDRMRenderer::recreateBlitSync() {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (recreateBlitSync): recreating blit sync"));
|
||||
|
||||
if (egl.lastBlitSync) {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (recreateBlitSync): cleaning up old sync (fd {})", egl.lastBlitSyncFD)));
|
||||
|
||||
// cleanup last sync
|
||||
if (egl.eglDestroySyncKHR(egl.display, egl.lastBlitSync) != EGL_TRUE)
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (recreateBlitSync): failed to destroy old sync"));
|
||||
|
||||
if (egl.lastBlitSyncFD >= 0)
|
||||
close(egl.lastBlitSyncFD);
|
||||
|
||||
egl.lastBlitSyncFD = -1;
|
||||
egl.lastBlitSync = nullptr;
|
||||
}
|
||||
|
||||
EGLSyncKHR sync = egl.eglCreateSyncKHR(egl.display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
|
||||
if (sync == EGL_NO_SYNC_KHR) {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (recreateBlitSync): failed to create an egl sync for explicit"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// we need to flush otherwise we might not get a valid fd
|
||||
glFlush();
|
||||
|
||||
int fd = egl.eglDupNativeFenceFDANDROID(egl.display, sync);
|
||||
if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (recreateBlitSync): failed to dup egl fence fd"));
|
||||
if (egl.eglDestroySyncKHR(egl.display, sync) != EGL_TRUE)
|
||||
TRACE(backend->log(AQ_LOG_TRACE, "EGL (recreateBlitSync): failed to destroy new sync"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
egl.lastBlitSync = sync;
|
||||
egl.lastBlitSyncFD = fd;
|
||||
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (recreateBlitSync): success, new fence exported with fd {}", fd)));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void CDRMRenderer::clearBuffer(IBuffer* buf) {
|
||||
setEGL();
|
||||
|
||||
auto dmabuf = buf->dmabuf();
|
||||
GLuint rboID = 0, fboID = 0;
|
||||
|
||||
if (!dmabuf.success) {
|
||||
backend->log(AQ_LOG_ERROR, "EGL (clear): cannot clear a non-dmabuf");
|
||||
return;
|
||||
}
|
||||
|
||||
auto rboImage = createEGLImage(dmabuf);
|
||||
if (rboImage == EGL_NO_IMAGE_KHR) {
|
||||
backend->log(AQ_LOG_ERROR, std::format("EGL (clear): createEGLImage failed: {}", eglGetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
GLCALL(glGenRenderbuffers(1, &rboID));
|
||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
||||
GLCALL(egl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)rboImage));
|
||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
||||
|
||||
GLCALL(glGenFramebuffers(1, &fboID));
|
||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
|
||||
GLCALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboID));
|
||||
|
||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
|
||||
|
||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (clear): fbo {} rbo {}", fboID, rboID)));
|
||||
|
||||
glClearColor(0.F, 0.F, 0.F, 1.F);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glFlush();
|
||||
|
||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
||||
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
egl.eglDestroyImageKHR(egl.display, rboImage);
|
||||
|
||||
restoreEGL();
|
||||
}
|
||||
|
||||
CDRMRenderer::SBlitResult CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to, int waitFD) {
|
||||
setEGL();
|
||||
|
||||
if (from->dmabuf().size != to->dmabuf().size) {
|
||||
backend->log(AQ_LOG_ERROR, "EGL (blit): buffer sizes mismatched");
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (waitFD >= 0) {
|
||||
// wait on a provided explicit fence
|
||||
waitOnSync(waitFD);
|
||||
}
|
||||
|
||||
// firstly, get a texture from the from buffer
|
||||
|
|
@ -514,7 +657,7 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
|||
|
||||
if (!verifyDestinationDMABUF(toDma)) {
|
||||
backend->log(AQ_LOG_ERROR, "EGL (blit): failed to blit: destination dmabuf unsupported");
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -533,7 +676,7 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
|||
rboImage = createEGLImage(toDma);
|
||||
if (rboImage == EGL_NO_IMAGE_KHR) {
|
||||
backend->log(AQ_LOG_ERROR, std::format("EGL (blit): createEGLImage failed: {}", eglGetError()));
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
GLCALL(glGenRenderbuffers(1, &rboID));
|
||||
|
|
@ -547,7 +690,7 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
|||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
backend->log(AQ_LOG_ERROR, std::format("EGL (blit): glCheckFramebufferStatus failed: {}", glGetError()));
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
// should never remove anything, but JIC. We'll leak an RBO and FBO if this removes anything.
|
||||
|
|
@ -623,15 +766,19 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
|||
GLCALL(glBindTexture(fromTex.target, 0));
|
||||
|
||||
// rendered, cleanup
|
||||
|
||||
glFlush();
|
||||
|
||||
// get an explicit sync fd for the secondary gpu.
|
||||
// when we pass buffers between gpus we should always use explicit sync,
|
||||
// as implicit is not guaranteed at all
|
||||
int explicitFD = recreateBlitSync();
|
||||
|
||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
||||
|
||||
restoreEGL();
|
||||
|
||||
return true;
|
||||
return {true, explicitFD == -1 ? std::nullopt : std::optional<int>{explicitFD}};
|
||||
}
|
||||
|
||||
void CDRMRenderer::onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment) {
|
||||
|
|
@ -655,7 +802,7 @@ void CDRMRenderer::onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachme
|
|||
}
|
||||
|
||||
bool CDRMRenderer::verifyDestinationDMABUF(const SDMABUFAttrs& attrs) {
|
||||
for (auto& fmt : formats) {
|
||||
for (auto const& fmt : formats) {
|
||||
if (fmt.drmFormat != attrs.format)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <aquamarine/backend/DRM.hpp>
|
||||
#include "FormatUtils.hpp"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
|
@ -19,6 +20,7 @@ namespace Aquamarine {
|
|||
GLuint texid = 0;
|
||||
GLuint target = GL_TEXTURE_2D;
|
||||
};
|
||||
|
||||
class CDRMRendererBufferAttachment : public IAttachment {
|
||||
public:
|
||||
CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer_, Hyprutils::Memory::CSharedPointer<IBuffer> buffer, EGLImageKHR image, GLuint fbo_,
|
||||
|
|
@ -45,12 +47,19 @@ namespace Aquamarine {
|
|||
|
||||
int drmFD = -1;
|
||||
|
||||
bool blit(Hyprutils::Memory::CSharedPointer<IBuffer> from, Hyprutils::Memory::CSharedPointer<IBuffer> to);
|
||||
struct SBlitResult {
|
||||
bool success = false;
|
||||
std::optional<int> syncFD;
|
||||
};
|
||||
|
||||
void setEGL();
|
||||
void restoreEGL();
|
||||
SBlitResult blit(Hyprutils::Memory::CSharedPointer<IBuffer> from, Hyprutils::Memory::CSharedPointer<IBuffer> to, int waitFD = -1);
|
||||
// can't be a SP<> because we call it from buf's ctor...
|
||||
void clearBuffer(IBuffer* buf);
|
||||
|
||||
void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment);
|
||||
void setEGL();
|
||||
void restoreEGL();
|
||||
|
||||
void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment);
|
||||
|
||||
struct {
|
||||
struct SShader {
|
||||
|
|
@ -60,8 +69,10 @@ namespace Aquamarine {
|
|||
} gl;
|
||||
|
||||
struct {
|
||||
EGLDisplay display = nullptr;
|
||||
EGLContext context = nullptr;
|
||||
EGLDisplay display = nullptr;
|
||||
EGLContext context = nullptr;
|
||||
EGLSync lastBlitSync = nullptr;
|
||||
int lastBlitSyncFD = -1;
|
||||
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
|
||||
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
|
||||
|
|
@ -70,6 +81,10 @@ namespace Aquamarine {
|
|||
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
|
||||
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
|
||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
|
||||
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
|
||||
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
|
||||
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
|
||||
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
|
||||
} egl;
|
||||
|
||||
struct {
|
||||
|
|
@ -78,16 +93,10 @@ namespace Aquamarine {
|
|||
EGLSurface draw = nullptr, read = nullptr;
|
||||
} savedEGLState;
|
||||
|
||||
struct GLFormat {
|
||||
uint32_t drmFormat = 0;
|
||||
uint64_t modifier = 0;
|
||||
bool external = false;
|
||||
};
|
||||
|
||||
SGLTex glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buf);
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CDRMRenderer> self;
|
||||
std::vector<GLFormat> formats;
|
||||
std::vector<SGLFormat> formats;
|
||||
|
||||
private:
|
||||
CDRMRenderer() = default;
|
||||
|
|
@ -96,6 +105,8 @@ namespace Aquamarine {
|
|||
std::optional<std::vector<std::pair<uint64_t, bool>>> getModsForFormat(EGLint format);
|
||||
bool initDRMFormats();
|
||||
bool verifyDestinationDMABUF(const SDMABUFAttrs& attrs);
|
||||
void waitOnSync(int fd);
|
||||
int recreateBlitSync();
|
||||
bool hasModifiers = false;
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ Aquamarine::CDRMAtomicImpl::CDRMAtomicImpl(Hyprutils::Memory::CSharedPointer<CDR
|
|||
bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
|
||||
const auto& STATE = connector->output->state->state();
|
||||
const bool enable = STATE.enabled;
|
||||
const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode;
|
||||
|
||||
if (data.modeset) {
|
||||
if (!enable)
|
||||
|
|
@ -262,11 +263,12 @@ bool Aquamarine::CDRMAtomicImpl::prepareConnector(Hyprutils::Memory::CSharedPoin
|
|||
}
|
||||
}
|
||||
|
||||
if (STATE.committed & COutputState::AQ_OUTPUT_STATE_DAMAGE && connector->crtc->primary->props.fb_damage_clips) {
|
||||
if ((STATE.committed & COutputState::AQ_OUTPUT_STATE_DAMAGE) && connector->crtc->primary->props.fb_damage_clips && MODE) {
|
||||
if (STATE.damage.empty())
|
||||
data.atomic.fbDamage = 0;
|
||||
else {
|
||||
std::vector<pixman_box32_t> rects = STATE.damage.getRects();
|
||||
TRACE(connector->backend->backend->log(AQ_LOG_TRACE, std::format("atomic drm: clipping damage to pixel size {}", MODE->pixelSize)));
|
||||
std::vector<pixman_box32_t> rects = STATE.damage.copy().intersect(CBox{{}, MODE->pixelSize}).getRects();
|
||||
if (drmModeCreatePropertyBlob(connector->backend->gpu->fd, rects.data(), sizeof(pixman_box32_t) * rects.size(), &data.atomic.fbDamage)) {
|
||||
connector->backend->backend->log(AQ_LOG_ERROR, "atomic drm: failed to create a damage blob");
|
||||
return false;
|
||||
|
|
@ -308,28 +310,30 @@ bool Aquamarine::CDRMAtomicImpl::commit(Hyprutils::Memory::CSharedPointer<SDRMCo
|
|||
bool Aquamarine::CDRMAtomicImpl::reset() {
|
||||
CDRMAtomicRequest request(backend);
|
||||
|
||||
for (auto& crtc : backend->crtcs) {
|
||||
for (auto const& crtc : backend->crtcs) {
|
||||
request.add(crtc->id, crtc->props.mode_id, 0);
|
||||
request.add(crtc->id, crtc->props.active, 0);
|
||||
}
|
||||
|
||||
for (auto& conn : backend->connectors) {
|
||||
for (auto const& conn : backend->connectors) {
|
||||
request.add(conn->id, conn->props.crtc_id, 0);
|
||||
}
|
||||
|
||||
for (auto& plane : backend->planes) {
|
||||
for (auto const& plane : backend->planes) {
|
||||
request.planeProps(plane, nullptr, 0, {});
|
||||
}
|
||||
|
||||
return request.commit(DRM_MODE_ATOMIC_ALLOW_MODESET);
|
||||
}
|
||||
|
||||
bool Aquamarine::CDRMAtomicImpl::moveCursor(SP<SDRMConnector> connector) {
|
||||
bool Aquamarine::CDRMAtomicImpl::moveCursor(SP<SDRMConnector> connector, bool skipSchedule) {
|
||||
if (!connector->output->cursorVisible || !connector->output->state->state().enabled || !connector->crtc || !connector->crtc->cursor)
|
||||
return true;
|
||||
|
||||
connector->output->needsFrame = true;
|
||||
connector->output->scheduleFrame(IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
if (!skipSchedule) {
|
||||
TRACE(connector->backend->log(AQ_LOG_TRACE, "atomic moveCursor"));
|
||||
connector->output->scheduleFrame(IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@ Aquamarine::CDRMLegacyImpl::CDRMLegacyImpl(Hyprutils::Memory::CSharedPointer<CDR
|
|||
;
|
||||
}
|
||||
|
||||
bool Aquamarine::CDRMLegacyImpl::moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector) {
|
||||
bool Aquamarine::CDRMLegacyImpl::moveCursor(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, bool skipSchedule) {
|
||||
if (!connector->output->cursorVisible || !connector->output->state->state().enabled || !connector->crtc || !connector->crtc->cursor)
|
||||
return true;
|
||||
|
||||
connector->output->needsFrame = true;
|
||||
connector->output->scheduleFrame(IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
if (!skipSchedule)
|
||||
connector->output->scheduleFrame(IOutput::AQ_SCHEDULE_CURSOR_MOVE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ bool Aquamarine::CDRMLegacyImpl::commit(Hyprutils::Memory::CSharedPointer<SDRMCo
|
|||
|
||||
bool Aquamarine::CDRMLegacyImpl::reset() {
|
||||
bool ok = true;
|
||||
for (auto& connector : backend->connectors) {
|
||||
for (auto const& connector : backend->connectors) {
|
||||
if (!connector->crtc)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using namespace Hyprutils::Memory;
|
|||
#define SP CSharedPointer
|
||||
|
||||
bool Aquamarine::CAttachmentManager::has(eAttachmentType type) {
|
||||
for (auto& a : attachments) {
|
||||
for (auto const& a : attachments) {
|
||||
if (a->type() == type)
|
||||
return true;
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ bool Aquamarine::CAttachmentManager::has(eAttachmentType type) {
|
|||
}
|
||||
|
||||
SP<IAttachment> Aquamarine::CAttachmentManager::get(eAttachmentType type) {
|
||||
for (auto& a : attachments) {
|
||||
for (auto const& a : attachments) {
|
||||
if (a->type() == type)
|
||||
return a;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
using namespace Aquamarine;
|
||||
|
||||
Hyprutils::Memory::CSharedPointer<SOutputMode> Aquamarine::IOutput::preferredMode() {
|
||||
for (auto& m : modes) {
|
||||
for (auto const& m : modes) {
|
||||
if (m->preferred)
|
||||
return m;
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ Hyprutils::Memory::CSharedPointer<SOutputMode> Aquamarine::IOutput::preferredMod
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Aquamarine::IOutput::moveCursor(const Hyprutils::Math::Vector2D& coord) {
|
||||
void Aquamarine::IOutput::moveCursor(const Hyprutils::Math::Vector2D& coord, bool skipSchedule) {
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "FormatUtils.hpp"
|
||||
#include <drm_fourcc.h>
|
||||
#include <xf86drm.h>
|
||||
#include <cstdlib>
|
||||
|
||||
std::string fourccToName(uint32_t drmFormat) {
|
||||
auto fmt = drmGetFormatName(drmFormat);
|
||||
|
|
|
|||
Loading…
Reference in New Issue