Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aquamarine for openSUSE:Factory checked in at 2025-07-17 17:18:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aquamarine (Old) and /work/SRC/openSUSE:Factory/.aquamarine.new.8875 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aquamarine" Thu Jul 17 17:18:45 2025 rev:7 rq:1293861 version:0.9.1 Changes: -------- --- /work/SRC/openSUSE:Factory/aquamarine/aquamarine.changes 2025-03-25 22:17:56.332353063 +0100 +++ /work/SRC/openSUSE:Factory/.aquamarine.new.8875/aquamarine.changes 2025-07-17 17:19:58.402767863 +0200 @@ -1,0 +2,26 @@ +Wed Jul 16 12:35:08 UTC 2025 - Florian "sp1rit" <sp1...@disroot.org> + +- Update to aquamarine-0.9.1: + * A small patch release fixing builds with hl <= 0.49 + * Fixes: + - backend: don't use a shorthand for SP + - Avoid unnecessary modeset + +- Changes from aquamarine aquamarine-0.9.0: + * A new major update, breaking ABI, but bringing a lot of + improvements + * Fixes: + - swapchain: fix age + - wayland: don't force swapchain length + - backend: Fix compiler warnings + - Restore hdr metadata after vt switch + - atomic: fix compiler warning with string + - clang-tidy: fix some errors + * Other: + - a few small renderer optimisations + - depend on gles3 and use vertex array objects + - reduce a bit of local temporar copies going around in renderer + - Use typed signals from hyprutils + - optimize blitting and use gles3 shaders + +------------------------------------------------------------------- Old: ---- aquamarine-0.8.0.tar.xz New: ---- aquamarine-0.9.1.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aquamarine.spec ++++++ --- /var/tmp/diff_new_pack.Dz6X00/_old 2025-07-17 17:19:59.430810706 +0200 +++ /var/tmp/diff_new_pack.Dz6X00/_new 2025-07-17 17:19:59.430810706 +0200 @@ -16,18 +16,19 @@ # -%define sover 7 +%define sover 8 %define _description %{expand: Aquamarine is a very light linux rendering backend library. It provides basic abstractions for an application to render on a Wayland session (in a window) or a native DRM session.} Name: aquamarine -Version: 0.8.0 +Version: 0.9.1 Release: 0 Summary: Rendering backend library License: BSD-3-Clause URL: https://github.com/hyprwm/aquamarine Source0: %{name}-%{version}.tar.xz +BuildRequires: Mesa-libGLESv3-devel BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: pkgconfig @@ -36,7 +37,7 @@ BuildRequires: pkgconfig(gl) BuildRequires: pkgconfig(glesv2) BuildRequires: pkgconfig(hwdata) -BuildRequires: pkgconfig(hyprutils) >= 0.5.2 +BuildRequires: pkgconfig(hyprutils) >= 0.8.0 BuildRequires: pkgconfig(libdisplay-info) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(libinput) >= 1.26.0 ++++++ aquamarine-0.8.0.tar.xz -> aquamarine-0.9.1.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/.clang-tidy new/aquamarine-0.9.1/.clang-tidy --- old/aquamarine-0.8.0/.clang-tidy 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/.clang-tidy 2025-07-07 17:58:11.000000000 +0200 @@ -1,12 +1,12 @@ WarningsAsErrors: '*' HeaderFilterRegex: '.*\.hpp' -FormatStyle: file +FormatStyle: 'file' Checks: > -*, bugprone-*, -bugprone-easily-swappable-parameters, - -bugprone-forward-declararion-namespace, - -bugprone-forward-declararion-namespace, + -bugprone-forward-declaration-namespace, + -bugprone-forward-declaration-namespace, -bugprone-macro-parentheses, -bugprone-narrowing-conversions, -bugprone-branch-clone, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/.github/workflows/nix.yml new/aquamarine-0.9.1/.github/workflows/nix.yml --- old/aquamarine-0.8.0/.github/workflows/nix.yml 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/.github/workflows/nix.yml 2025-07-07 17:58:11.000000000 +0200 @@ -13,7 +13,35 @@ steps: - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v26 + - name: Install Nix + uses: nixbuild/nix-quick-install-action@v31 + with: + nix_conf: | + keep-env-derivations = true + keep-outputs = true + + - name: Restore and save Nix store + uses: nix-community/cache-nix-action@v6 + with: + # restore and save a cache using this key + primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} + # if there's no cache hit, restore a cache by this prefix + restore-prefixes-first-match: nix-${{ runner.os }}- + # collect garbage until the Nix store size (in bytes) is at most this number + # before trying to save a new cache + # 1G = 1073741824 + gc-max-store-size-linux: 1G + # do purge caches + purge: true + # purge all versions of the cache + purge-prefixes: nix-${{ runner.os }}- + # created more than this number of seconds ago + purge-created: 0 + # or, last accessed more than this number of seconds ago + # relative to the start of the `Post Restore and save Nix store` phase + purge-last-accessed: 0 + # except any version with the key that is the same as the `primary-key` + purge-primary-key: never # not needed (yet) # - uses: cachix/cachix-action@v12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/CMakeLists.txt new/aquamarine-0.9.1/CMakeLists.txt --- old/aquamarine-0.8.0/CMakeLists.txt 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/CMakeLists.txt 2025-07-07 17:58:11.000000000 +0200 @@ -19,7 +19,7 @@ set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}) find_package(PkgConfig REQUIRED) -find_package(OpenGL REQUIRED COMPONENTS "GLES2") +find_package(OpenGL REQUIRED COMPONENTS "GLES3") find_package(hyprwayland-scanner 0.4.0 REQUIRED) pkg_check_modules( deps @@ -29,7 +29,7 @@ libinput>=1.26.0 wayland-client wayland-protocols - hyprutils>=0.5.2 + hyprutils>=0.8.0 pixman-1 libdrm gbm @@ -65,7 +65,7 @@ PUBLIC "./include" PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}") set_target_properties(aquamarine PROPERTIES VERSION ${AQUAMARINE_VERSION} - SOVERSION 7) + SOVERSION 8) target_link_libraries(aquamarine OpenGL::EGL OpenGL::OpenGL PkgConfig::deps) check_include_file("sys/timerfd.h" HAS_TIMERFD) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/VERSION new/aquamarine-0.9.1/VERSION --- old/aquamarine-0.8.0/VERSION 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/VERSION 2025-07-07 17:58:11.000000000 +0200 @@ -1 +1 @@ -0.8.0 +0.9.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/flake.lock new/aquamarine-0.9.1/flake.lock --- old/aquamarine-0.8.0/flake.lock 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/flake.lock 2025-07-07 17:58:11.000000000 +0200 @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1741534688, - "narHash": "sha256-EV3945SnjOCuRVbGRghsWx/9D89FyshnSO1Q6/TuQ14=", + "lastModified": 1750960192, + "narHash": "sha256-AbaeiQAFq66XRMkhnwzxe8uZO2d81RdqO2XuuMzZU8U=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "dd1f720cbc2dbb3c71167c9598045dd3261d27b3", + "rev": "d844a08d830e87d023ba2838e645004cb08118f6", "type": "github" }, "original": { @@ -33,11 +33,11 @@ ] }, "locked": { - "lastModified": 1739870480, - "narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", + "lastModified": 1750371869, + "narHash": "sha256-lGk4gLjgZQ/rndUkzmPYcgbHr8gKU5u71vyrjnwfpB4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", + "rev": "aa38edd6e3e277ae6a97ea83a69261a5c3aab9fd", "type": "github" }, "original": { @@ -48,11 +48,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1741379970, - "narHash": "sha256-Wh7esNh7G24qYleLvgOSY/7HlDUzWaL/n4qzlBePpiw=", + "lastModified": 1750776420, + "narHash": "sha256-/CG+w0o0oJ5itVklOoLbdn2dGB0wbZVOoDm4np6w09A=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "36fd87baa9083f34f7f5027900b62ee6d09b1f2f", + "rev": "30a61f056ac492e3b7cdcb69c1e6abdcf00e39cf", "type": "github" }, "original": { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/flake.nix new/aquamarine-0.9.1/flake.nix --- old/aquamarine-0.8.0/flake.nix 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/flake.nix 2025-07-07 17:58:11.000000000 +0200 @@ -52,7 +52,7 @@ inputs.hyprwayland-scanner.overlays.default (final: prev: { aquamarine = final.callPackage ./nix/default.nix { - stdenv = final.gcc14Stdenv; + stdenv = final.gcc15Stdenv; version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); }; aquamarine-with-tests = final.aquamarine.override {doCheck = true;}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/backend/Backend.hpp new/aquamarine-0.9.1/include/aquamarine/backend/Backend.hpp --- old/aquamarine-0.8.0/include/aquamarine/backend/Backend.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/backend/Backend.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -12,6 +12,15 @@ #include "Session.hpp" namespace Aquamarine { + class IOutput; + class IPointer; + class IKeyboard; + class ITouch; + class ISwitch; + class ITablet; + class ITabletTool; + class ITabletPad; + enum eBackendType : uint32_t { AQ_BACKEND_WAYLAND = 0, AQ_BACKEND_DRM, @@ -123,16 +132,16 @@ void onNewGpu(std::string path); struct { - Hyprutils::Signal::CSignal newOutput; - Hyprutils::Signal::CSignal newPointer; - Hyprutils::Signal::CSignal newKeyboard; - Hyprutils::Signal::CSignal newTouch; - Hyprutils::Signal::CSignal newSwitch; - Hyprutils::Signal::CSignal newTablet; - Hyprutils::Signal::CSignal newTabletTool; - Hyprutils::Signal::CSignal newTabletPad; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<IOutput>> newOutput; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<IPointer>> newPointer; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<IKeyboard>> newKeyboard; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<ITouch>> newTouch; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<ISwitch>> newSwitch; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<ITablet>> newTablet; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<ITabletTool>> newTabletTool; + Hyprutils::Signal::CSignalT<Hyprutils::Memory::CSharedPointer<ITabletPad>> newTabletPad; - Hyprutils::Signal::CSignal pollFDsChanged; + Hyprutils::Signal::CSignalT<> pollFDsChanged; } events; Hyprutils::Memory::CSharedPointer<IAllocator> primaryAllocator; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/backend/DRM.hpp new/aquamarine-0.9.1/include/aquamarine/backend/DRM.hpp --- old/aquamarine-0.8.0/include/aquamarine/backend/DRM.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/backend/DRM.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -53,7 +53,7 @@ bool active = true; struct { - Hyprutils::Signal::CSignal destroy; + Hyprutils::Signal::CSignalT<> destroy; } events; private: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/backend/Session.hpp new/aquamarine-0.9.1/include/aquamarine/backend/Session.hpp --- old/aquamarine-0.8.0/include/aquamarine/backend/Session.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/backend/Session.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -49,8 +49,8 @@ }; struct { - Hyprutils::Signal::CSignal change; - Hyprutils::Signal::CSignal remove; + Hyprutils::Signal::CSignalT<SChangeEvent> change; + Hyprutils::Signal::CSignalT<> remove; } events; private: @@ -224,9 +224,9 @@ }; struct { - Hyprutils::Signal::CSignal changeActive; - Hyprutils::Signal::CSignal addDrmCard; - Hyprutils::Signal::CSignal destroy; + Hyprutils::Signal::CSignalT<> changeActive; + Hyprutils::Signal::CSignalT<SAddDrmCardEvent> addDrmCard; + Hyprutils::Signal::CSignalT<> destroy; } events; private: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/buffer/Buffer.hpp new/aquamarine-0.9.1/include/aquamarine/buffer/Buffer.hpp --- old/aquamarine-0.8.0/include/aquamarine/buffer/Buffer.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/buffer/Buffer.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -66,8 +66,8 @@ CAttachmentManager attachments; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal backendRelease; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<> backendRelease; } events; private: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/input/Input.hpp new/aquamarine-0.9.1/include/aquamarine/input/Input.hpp --- old/aquamarine-0.8.0/include/aquamarine/input/Input.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/input/Input.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -28,9 +28,9 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal key; - Hyprutils::Signal::CSignal modifiers; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<SKeyEvent> key; + Hyprutils::Signal::CSignalT<SModifiersEvent> modifiers; } events; }; @@ -128,23 +128,23 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal move; - Hyprutils::Signal::CSignal warp; - Hyprutils::Signal::CSignal button; - Hyprutils::Signal::CSignal axis; - Hyprutils::Signal::CSignal frame; - - Hyprutils::Signal::CSignal swipeBegin; - Hyprutils::Signal::CSignal swipeUpdate; - Hyprutils::Signal::CSignal swipeEnd; - - Hyprutils::Signal::CSignal pinchBegin; - Hyprutils::Signal::CSignal pinchUpdate; - Hyprutils::Signal::CSignal pinchEnd; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<SMoveEvent> move; + Hyprutils::Signal::CSignalT<SWarpEvent> warp; + Hyprutils::Signal::CSignalT<SButtonEvent> button; + Hyprutils::Signal::CSignalT<SAxisEvent> axis; + Hyprutils::Signal::CSignalT<> frame; + + Hyprutils::Signal::CSignalT<SSwipeBeginEvent> swipeBegin; + Hyprutils::Signal::CSignalT<SSwipeUpdateEvent> swipeUpdate; + Hyprutils::Signal::CSignalT<SSwipeEndEvent> swipeEnd; + + Hyprutils::Signal::CSignalT<SPinchBeginEvent> pinchBegin; + Hyprutils::Signal::CSignalT<SPinchUpdateEvent> pinchUpdate; + Hyprutils::Signal::CSignalT<SPinchEndEvent> pinchEnd; - Hyprutils::Signal::CSignal holdBegin; - Hyprutils::Signal::CSignal holdEnd; + Hyprutils::Signal::CSignalT<SHoldBeginEvent> holdBegin; + Hyprutils::Signal::CSignalT<SHoldEndEvent> holdEnd; } events; }; @@ -182,12 +182,12 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal move; - Hyprutils::Signal::CSignal down; - Hyprutils::Signal::CSignal up; - Hyprutils::Signal::CSignal cancel; - Hyprutils::Signal::CSignal frame; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<SMotionEvent> move; + Hyprutils::Signal::CSignalT<SDownEvent> down; + Hyprutils::Signal::CSignalT<SUpEvent> up; + Hyprutils::Signal::CSignalT<SCancelEvent> cancel; + Hyprutils::Signal::CSignalT<> frame; } events; }; @@ -213,8 +213,8 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal fire; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<SFireEvent> fire; } events; }; @@ -277,11 +277,11 @@ }; struct { - Hyprutils::Signal::CSignal axis; - Hyprutils::Signal::CSignal proximity; - Hyprutils::Signal::CSignal tip; - Hyprutils::Signal::CSignal button; - Hyprutils::Signal::CSignal destroy; + Hyprutils::Signal::CSignalT<SAxisEvent> axis; + Hyprutils::Signal::CSignalT<SProximityEvent> proximity; + Hyprutils::Signal::CSignalT<STipEvent> tip; + Hyprutils::Signal::CSignalT<SButtonEvent> button; + Hyprutils::Signal::CSignalT<> destroy; } events; }; @@ -321,7 +321,7 @@ uint32_t capabilities = 0; // enum eTabletToolCapabilities struct { - Hyprutils::Signal::CSignal destroy; + Hyprutils::Signal::CSignalT<> destroy; } events; }; @@ -379,11 +379,11 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal button; - Hyprutils::Signal::CSignal ring; - Hyprutils::Signal::CSignal strip; - Hyprutils::Signal::CSignal attach; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<SButtonEvent> button; + Hyprutils::Signal::CSignalT<SRingEvent> ring; + Hyprutils::Signal::CSignalT<SStripEvent> strip; + Hyprutils::Signal::CSignalT<> attach; } events; }; -} \ No newline at end of file +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/include/aquamarine/output/Output.hpp new/aquamarine-0.9.1/include/aquamarine/output/Output.hpp --- old/aquamarine-0.8.0/include/aquamarine/output/Output.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/include/aquamarine/output/Output.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -209,12 +209,12 @@ }; struct { - Hyprutils::Signal::CSignal destroy; - Hyprutils::Signal::CSignal frame; - Hyprutils::Signal::CSignal needsFrame; - Hyprutils::Signal::CSignal present; - Hyprutils::Signal::CSignal commit; - Hyprutils::Signal::CSignal state; + Hyprutils::Signal::CSignalT<> destroy; + Hyprutils::Signal::CSignalT<> frame; + Hyprutils::Signal::CSignalT<> needsFrame; + Hyprutils::Signal::CSignalT<SPresentEvent> present; + Hyprutils::Signal::CSignalT<> commit; + Hyprutils::Signal::CSignalT<SStateEvent> state; } events; }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/allocator/Swapchain.cpp new/aquamarine-0.9.1/src/allocator/Swapchain.cpp --- old/aquamarine-0.8.0/src/allocator/Swapchain.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/allocator/Swapchain.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -66,7 +66,7 @@ lastAcquired = (lastAcquired + 1) % options.length; if (age) - *age = 1; + *age = options.length; // we always just rotate return buffers.at(lastAcquired); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/Backend.cpp new/aquamarine-0.9.1/src/backend/Backend.cpp --- old/aquamarine-0.8.0/src/backend/Backend.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/Backend.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -102,8 +102,7 @@ bool Aquamarine::CBackend::start() { log(AQ_LOG_DEBUG, "Starting the Aquamarine backend!"); - bool fallback = false; - int started = 0; + int started = 0; auto optionsForType = [this](eBackendType type) -> SBackendImplementationOptions { for (auto const& o : implementationOptions) { @@ -118,7 +117,6 @@ if (!ok) { log(AQ_LOG_ERROR, std::format("Requested backend ({}) could not start, enabling fallbacks", backendTypeToName(implementations.at(i)->type()))); - fallback = true; if (optionsForType(implementations.at(i)->type()).backendRequestMode == AQ_BACKEND_REQUEST_MANDATORY) { log(AQ_LOG_CRITICAL, std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementations.at(i)->type()))); implementations.clear(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/Headless.cpp new/aquamarine-0.9.1/src/backend/Headless.cpp --- old/aquamarine-0.8.0/src/backend/Headless.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/Headless.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -181,7 +181,6 @@ void Aquamarine::CHeadlessBackend::updateTimerFD() { long long lowestNs = TIMESPEC_NSEC_PER_SEC * 240 /* 240s, 4 mins */; const auto clocknow = std::chrono::steady_clock::now(); - bool any = false; for (auto const& t : timers.timers) { auto delta = std::chrono::duration_cast<std::chrono::microseconds>(t.when - clocknow).count() * 1000 /* µs -> ns */; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/Session.cpp new/aquamarine-0.9.1/src/backend/Session.cpp --- old/aquamarine-0.8.0/src/backend/Session.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/Session.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -620,7 +620,6 @@ break; } case LIBINPUT_EVENT_TOUCH_FRAME: { - auto te = libinput_event_get_touch_event(e); hlDevice->touch->events.frame.emit(); break; } @@ -709,7 +708,8 @@ break; } - // fallthrough. If this is proximity in, also process axis. + // If this is proximity in, also process axis. + [[fallthrough]]; } case LIBINPUT_EVENT_TABLET_TOOL_AXIS: { auto tte = libinput_event_get_tablet_tool_event(e); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/Wayland.cpp new/aquamarine-0.9.1/src/backend/Wayland.cpp --- old/aquamarine-0.8.0/src/backend/Wayland.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/Wayland.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -542,8 +542,7 @@ } bool Aquamarine::CWaylandOutput::commit() { - Vector2D pixelSize = {}; - uint32_t refreshRate = 0; + Vector2D pixelSize = {}; if (state->internalState.customMode) pixelSize = state->internalState.customMode->pixelSize; @@ -566,7 +565,7 @@ return true; } - if (!swapchain->reconfigure(SSwapchainOptions{.length = 2, .size = pixelSize, .format = format})) { + if (!swapchain->reconfigure(SSwapchainOptions{.length = swapchain->currentOptions().length, .size = pixelSize, .format = format})) { backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: swapchain failed reconfiguring", name)); return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/drm/DRM.cpp new/aquamarine-0.9.1/src/backend/drm/DRM.cpp --- old/aquamarine-0.8.0/src/backend/drm/DRM.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/drm/DRM.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -40,7 +40,7 @@ #define SP CSharedPointer Aquamarine::CDRMBackend::CDRMBackend(SP<CBackend> backend_) : backend(backend_) { - listeners.sessionActivate = backend->session->events.changeActive.registerListener([this](std::any d) { + listeners.sessionActivate = backend->session->events.changeActive.listen([this] { if (backend->session->active) { // session got activated, we need to restore restoreAfterVT(); @@ -378,16 +378,18 @@ if (!c->crtc || !c->output) continue; + auto& STATE = c->output->state->state(); + SDRMConnectorCommitData data = { - .mainFB = nullptr, - .modeset = true, - .blocking = true, - .flags = 0, - .test = false, + .mainFB = nullptr, + .modeset = true, + .blocking = true, + .flags = 0, + .test = false, + .hdrMetadata = STATE.hdrMetadata, }; - auto& STATE = c->output->state->state(); - auto& MODE = STATE.customMode ? STATE.customMode : STATE.mode; + auto& MODE = STATE.customMode ? 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."); @@ -734,8 +736,7 @@ drmFreeVersion(drmVer); - listeners.gpuChange = gpu->events.change.registerListener([this](std::any d) { - auto E = std::any_cast<CSessionDevice::SChangeEvent>(d); + listeners.gpuChange = gpu->events.change.listen([this](const CSessionDevice::SChangeEvent& E) { if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG) { backend->log(AQ_LOG_DEBUG, std::format("drm: Got a hotplug event for {}", gpuName)); recheckOutputs(); @@ -745,7 +746,7 @@ } }); - listeners.gpuRemove = gpu->events.remove.registerListener([this](std::any d) { + listeners.gpuRemove = gpu->events.remove.listen([this] { std::erase_if(backend->implementations, [this](const auto& impl) { return impl->drmFD() == this->drmFD(); }); backend->events.pollFDsChanged.emit(); }); @@ -894,7 +895,6 @@ } bool Aquamarine::CDRMBackend::start() { - impl->reset(); return true; } @@ -2071,7 +2071,7 @@ closeHandles(); - listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { + listeners.destroyBuffer = buffer->events.destroy.listen([this] { drop(); dead = true; id = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/drm/Renderer.cpp new/aquamarine-0.9.1/src/backend/drm/Renderer.cpp --- old/aquamarine-0.8.0/src/backend/drm/Renderer.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/drm/Renderer.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -9,10 +9,13 @@ #include "Shared.hpp" #include "FormatUtils.hpp" #include <aquamarine/allocator/GBM.hpp> +#include <hyprutils/os/FileDescriptor.hpp> using namespace Aquamarine; using namespace Hyprutils::Memory; using namespace Hyprutils::Math; +using namespace Hyprutils::OS; + #define SP CSharedPointer #define WP CWeakPointer @@ -20,11 +23,13 @@ #define GLCALL(__CALL__) \ { \ __CALL__; \ - auto err = glGetError(); \ - if (err != GL_NO_ERROR) { \ - backend->log(AQ_LOG_ERROR, \ - std::format("[GLES] Error in call at {}@{}: 0x{:x}", __LINE__, \ - ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err)); \ + if (Aquamarine::isTrace()) { \ + auto err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + backend->log(AQ_LOG_ERROR, \ + std::format("[GLES] Error in call at {}@{}: 0x{:x}", __LINE__, \ + ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err)); \ + } \ } \ } @@ -78,10 +83,15 @@ } inline const std::string VERT_SRC = R"#( +#version 300 es +precision highp float; + uniform mat3 proj; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec2 v_texcoord; + +in vec2 pos; +in vec2 texcoord; + +out vec2 v_texcoord; void main() { gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); @@ -89,22 +99,30 @@ })#"; inline const std::string FRAG_SRC = R"#( +#version 300 es precision highp float; -varying vec2 v_texcoord; // is in 0-1 + +in vec2 v_texcoord; +out vec4 fragColor; + uniform sampler2D tex; void main() { - gl_FragColor = texture2D(tex, v_texcoord); + fragColor = texture(tex, v_texcoord); })#"; inline const std::string FRAG_SRC_EXT = R"#( -#extension GL_OES_EGL_image_external : require +#version 300 es +#extension GL_OES_EGL_image_external_essl3 : require precision highp float; -varying vec2 v_texcoord; // is in 0-1 + +in vec2 v_texcoord; +out vec4 fragColor; + uniform samplerExternalOES texture0; void main() { - gl_FragColor = texture2D(texture0, v_texcoord); + fragColor = texture(texture0, v_texcoord); })#"; // ------------------- egl stuff @@ -167,6 +185,54 @@ // ------------------- +CDRMRenderer::SShader::~SShader() { + if (program == 0) + return; + + if (shaderVao) + glDeleteVertexArrays(1, &shaderVao); + + if (shaderVboPos) + glDeleteBuffers(1, &shaderVboPos); + + if (shaderVboUv) + glDeleteBuffers(1, &shaderVboUv); + + glDeleteProgram(program); + program = 0; +} + +void CDRMRenderer::SShader::createVao() { + const float fullVerts[] = { + 1, 0, // top right + 0, 0, // top left + 1, 1, // bottom right + 0, 1, // bottom left + }; + + glGenVertexArrays(1, &shaderVao); + glBindVertexArray(shaderVao); + + if (posAttrib != -1) { + glGenBuffers(1, &shaderVboPos); + glBindBuffer(GL_ARRAY_BUFFER, shaderVboPos); + glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_STATIC_DRAW); + glEnableVertexAttribArray(posAttrib); + glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + } + + if (texAttrib != -1) { + glGenBuffers(1, &shaderVboUv); + glBindBuffer(GL_ARRAY_BUFFER, shaderVboUv); + glBufferData(GL_ARRAY_BUFFER, sizeof(fullVerts), fullVerts, GL_STATIC_DRAW); + glEnableVertexAttribArray(texAttrib); + glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + EGLDeviceEXT CDRMRenderer::eglDeviceFromDRMFD(int drmFD) { EGLint nDevices = 0; if (!proc.eglQueryDevicesEXT(0, nullptr, &nDevices)) { @@ -241,12 +307,19 @@ } // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) - if (!linearIsExternal && std::ranges::find(mods, DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) + if (!linearIsExternal && std::ranges::find(mods, DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.empty()) result.emplace_back(DRM_FORMAT_MOD_LINEAR, true); return result; } +void CDRMRenderer::useProgram(GLuint prog) { + if (m_currentProgram == prog) + return; + + GLCALL(glUseProgram(prog)); +} + bool CDRMRenderer::initDRMFormats() { std::vector<EGLint> formats; @@ -255,7 +328,7 @@ formats.resize(len); proc.eglQueryDmaBufFormatsEXT(egl.display, len, formats.data(), &len); - if (formats.size() == 0) { + if (formats.empty()) { backend->log(AQ_LOG_ERROR, "EGL: Failed to get formats"); return false; } @@ -276,7 +349,7 @@ mods = *ret; } - hasModifiers = hasModifiers || mods.size() > 0; + hasModifiers = hasModifiers || !mods.empty(); // EGL can always do implicit modifiers. mods.emplace_back(DRM_FORMAT_MOD_INVALID, true); @@ -365,7 +438,7 @@ RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a Hyprland or Aquamarine issue."); } -void CDRMRenderer::initContext(bool GLES2) { +void CDRMRenderer::initContext() { RASSERT(egl.display != nullptr && egl.display != EGL_NO_DISPLAY, "CDRMRenderer: Can't create EGL context without display"); EGLint major, minor; @@ -400,27 +473,15 @@ auto attrsNoVer = attrs; - if (GLES2) { - attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); - attrs.push_back(2); - attrs.push_back(EGL_CONTEXT_MINOR_VERSION); - attrs.push_back(0); - } else { - attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); - attrs.push_back(3); - attrs.push_back(EGL_CONTEXT_MINOR_VERSION); - attrs.push_back(2); - } + attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); + attrs.push_back(3); + attrs.push_back(EGL_CONTEXT_MINOR_VERSION); + attrs.push_back(2); attrs.push_back(EGL_NONE); egl.context = eglCreateContext(egl.display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data()); if (egl.context == EGL_NO_CONTEXT) { - if (GLES2) { - backend->log(AQ_LOG_ERROR, "CDRMRenderer: Can't create renderer, eglCreateContext failed with GLES 2.0"); - return; - } - backend->log(AQ_LOG_ERROR, "CDRMRenderer: eglCreateContext failed with GLES 3.2, retrying GLES 3.0"); attrs = attrsNoVer; @@ -458,7 +519,7 @@ free(drmName); } - backend->log(AQ_LOG_DEBUG, std::format("Creating {}CDRMRenderer on gpu {}", GLES2 ? "GLES2 " : "", gpuName)); + backend->log(AQ_LOG_DEBUG, std::format("Creating CDRMRenderer on gpu {}", gpuName)); backend->log(AQ_LOG_DEBUG, std::format("Using: {}", (char*)glGetString(GL_VERSION))); backend->log(AQ_LOG_DEBUG, std::format("Vendor: {}", (char*)glGetString(GL_VENDOR))); backend->log(AQ_LOG_DEBUG, std::format("Renderer: {}", (char*)glGetString(GL_RENDERER))); @@ -474,26 +535,28 @@ if (!exts.EXT_image_dma_buf_import || !initDRMFormats()) backend->log(AQ_LOG_ERROR, "CDRMRenderer: initDRMFormats failed, dma-buf won't work"); - gl.shader.program = createProgram(VERT_SRC, FRAG_SRC); - if (gl.shader.program == 0) + shader.program = createProgram(VERT_SRC, FRAG_SRC); + if (shader.program == 0) backend->log(AQ_LOG_ERROR, "CDRMRenderer: texture shader failed"); - gl.shader.proj = glGetUniformLocation(gl.shader.program, "proj"); - gl.shader.posAttrib = glGetAttribLocation(gl.shader.program, "pos"); - gl.shader.texAttrib = glGetAttribLocation(gl.shader.program, "texcoord"); - gl.shader.tex = glGetUniformLocation(gl.shader.program, "tex"); + shader.proj = glGetUniformLocation(shader.program, "proj"); + shader.posAttrib = glGetAttribLocation(shader.program, "pos"); + shader.texAttrib = glGetAttribLocation(shader.program, "texcoord"); + shader.tex = glGetUniformLocation(shader.program, "tex"); + shader.createVao(); - gl.shaderExt.program = createProgram(VERT_SRC, FRAG_SRC_EXT); - if (gl.shaderExt.program == 0) + shaderExt.program = createProgram(VERT_SRC, FRAG_SRC_EXT); + if (shaderExt.program == 0) backend->log(AQ_LOG_ERROR, "CDRMRenderer: external texture shader failed"); - gl.shaderExt.proj = glGetUniformLocation(gl.shaderExt.program, "proj"); - gl.shaderExt.posAttrib = glGetAttribLocation(gl.shaderExt.program, "pos"); - gl.shaderExt.texAttrib = glGetAttribLocation(gl.shaderExt.program, "texcoord"); - gl.shaderExt.tex = glGetUniformLocation(gl.shaderExt.program, "tex"); + shaderExt.proj = glGetUniformLocation(shaderExt.program, "proj"); + shaderExt.posAttrib = glGetAttribLocation(shaderExt.program, "pos"); + shaderExt.texAttrib = glGetAttribLocation(shaderExt.program, "texcoord"); + shaderExt.tex = glGetUniformLocation(shaderExt.program, "tex"); + shaderExt.createVao(); } -SP<CDRMRenderer> CDRMRenderer::attempt(SP<CBackend> backend_, int drmFD, bool GLES2) { +SP<CDRMRenderer> CDRMRenderer::attempt(SP<CBackend> backend_, int drmFD) { SP<CDRMRenderer> renderer = SP<CDRMRenderer>(new CDRMRenderer()); renderer->drmFD = drmFD; renderer->backend = backend_; @@ -526,7 +589,7 @@ return nullptr; } - renderer->initContext(GLES2); + renderer->initContext(); if (renderer->egl.context == nullptr || renderer->egl.context == EGL_NO_CONTEXT) return nullptr; @@ -535,7 +598,7 @@ return renderer; } -SP<CDRMRenderer> CDRMRenderer::attempt(SP<CBackend> backend_, Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_, bool GLES2) { +SP<CDRMRenderer> CDRMRenderer::attempt(SP<CBackend> backend_, Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_) { SP<CDRMRenderer> renderer = SP<CDRMRenderer>(new CDRMRenderer()); renderer->drmFD = allocator_->drmFD(); renderer->backend = backend_; @@ -562,7 +625,7 @@ return nullptr; } - renderer->initContext(GLES2); + renderer->initContext(); if (renderer->egl.context == nullptr || renderer->egl.context == EGL_NO_CONTEXT) return nullptr; @@ -660,10 +723,10 @@ return image; } -SGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buffa) { - SGLTex tex; +CGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buffa) { + CGLTex tex; - const auto dma = buffa->dmabuf(); + const auto& dma = buffa->dmabuf(); tex.image = createEGLImage(dma); if (tex.image == EGL_NO_IMAGE_KHR) { @@ -685,11 +748,11 @@ GLCALL(glGenTextures(1, &tex.texid)); - GLCALL(glBindTexture(tex.target, tex.texid)); - GLCALL(glTexParameteri(tex.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLCALL(glTexParameteri(tex.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(tex.bind()); + GLCALL(tex.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(tex.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLCALL(proc.glEGLImageTargetTexture2DOES(tex.target, tex.image)); - GLCALL(glBindTexture(tex.target, 0)); + GLCALL(tex.unbind()); return tex; } @@ -700,11 +763,11 @@ CEglContextGuard eglContext(*this); auto att = buf->attachments.get<CDRMRendererBufferAttachment>(); if (!att) { - att = makeShared<CDRMRendererBufferAttachment>(self, buf, nullptr, 0, 0, SGLTex{}, std::vector<uint8_t>()); + att = makeShared<CDRMRendererBufferAttachment>(self, buf, nullptr, 0, 0, CGLTex{}, std::vector<uint8_t>()); buf->attachments.add(att); } - auto dma = buf->dmabuf(); + const auto& dma = buf->dmabuf(); if (!att->eglImage) { att->eglImage = createEGLImage(dma); if (att->eglImage == EGL_NO_IMAGE_KHR) { @@ -733,26 +796,19 @@ GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); } -inline const float fullVerts[] = { - 1, 0, // top right - 0, 0, // top left - 1, 1, // bottom right - 0, 1, // bottom left -}; - 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); + std::array<EGLint, 3> 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); + attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; + attribs[1] = dupFd; + attribs[2] = EGL_NONE; EGLSyncKHR sync = proc.eglCreateSyncKHR(egl.display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { @@ -819,7 +875,7 @@ void CDRMRenderer::clearBuffer(IBuffer* buf) { CEglContextGuard eglContext(*this); - auto dmabuf = buf->dmabuf(); + const auto& dmabuf = buf->dmabuf(); GLuint rboID = 0, fboID = 0; if (!dmabuf.success) { @@ -850,8 +906,6 @@ 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)); @@ -868,7 +922,7 @@ return {}; } - if (waitFD >= 0) { + if (waitFD >= 0 && !CFileDescriptor::isReadable(waitFD)) { // wait on a provided explicit fence waitOnSync(waitFD); } @@ -878,8 +932,8 @@ // both from and to have the same AQ_ATTACHMENT_DRM_RENDERER_DATA. // Those buffers always come from different swapchains, so it's OK. - SGLTex fromTex; - auto fromDma = from->dmabuf(); + WP<CGLTex> fromTex; + const auto& fromDma = from->dmabuf(); std::span<uint8_t> intermediateBuf; { auto attachment = from->attachments.get<CDRMRendererBufferAttachment>(); @@ -889,21 +943,22 @@ intermediateBuf = attachment->intermediateBuf; } - if (!fromTex.image && intermediateBuf.empty()) { + if ((!fromTex || !fromTex->image) && intermediateBuf.empty()) { backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in from, creating a new image"); - fromTex = glTex(from); - attachment = makeShared<CDRMRendererBufferAttachment>(self, from, nullptr, 0, 0, fromTex, std::vector<uint8_t>()); + attachment = makeShared<CDRMRendererBufferAttachment>(self, from, nullptr, 0, 0, glTex(from), std::vector<uint8_t>()); from->attachments.add(attachment); - if (!fromTex.image && primaryRenderer) { + if (!attachment->tex->image && primaryRenderer) { backend->log(AQ_LOG_DEBUG, "EGL (blit): Failed to create image from source buffer directly, allocating intermediate buffer"); static_assert(PIXEL_BUFFER_FORMAT == GL_RGBA); // If the pixel buffer format changes, the below size calculation probably needs to as well. attachment->intermediateBuf.resize(fromDma.size.x * fromDma.size.y * 4); - intermediateBuf = attachment->intermediateBuf; - fromTex.target = GL_TEXTURE_2D; - GLCALL(glGenTextures(1, &fromTex.texid)); + intermediateBuf = attachment->intermediateBuf; + attachment->tex->target = GL_TEXTURE_2D; + GLCALL(glGenTextures(1, &attachment->tex->texid)); } + + fromTex = attachment->tex; } if (!intermediateBuf.empty() && primaryRenderer) { @@ -913,15 +968,15 @@ } TRACE(backend->log(AQ_LOG_TRACE, - std::format("EGL (blit): fromTex id {}, image 0x{:x}, target {}", fromTex.texid, (uintptr_t)fromTex.image, - fromTex.target == GL_TEXTURE_2D ? "GL_TEXTURE_2D" : "GL_TEXTURE_EXTERNAL_OES"))); + std::format("EGL (blit): fromTex id {}, image 0x{:x}, target {}", fromTex->texid, (uintptr_t)fromTex->image, + fromTex->target == GL_TEXTURE_2D ? "GL_TEXTURE_2D" : "GL_TEXTURE_EXTERNAL_OES"))); // then, get a rbo from our to buffer // if it has an attachment, use that EGLImageKHR rboImage = nullptr; GLuint rboID = 0, fboID = 0; - auto toDma = to->dmabuf(); + const auto& toDma = to->dmabuf(); if (!verifyDestinationDMABUF(toDma)) { backend->log(AQ_LOG_ERROR, "EGL (blit): failed to blit: destination dmabuf unsupported"); @@ -960,12 +1015,10 @@ return {}; } - to->attachments.add(makeShared<CDRMRendererBufferAttachment>(self, to, rboImage, fboID, rboID, SGLTex{}, std::vector<uint8_t>())); + to->attachments.add(makeShared<CDRMRendererBufferAttachment>(self, to, rboImage, fboID, rboID, CGLTex{}, std::vector<uint8_t>())); } } - glFlush(); - TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): rboImage 0x{:x}", (uintptr_t)rboImage))); GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID)); @@ -986,7 +1039,7 @@ float monitorProj[9]; matrixIdentity(base); - auto& SHADER = fromTex.target == GL_TEXTURE_2D ? gl.shader : gl.shaderExt; + auto& SHADER = fromTex->target == GL_TEXTURE_2D ? shader : shaderExt; // KMS uses flipped y, we have to do FLIPPED_180 matrixTranslate(base, toDma.size.x / 2.0, toDma.size.y / 2.0); @@ -1000,18 +1053,21 @@ float glMtx[9]; matrixMultiply(glMtx, monitorProj, mtx); - GLCALL(glViewport(0, 0, toDma.size.x, toDma.size.y)); + static Vector2D lastViewportSize = {-1, -1}; + if (lastViewportSize != toDma.size) { + GLCALL(glViewport(0, 0, toDma.size.x, toDma.size.y)); + lastViewportSize = toDma.size; + } GLCALL(glActiveTexture(GL_TEXTURE0)); - GLCALL(glBindTexture(fromTex.target, fromTex.texid)); - - GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + GLCALL(fromTex->bind()); + GLCALL(fromTex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + GLCALL(fromTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST)); if (!intermediateBuf.empty()) - GLCALL(glTexImage2D(fromTex.target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf.data())); + GLCALL(glTexImage2D(fromTex->target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf.data())); - GLCALL(glUseProgram(SHADER.program)); + useProgram(SHADER.program); GLCALL(glDisable(GL_BLEND)); GLCALL(glDisable(GL_SCISSOR_TEST)); @@ -1019,22 +1075,12 @@ GLCALL(glUniformMatrix3fv(SHADER.proj, 1, GL_FALSE, glMtx)); GLCALL(glUniform1i(SHADER.tex, 0)); - - GLCALL(glVertexAttribPointer(SHADER.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts)); - GLCALL(glVertexAttribPointer(SHADER.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts)); - - GLCALL(glEnableVertexAttribArray(SHADER.posAttrib)); - GLCALL(glEnableVertexAttribArray(SHADER.texAttrib)); + GLCALL(glBindVertexArray(SHADER.shaderVao)); GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); - GLCALL(glDisableVertexAttribArray(SHADER.posAttrib)); - GLCALL(glDisableVertexAttribArray(SHADER.texAttrib)); - - GLCALL(glBindTexture(fromTex.target, 0)); - - // rendered, cleanup - glFlush(); + GLCALL(glBindVertexArray(0)); + GLCALL(fromTex->unbind()); // get an explicit sync fd for the secondary gpu. // when we pass buffers between gpus we should always use explicit sync, @@ -1053,16 +1099,16 @@ TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (onBufferAttachmentDrop): dropping fbo {} rbo {} image 0x{:x}", attachment->fbo, attachment->rbo, (uintptr_t)attachment->eglImage))); - if (attachment->tex.texid) - GLCALL(glDeleteTextures(1, &attachment->tex.texid)); + if (attachment->tex && attachment->tex->texid) + GLCALL(glDeleteTextures(1, &attachment->tex->texid)); if (attachment->rbo) GLCALL(glDeleteRenderbuffers(1, &attachment->rbo)); if (attachment->fbo) GLCALL(glDeleteFramebuffers(1, &attachment->fbo)); if (attachment->eglImage) proc.eglDestroyImageKHR(egl.display, attachment->eglImage); - if (attachment->tex.image) - proc.eglDestroyImageKHR(egl.display, attachment->tex.image); + if (attachment->tex && attachment->tex->image) + proc.eglDestroyImageKHR(egl.display, attachment->tex->image); } bool CDRMRenderer::verifyDestinationDMABUF(const SDMABUFAttrs& attrs) { @@ -1085,8 +1131,43 @@ return false; } +constexpr std::optional<size_t> CGLTex::getCacheStateIndex(GLenum pname) { + switch (pname) { + case GL_TEXTURE_WRAP_S: return TEXTURE_PAR_WRAP_S; + case GL_TEXTURE_WRAP_T: return TEXTURE_PAR_WRAP_T; + case GL_TEXTURE_MAG_FILTER: return TEXTURE_PAR_MAG_FILTER; + case GL_TEXTURE_MIN_FILTER: return TEXTURE_PAR_MIN_FILTER; + default: return std::nullopt; + } +} + +void CGLTex::bind() { + glBindTexture(target, texid); +} + +void CGLTex::unbind() { + glBindTexture(target, 0); +} + +void CGLTex::setTexParameter(GLenum pname, GLint param) { + const auto cacheIndex = getCacheStateIndex(pname); + + if (!cacheIndex) { + glTexParameteri(target, pname, param); + return; + } + + const auto idx = cacheIndex.value(); + + if (m_cachedStates[idx] == param) + return; + + m_cachedStates[idx] = param; + glTexParameteri(target, pname, param); +} + CDRMRendererBufferAttachment::CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer_, Hyprutils::Memory::CSharedPointer<IBuffer> buffer, - EGLImageKHR image, GLuint fbo_, GLuint rbo_, SGLTex tex_, std::vector<uint8_t> intermediateBuf_) : - eglImage(image), fbo(fbo_), rbo(rbo_), tex(tex_), intermediateBuf(intermediateBuf_), renderer(renderer_) { - bufferDestroy = buffer->events.destroy.registerListener([this](std::any d) { renderer->onBufferAttachmentDrop(this); }); + EGLImageKHR image, GLuint fbo_, GLuint rbo_, CGLTex&& tex_, std::vector<uint8_t> intermediateBuf_) : + eglImage(image), fbo(fbo_), rbo(rbo_), tex(makeUnique<CGLTex>(std::move(tex_))), intermediateBuf(intermediateBuf_), renderer(renderer_) { + bufferDestroy = buffer->events.destroy.listen([this] { renderer->onBufferAttachmentDrop(this); }); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/drm/Renderer.hpp new/aquamarine-0.9.1/src/backend/drm/Renderer.hpp --- old/aquamarine-0.8.0/src/backend/drm/Renderer.hpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/drm/Renderer.hpp 2025-07-07 17:58:11.000000000 +0200 @@ -4,7 +4,9 @@ #include "FormatUtils.hpp" #include <EGL/egl.h> #include <EGL/eglext.h> -#include <GLES2/gl2.h> +#include <GLES3/gl3.h> +#include <GLES3/gl3ext.h> +#define __gl2_h_ // define guard for gl2ext.h #include <GLES2/gl2ext.h> #include <gbm.h> #include <optional> @@ -16,23 +18,40 @@ class CGBMAllocator; - struct SGLTex { + class CGLTex { + public: + CGLTex() = default; + void bind(); + void unbind(); + void setTexParameter(GLenum pname, GLint param); EGLImage image = nullptr; GLuint texid = 0; GLuint target = GL_TEXTURE_2D; + + private: + enum eTextureParam : uint8_t { + TEXTURE_PAR_WRAP_S = 0, + TEXTURE_PAR_WRAP_T, + TEXTURE_PAR_MAG_FILTER, + TEXTURE_PAR_MIN_FILTER, + TEXTURE_PAR_LAST, + }; + + inline constexpr std::optional<size_t> getCacheStateIndex(GLenum pname); + std::array<std::optional<GLint>, TEXTURE_PAR_LAST> m_cachedStates; }; class CDRMRendererBufferAttachment : public IAttachment { public: CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer_, Hyprutils::Memory::CSharedPointer<IBuffer> buffer, EGLImageKHR image, GLuint fbo_, - GLuint rbo_, SGLTex tex, std::vector<uint8_t> intermediateBuf_); + GLuint rbo_, CGLTex&& tex, std::vector<uint8_t> intermediateBuf_); virtual ~CDRMRendererBufferAttachment() { ; } EGLImageKHR eglImage = nullptr; GLuint fbo = 0, rbo = 0; - SGLTex tex; + Hyprutils::Memory::CUniquePointer<CGLTex> tex; Hyprutils::Signal::CHyprSignalListener bufferDestroy; std::vector<uint8_t> intermediateBuf; @@ -66,9 +85,9 @@ public: ~CDRMRenderer(); - static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend_, int drmFD, bool GLES2 = true); + static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend_, int drmFD); static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(Hyprutils::Memory::CSharedPointer<CBackend> backend_, - Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_, bool GLES2 = true); + Hyprutils::Memory::CSharedPointer<CGBMAllocator> allocator_); int drmFD = -1; @@ -84,12 +103,14 @@ void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment); - struct { - struct SShader { - GLuint program = 0; - GLint proj = -1, tex = -1, posAttrib = -1, texAttrib = -1; - } shader, shaderExt; - } gl; + struct SShader { + ~SShader(); + void createVao(); + + GLuint program = 0; + GLint proj = -1, tex = -1, posAttrib = -1, texAttrib = -1; + GLuint shaderVao = 0, shaderVboPos = 0, shaderVboUv = 0; + } shader, shaderExt; struct { PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr; @@ -128,7 +149,7 @@ int lastBlitSyncFD = -1; } egl; - SGLTex glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buf); + CGLTex glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buf); void readBuffer(Hyprutils::Memory::CSharedPointer<IBuffer> buf, std::span<uint8_t> out); Hyprutils::Memory::CWeakPointer<CDRMRenderer> self; @@ -144,11 +165,13 @@ void loadEGLAPI(); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); - void initContext(bool GLES2); + void initContext(); void initResources(); bool initDRMFormats(); std::optional<std::vector<std::pair<uint64_t, bool>>> getModsForFormat(EGLint format); bool hasModifiers = false; + void useProgram(GLuint prog); + GLuint m_currentProgram = 0; Hyprutils::Memory::CWeakPointer<CBackend> backend; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/src/backend/drm/impl/Atomic.cpp new/aquamarine-0.9.1/src/backend/drm/impl/Atomic.cpp --- old/aquamarine-0.8.0/src/backend/drm/impl/Atomic.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/src/backend/drm/impl/Atomic.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -5,6 +5,7 @@ #include <xf86drm.h> #include <xf86drmMode.h> #include <sys/mman.h> +#include <sstream> #include "Shared.hpp" #include "aquamarine/output/Output.hpp" @@ -99,8 +100,19 @@ TRACE(backend->log(AQ_LOG_TRACE, std::format("atomic addConnector values: CRTC {}, mode {}", enable ? connector->crtc->id : 0, data.atomic.modeBlob))); conn = connector; + if (enable) { + drmModeModeInfo* currentMode = connector->getCurrentMode(); + bool modeDiffers = true; + if (currentMode) { + modeDiffers = memcmp(currentMode, &data.modeInfo, sizeof(drmModeModeInfo)) != 0; + free(currentMode); + } - addConnectorModeset(connector, data); + if (modeDiffers) + addConnectorModeset(connector, data); + } else + addConnectorModeset(connector, data); + addConnectorCursor(connector, data); add(connector->id, connector->props.crtc_id, enable ? connector->crtc->id : 0); @@ -180,7 +192,7 @@ const auto& STATE = connector->output->state->state(); const bool enable = STATE.enabled && data.mainFB; - add(connector->crtc->id, connector->crtc->props.mode_id, data.atomic.modeBlob); + add(connector->crtc->id, connector->crtc->props.mode_id, enable ? data.atomic.modeBlob : 0); data.atomic.blobbed = true; if (!enable) @@ -223,20 +235,20 @@ bool Aquamarine::CDRMAtomicRequest::commit(uint32_t flagssss) { static auto flagsToStr = [](uint32_t flags) { - std::string result; + std::ostringstream result; if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) - result += "ATOMIC_ALLOW_MODESET "; + result << "ATOMIC_ALLOW_MODESET "; if (flags & DRM_MODE_ATOMIC_NONBLOCK) - result += "ATOMIC_NONBLOCK "; + result << "ATOMIC_NONBLOCK "; if (flags & DRM_MODE_ATOMIC_TEST_ONLY) - result += "ATOMIC_TEST_ONLY "; + result << "ATOMIC_TEST_ONLY "; if (flags & DRM_MODE_PAGE_FLIP_EVENT) - result += "PAGE_FLIP_EVENT "; + result << "PAGE_FLIP_EVENT "; if (flags & DRM_MODE_PAGE_FLIP_ASYNC) - result += "PAGE_FLIP_ASYNC "; + result << "PAGE_FLIP_ASYNC "; if (flags & (~DRM_MODE_ATOMIC_FLAGS)) - result += " + invalid..."; - return result; + result << " + invalid..."; + return result.str(); }; if (failed) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aquamarine-0.8.0/tests/SimpleWindow.cpp new/aquamarine-0.9.1/tests/SimpleWindow.cpp --- old/aquamarine-0.8.0/tests/SimpleWindow.cpp 2025-03-16 23:00:48.000000000 +0100 +++ new/aquamarine-0.9.1/tests/SimpleWindow.cpp 2025-07-07 17:58:11.000000000 +0200 @@ -60,29 +60,23 @@ auto aqBackend = Aquamarine::CBackend::create(implementations, options); - newOutputListener = aqBackend->events.newOutput.registerListener([](std::any data) { - output = std::any_cast<SP<Aquamarine::IOutput>>(data); + newOutputListener = aqBackend->events.newOutput.listen([](const SP<Aquamarine::IOutput> newOutput) { + output = newOutput; std::cout << "[Client] Got a new output named " << output->name << "\n"; - outputFrameListener = output->events.frame.registerListener([](std::any data) { onFrame(); }); - outputStateListener = output->events.state.registerListener([](std::any data) { onState(std::any_cast<Aquamarine::IOutput::SStateEvent>(data)); }); + outputFrameListener = output->events.frame.listen([] { onFrame(); }); + outputStateListener = output->events.state.listen([](const Aquamarine::IOutput::SStateEvent& event) { onState(event); }); }); - newMouseListener = aqBackend->events.newPointer.registerListener([] (std::any pointer) { - auto p = std::any_cast<SP<Aquamarine::IPointer>>(pointer); - mouseMotionListener = p->events.warp.registerListener([] (std::any data) { - auto e = std::any_cast<Aquamarine::IPointer::SWarpEvent>(data); - std::cout << "[Client] Mouse warped to " << std::format("{}", e.absolute) << "\n"; - }); + newMouseListener = aqBackend->events.newPointer.listen([](const SP<Aquamarine::IPointer>& pointer) { + mouseMotionListener = pointer->events.warp.listen( + [](const Aquamarine::IPointer::SWarpEvent& event) { std::cout << "[Client] Mouse warped to " << std::format("{}", event.absolute) << "\n"; }); }); - newKeyboardListener = aqBackend->events.newKeyboard.registerListener([] (std::any keeb) { - auto k = std::any_cast<SP<Aquamarine::IKeyboard>>(keeb); - keyboardKeyListener = k->events.key.registerListener([] (std::any data) { - auto e = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(data); - std::cout << "[Client] Key " << std::format("{}", e.key) << " state: " << e.pressed << " \n"; - }); + newKeyboardListener = aqBackend->events.newKeyboard.listen([](const SP<Aquamarine::IKeyboard>& keyboard) { + keyboardKeyListener = keyboard->events.key.listen( + [](const Aquamarine::IKeyboard::SKeyEvent& event) { std::cout << "[Client] Key " << std::format("{}", event.key) << " state: " << event.pressed << " \n"; }); }); if (!aqBackend || !aqBackend->start()) { @@ -94,4 +88,4 @@ // aqBackend->enterLoop(); return 0; -} \ No newline at end of file +} ++++++ aquamarine.obsinfo ++++++ --- /var/tmp/diff_new_pack.Dz6X00/_old 2025-07-17 17:19:59.558816040 +0200 +++ /var/tmp/diff_new_pack.Dz6X00/_new 2025-07-17 17:19:59.558816040 +0200 @@ -1,5 +1,5 @@ name: aquamarine -version: 0.8.0 -mtime: 1742162448 -commit: 1c8fa0bf04d706698311cf595e80bbd6d3697956 +version: 0.9.1 +mtime: 1751903891 +commit: 664b2766bc624a62901b241fbdb19d0d0e790f38