diff --git a/.gitignore b/.gitignore index abd4567..ab8439a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ result *.swp -*.qcow2 \ No newline at end of file +*.qcow2 +.idea/ \ No newline at end of file diff --git a/README.md b/README.md index 3424b58..a68b959 100644 --- a/README.md +++ b/README.md @@ -10,31 +10,6 @@ nixos-rebuild switch --flake flake_path_directory#hostname nix flake update --extra-experimental-features "nix-command flakes" ``` -## Configure VM - -Configure VM -```nix -users.users.<user>.initialPassword = "<password>"; -virtualisation.vmVariant = { - # following configuration is added only when building VM with build-vm - virtualisation = { - memorySize = <RAM in MiB>; # Use 8192MiB memory. - cores = <CPU Core number>; - # And more here https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/virtualisation/qemu-vm.nix - }; -}; -``` - -Build -```bash -nixos-rebuild build-vm --flake .#nixos-test -``` - -Run -```bash -./result/bin/run-nixos-vm-vm -``` - ## Show changements between revisions @@ -72,36 +47,6 @@ error: cached failure of attribute 'nixosConfigurations.perso-desktop.config.sys sudo rm -fr /root/.cache/nix/ ``` -## If package is marked as insecure - -Example: - -> error: Package 'nix-2.16.2' in /nix/store/nra828scc8qs92b9pxra5csqzffb6hpl-source/pkgs/tools/package-management/nix/default.nix:229 is marked as insecure, refusing to evaluate. -> -> Known issues: -> - CVE-2024-27297 - -```bash -nix path-info -r /run/current-system | grep nix-2.16.2 -``` -Result: -> [...] -> -> /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 -> -> [...] - -```bash -nix-store -q --referrers /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 -``` -Result: -> /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 -> -> /nix/store/72pfc05339izcwqhlbs8441brrdasas7-nix-2.16.2-dev -> -> /nix/store/ln2z5d5izn8icm3wx94ci13ad19lzjhr-nixd-1.2.3 - -nixd is not up to date and require nix 2.16.2 ## To limit resources use during build diff --git a/flake.lock b/flake.lock index 326a4af..6726d62 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1716561646, - "narHash": "sha256-UIGtLO89RxKt7RF2iEgPikSdU53r6v/6WYB0RW3k89I=", + "lastModified": 1723293904, + "narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=", "owner": "ryantm", "repo": "agenix", - "rev": "c2fc0762bbe8feb06a2e59a364fa81b3a57671c9", + "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41", "type": "github" }, "original": { @@ -47,6 +47,203 @@ "type": "github" } }, + "doom-emacs": { + "flake": false, + "locked": { + "lastModified": 1662497747, + "narHash": "sha256-4n7E1fqda7cn5/F2jTkOnKw1juG6XMS/FI9gqODL3aU=", + "owner": "doomemacs", + "repo": "doomemacs", + "rev": "3853dff5e11655e858d0bfae64b70cb12ef685ac", + "type": "github" + }, + "original": { + "owner": "doomemacs", + "repo": "doomemacs", + "rev": "3853dff5e11655e858d0bfae64b70cb12ef685ac", + "type": "github" + } + }, + "doom-snippets": { + "flake": false, + "locked": { + "lastModified": 1694887483, + "narHash": "sha256-KlKhruPSLPSKqUnr5/U65arm16VrY9ORzm+XKNZhpTQ=", + "owner": "doomemacs", + "repo": "snippets", + "rev": "f022984ee1318a4015d5d081b3c3dab5a60dc6ff", + "type": "github" + }, + "original": { + "owner": "doomemacs", + "repo": "snippets", + "type": "github" + } + }, + "emacs-overlay": { + "flake": false, + "locked": { + "lastModified": 1676366521, + "narHash": "sha256-i4UAY8t9Au9SJtsgYppa3NHSVf1YkV6yqnNIQd+Km4g=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "c16be6de78ea878aedd0292aa5d4a1ee0a5da501", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "c16be6de78ea878aedd0292aa5d4a1ee0a5da501", + "type": "github" + } + }, + "emacs-so-long": { + "flake": false, + "locked": { + "lastModified": 1575031854, + "narHash": "sha256-xIa5zO0ZaToDrec1OFjBK6l39AbA4l/CE4LInVu2hi0=", + "owner": "hlissner", + "repo": "emacs-so-long", + "rev": "ed666b0716f60e8988c455804de24b55919e71ca", + "type": "github" + }, + "original": { + "owner": "hlissner", + "repo": "emacs-so-long", + "type": "github" + } + }, + "evil-escape": { + "flake": false, + "locked": { + "lastModified": 1588439096, + "narHash": "sha256-aB2Ge5o/93B18tPf4fN1c+O46CNh/nOqwLJbox4c8Gw=", + "owner": "hlissner", + "repo": "evil-escape", + "rev": "819f1ee1cf3f69a1ae920e6004f2c0baeebbe077", + "type": "github" + }, + "original": { + "owner": "hlissner", + "repo": "evil-escape", + "type": "github" + } + }, + "evil-markdown": { + "flake": false, + "locked": { + "lastModified": 1626852210, + "narHash": "sha256-HBBuZ1VWIn6kwK5CtGIvHM1+9eiNiKPH0GUsyvpUVN8=", + "owner": "Somelauw", + "repo": "evil-markdown", + "rev": "8e6cc68af83914b2fa9fd3a3b8472573dbcef477", + "type": "github" + }, + "original": { + "owner": "Somelauw", + "repo": "evil-markdown", + "type": "github" + } + }, + "evil-org-mode": { + "flake": false, + "locked": { + "lastModified": 1607203864, + "narHash": "sha256-JxwqVYDN6OIJEH15MVI6XOZAPtUWUhJQWHyzcrUvrFg=", + "owner": "hlissner", + "repo": "evil-org-mode", + "rev": "a9706da260c45b98601bcd72b1d2c0a24a017700", + "type": "github" + }, + "original": { + "owner": "hlissner", + "repo": "evil-org-mode", + "type": "github" + } + }, + "evil-quick-diff": { + "flake": false, + "locked": { + "lastModified": 1575189609, + "narHash": "sha256-oGzl1ayW9rIuq0haoiFS7RZsS8NFMdEA7K1BSozgnJU=", + "owner": "rgrinberg", + "repo": "evil-quick-diff", + "rev": "69c883720b30a892c63bc89f49d4f0e8b8028908", + "type": "github" + }, + "original": { + "owner": "rgrinberg", + "repo": "evil-quick-diff", + "type": "github" + } + }, + "explain-pause-mode": { + "flake": false, + "locked": { + "lastModified": 1595842060, + "narHash": "sha256-++znrjiDSx+cy4okFBBXUBkRFdtnE2x+trkmqjB3Njs=", + "owner": "lastquestion", + "repo": "explain-pause-mode", + "rev": "2356c8c3639cbeeb9751744dbe737267849b4b51", + "type": "github" + }, + "original": { + "owner": "lastquestion", + "repo": "explain-pause-mode", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "format-all": { + "flake": false, + "locked": { + "lastModified": 1581716637, + "narHash": "sha256-ul7LCe60W8TIvUmUtZtZRo8489TK9iTPDsLHmzxY57M=", + "owner": "lassik", + "repo": "emacs-format-all-the-code", + "rev": "47d862d40a088ca089c92cd393c6dca4628f87d3", + "type": "github" + }, + "original": { + "owner": "lassik", + "repo": "emacs-format-all-the-code", + "rev": "47d862d40a088ca089c92cd393c6dca4628f87d3", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -54,11 +251,11 @@ ] }, "locked": { - "lastModified": 1716736760, - "narHash": "sha256-h3RmnNknKYtVA+EvUSra6QAwfZjC2q1G8YA7W0gat8Y=", + "lastModified": 1726036828, + "narHash": "sha256-ZQHbpyti0jcAKnwQY1lwmooecLmSG6wX1JakQ/eZNeM=", "owner": "nix-community", "repo": "home-manager", - "rev": "5d151429e1e79107acf6d06dcc5ace4e642ec239", + "rev": "8a1671642826633586d12ac3158e463c7a50a112", "type": "github" }, "original": { @@ -67,6 +264,52 @@ "type": "github" } }, + "nix-doom-emacs": { + "inputs": { + "doom-emacs": "doom-emacs", + "doom-snippets": "doom-snippets", + "emacs-overlay": "emacs-overlay", + "emacs-so-long": "emacs-so-long", + "evil-escape": "evil-escape", + "evil-markdown": "evil-markdown", + "evil-org-mode": "evil-org-mode", + "evil-quick-diff": "evil-quick-diff", + "explain-pause-mode": "explain-pause-mode", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "format-all": "format-all", + "nix-straight": [ + "nix-straight" + ], + "nixpkgs": [ + "nixpkgs" + ], + "nose": "nose", + "ob-racket": "ob-racket", + "org": "org", + "org-contrib": "org-contrib", + "org-yt": "org-yt", + "php-extras": "php-extras", + "revealjs": "revealjs", + "rotate-text": "rotate-text", + "sln-mode": "sln-mode", + "ts-fold": "ts-fold", + "ws-butler": "ws-butler" + }, + "locked": { + "lastModified": 1701264882, + "narHash": "sha256-MBXR7x7Ua8qystlGr+lenwjQd7dsFNFpEFmtHhh10zM=", + "owner": "nix-community", + "repo": "nix-doom-emacs", + "rev": "f7413022370f24bb53cb450bfb2803233510113e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-doom-emacs", + "type": "github" + } + }, "nix-flatpak": { "locked": { "lastModified": 1711997201, @@ -83,13 +326,30 @@ "type": "github" } }, + "nix-straight": { + "flake": false, + "locked": { + "lastModified": 1696948727, + "narHash": "sha256-6fQamWVIyeLoFSJl1WKcIl+LUdZluzFla4H+4Z5Cv2E=", + "owner": "codingkoi", + "repo": "nix-straight.el", + "rev": "c64edbf49598453bd85dae1acef9a0f9d294185d", + "type": "github" + }, + "original": { + "owner": "codingkoi", + "ref": "codingkoi/apply-librephoenixs-fix", + "repo": "nix-straight.el", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1716509168, - "narHash": "sha256-4zSIhSRRIoEBwjbPm3YiGtbd8HDWzFxJjw5DYSDy1n8=", + "lastModified": 1725983898, + "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "bfb7a882678e518398ce9a31a881538679f6f092", + "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", "type": "github" }, "original": { @@ -99,12 +359,174 @@ "type": "github" } }, + "nose": { + "flake": false, + "locked": { + "lastModified": 1400604510, + "narHash": "sha256-daEi8Kta1oGaDEmUUDDQMahTTPOpvNpDKk22rlr7cB0=", + "owner": "emacsattic", + "repo": "nose", + "rev": "f8528297519eba911696c4e68fa88892de9a7b72", + "type": "github" + }, + "original": { + "owner": "emacsattic", + "repo": "nose", + "type": "github" + } + }, + "nur": { + "locked": { + "lastModified": 1726059953, + "narHash": "sha256-uuqSnIgC2g3W6wk6Of1HvOFgFvo5Q+h0469VwMzDaBI=", + "owner": "nix-community", + "repo": "NUR", + "rev": "72296d37a29541a017e545c8f4e2c5c37dbaba59", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "ob-racket": { + "flake": false, + "locked": { + "lastModified": 1584656173, + "narHash": "sha256-rBUYDDCXb+3D4xTPQo9UocbTPZ32kWV1Uya/1DmZknU=", + "owner": "xchrishawk", + "repo": "ob-racket", + "rev": "83457ec9e1e96a29fd2086ed19432b9d75787673", + "type": "github" + }, + "original": { + "owner": "xchrishawk", + "repo": "ob-racket", + "type": "github" + } + }, + "org": { + "flake": false, + "locked": { + "lastModified": 1695726851, + "narHash": "sha256-qgbjspklSoI8M3cbCJOcUdjuijRgsL/+PSyEOW9VX4I=", + "owner": "emacs-straight", + "repo": "org-mode", + "rev": "aa9177e1a8b039c357d369c1c9aaab710bb247a9", + "type": "github" + }, + "original": { + "owner": "emacs-straight", + "repo": "org-mode", + "type": "github" + } + }, + "org-contrib": { + "flake": false, + "locked": { + "lastModified": 1694946041, + "narHash": "sha256-X/HFG6NZe5BY00KvGbcsIuf9R6Lg8x7Uhd0Y5+Q3qZU=", + "owner": "emacsmirror", + "repo": "org-contrib", + "rev": "5eabbf22bdd4523c922a30787e98ee66c24221aa", + "type": "github" + }, + "original": { + "owner": "emacsmirror", + "repo": "org-contrib", + "type": "github" + } + }, + "org-yt": { + "flake": false, + "locked": { + "lastModified": 1527381913, + "narHash": "sha256-dzQ6B7ryzatHCTLyEnRSbWO0VUiX/FHYnpHTs74aVUs=", + "owner": "TobiasZawada", + "repo": "org-yt", + "rev": "40cc1ac76d741055cbefa13860d9f070a7ade001", + "type": "github" + }, + "original": { + "owner": "TobiasZawada", + "repo": "org-yt", + "type": "github" + } + }, + "php-extras": { + "flake": false, + "locked": { + "lastModified": 1573312690, + "narHash": "sha256-r4WyVbzvT0ra4Z6JywNBOw5RxOEYd6Qe2IpebHXkj1U=", + "owner": "arnested", + "repo": "php-extras", + "rev": "d410c5af663c30c01d461ac476d1cbfbacb49367", + "type": "github" + }, + "original": { + "owner": "arnested", + "repo": "php-extras", + "type": "github" + } + }, + "revealjs": { + "flake": false, + "locked": { + "lastModified": 1695738029, + "narHash": "sha256-Z9c9Q41jMkj/DyXOiZYyIa7Gmn8VB8yauTyWrSsT+ps=", + "owner": "hakimel", + "repo": "reveal.js", + "rev": "88fbfc5751ad01e3f6adee5819eabeb9e73c3757", + "type": "github" + }, + "original": { + "owner": "hakimel", + "repo": "reveal.js", + "type": "github" + } + }, "root": { "inputs": { "agenix": "agenix", "home-manager": "home-manager", + "nix-doom-emacs": "nix-doom-emacs", "nix-flatpak": "nix-flatpak", - "nixpkgs": "nixpkgs" + "nix-straight": "nix-straight", + "nixpkgs": "nixpkgs", + "nur": "nur" + } + }, + "rotate-text": { + "flake": false, + "locked": { + "lastModified": 1322962747, + "narHash": "sha256-SOeOgSlcEIsKhUiYDJv0p+mLUb420s9E2BmvZQvZ0wk=", + "owner": "debug-ito", + "repo": "rotate-text.el", + "rev": "48f193697db996855aee1ad2bc99b38c6646fe76", + "type": "github" + }, + "original": { + "owner": "debug-ito", + "repo": "rotate-text.el", + "type": "github" + } + }, + "sln-mode": { + "flake": false, + "locked": { + "lastModified": 1423727528, + "narHash": "sha256-XqkqPyEJuTtFslOz1fpTf/Klbd/zA7IGpzpmum/MGao=", + "owner": "sensorflo", + "repo": "sln-mode", + "rev": "0f91d1b957c7d2a7bab9278ec57b54d57f1dbd9c", + "type": "github" + }, + "original": { + "owner": "sensorflo", + "repo": "sln-mode", + "type": "github" } }, "systems": { @@ -121,6 +543,53 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "ts-fold": { + "flake": false, + "locked": { + "lastModified": 1695278494, + "narHash": "sha256-O4NcUC1u08W8ZslqoA/i+iTaLotKwheURXQWBxLLMFc=", + "owner": "jcs-elpa", + "repo": "ts-fold", + "rev": "70b2c79ff4daa7351d4e2917b0343b9a18d4d4f2", + "type": "github" + }, + "original": { + "owner": "jcs-elpa", + "repo": "ts-fold", + "type": "github" + } + }, + "ws-butler": { + "flake": false, + "locked": { + "lastModified": 1634511126, + "narHash": "sha256-c0y0ZPtxxICPk+eaNbbQf6t+FRCliNY54CCz9QHQ8ZI=", + "owner": "hlissner", + "repo": "ws-butler", + "rev": "572a10c11b6cb88293de48acbb59a059d36f9ba5", + "type": "github" + }, + "original": { + "owner": "hlissner", + "repo": "ws-butler", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8eb11a3..5ec27f8 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,7 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nur.url = github:nix-community/NUR; home-manager = { url = "github:nix-community/home-manager"; @@ -16,13 +17,30 @@ }; nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=v0.4.1"; + + # Follow nix-doom-emacs completely when this is merged or fixed + # - https://github.com/nix-community/nix-doom-emacs/issues/409 + # - https://github.com/nix-community/nix-straight.el/pull/4 + nix-straight = { + url = "github:codingkoi/nix-straight.el?ref=codingkoi/apply-librephoenixs-fix"; + flake = false; + }; + nix-doom-emacs = { + url = "github:nix-community/nix-doom-emacs"; + inputs = { + nix-straight.follows = "nix-straight"; + nixpkgs.follows = "nixpkgs"; + }; + }; }; outputs = inputs@{ nixpkgs, + nur, home-manager, agenix, nix-flatpak, + nix-doom-emacs, ... }: let @@ -41,12 +59,15 @@ ./hosts/${s.name}/configuration.nix home-manager.nixosModules.home-manager agenix.nixosModules.default + { nixpkgs.overlays = [ nur.overlay ]; } { home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; home-manager.extraSpecialArgs = inputs; home-manager.users.florian.imports = [ nix-flatpak.homeManagerModules.nix-flatpak + nix-doom-emacs.hmModule + ./hosts/${s.name}/home.nix ]; } diff --git a/hosts/nixos-test/home.nix b/hosts/nixos-test/home.nix index 0aafc57..6dcf755 100644 --- a/hosts/nixos-test/home.nix +++ b/hosts/nixos-test/home.nix @@ -13,10 +13,6 @@ kitty.enable = true; }; - editors = { - vscode.enable = true; - }; - shell = { zsh.enable = true; atuin.enable = true; diff --git a/hosts/perso-desktop/configuration.nix b/hosts/perso-desktop/configuration.nix index 43e5e9a..8a538d4 100644 --- a/hosts/perso-desktop/configuration.nix +++ b/hosts/perso-desktop/configuration.nix @@ -20,6 +20,10 @@ networking.hostName = "nixos-desktop-perso"; # Define your hostname. modules.system = { + apps = { + steam.enable = true; + }; + desktop = { plasma.enable = true; }; @@ -34,5 +38,9 @@ printing.enable = true; waydroid.enable = true; }; + + server = { + distrobox.enable = true; + }; }; } diff --git a/hosts/perso-desktop/home.nix b/hosts/perso-desktop/home.nix index 0aafc57..48642dc 100644 --- a/hosts/perso-desktop/home.nix +++ b/hosts/perso-desktop/home.nix @@ -8,15 +8,12 @@ modules.home = { apps = { chromium.enable = true; + firefox.enable = true; flatpak.enable = true; jetbrainsToolbox.enable = true; kitty.enable = true; }; - editors = { - vscode.enable = true; - }; - shell = { zsh.enable = true; atuin.enable = true; diff --git a/hosts/perso-laptop/home.nix b/hosts/perso-laptop/home.nix index 0aafc57..6dcf755 100644 --- a/hosts/perso-laptop/home.nix +++ b/hosts/perso-laptop/home.nix @@ -13,10 +13,6 @@ kitty.enable = true; }; - editors = { - vscode.enable = true; - }; - shell = { zsh.enable = true; atuin.enable = true; diff --git a/hosts/pro-laptop/configuration.nix b/hosts/pro-laptop/configuration.nix index 4a0eec2..3c57635 100644 --- a/hosts/pro-laptop/configuration.nix +++ b/hosts/pro-laptop/configuration.nix @@ -19,18 +19,18 @@ networking.hostName = "nixos-laptop-pro"; # Define your hostname. - hardware.nvidia.prime = { - offload = { - enable = true; - enableOffloadCmd = true; - }; - - # Make sure to use the correct Bus ID values for your system! - # information bus: pci@0000:00:02.0 - intelBusId = "PCI:0:2:0"; - # information bus: pci@0000:01:00.0 - nvidiaBusId = "PCI:1:0:0"; - }; +# hardware.nvidia.prime = { +# offload = { +# enable = true; +# enableOffloadCmd = true; +# }; +# +# # Make sure to use the correct Bus ID values for your system! +# # information bus: pci@0000:00:02.0 +# intelBusId = "PCI:0:2:0"; +# # information bus: pci@0000:01:00.0 +# nvidiaBusId = "PCI:1:0:0"; +# }; modules.system = { desktop = { @@ -47,5 +47,9 @@ printing.enable = true; waydroid.enable = true; }; + + server = { + distrobox.enable = true; + }; }; } diff --git a/hosts/pro-laptop/home.nix b/hosts/pro-laptop/home.nix index 0aafc57..48642dc 100644 --- a/hosts/pro-laptop/home.nix +++ b/hosts/pro-laptop/home.nix @@ -8,15 +8,12 @@ modules.home = { apps = { chromium.enable = true; + firefox.enable = true; flatpak.enable = true; jetbrainsToolbox.enable = true; kitty.enable = true; }; - editors = { - vscode.enable = true; - }; - shell = { zsh.enable = true; atuin.enable = true; diff --git a/modules/common.nix b/modules/common.nix new file mode 100644 index 0000000..c7eb3e6 --- /dev/null +++ b/modules/common.nix @@ -0,0 +1,5 @@ +{ ... }: + +{ + nix.settings.experimental-features = [ "nix-command" "flakes" ]; +} \ No newline at end of file diff --git a/modules/home/apps/default.nix b/modules/home/apps/default.nix index 888257b..5f6f130 100644 --- a/modules/home/apps/default.nix +++ b/modules/home/apps/default.nix @@ -1,10 +1,11 @@ -{ config, pkgs, ... }: +{ ... }: { imports = [ ./chromium + ./firefox ./flatpak ./jetbrainsToolbox ./kitty ]; -} \ No newline at end of file +} diff --git a/modules/home/apps/firefox/default.nix b/modules/home/apps/firefox/default.nix new file mode 100644 index 0000000..4ea8d76 --- /dev/null +++ b/modules/home/apps/firefox/default.nix @@ -0,0 +1,44 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.home.apps.firefox; +in +{ + options.modules.home.apps.firefox = { + enable = mkEnableOption '' + Enable firefox with my custom configurations + ''; + }; + config = mkIf cfg.enable { + programs.firefox = { + enable = true; + + nativeMessagingHosts = [ + pkgs.kdePackages.plasma-browser-integration + ]; + + profiles = { + perso = { + id = 0; + + name = "Perso"; + + extensions = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + bitwarden + floccus + plasma-integration + istilldontcareaboutcookies + darkreader + ]; + + settings = { + # Enable multi-pip + "media.videocontrols.picture-in-picture.allow-multiple" = true; + }; + }; + }; + }; + }; +} diff --git a/modules/home/apps/flatpak/default.nix b/modules/home/apps/flatpak/default.nix index 052f6b0..4c05680 100644 --- a/modules/home/apps/flatpak/default.nix +++ b/modules/home/apps/flatpak/default.nix @@ -12,7 +12,6 @@ in }; config = mkIf cfg.enable { - services.flatpak = { enable = true; @@ -21,22 +20,15 @@ in packages = [ # Gaming { appId = "com.discordapp.Discord"; origin = "flathub"; } - { appId = "com.valvesoftware.Steam"; origin = "flathub"; } { appId = "net.lutris.Lutris"; origin = "flathub"; } # Pro - { appId = "com.slack.Slack"; origin = "flathub"; } - { appId = "com.skype.Client"; origin = "flathub"; } - { appId = "org.mozilla.Thunderbird"; origin = "flathub"; } { appId = "ch.protonmail.protonmail-bridge"; origin = "flathub"; } { appId = "org.kde.neochat"; origin = "flathub"; } # Loisir { appId = "com.spotify.Client"; origin = "flathub"; } - { appId = "io.gitlab.news_flash.NewsFlash"; origin = "flathub"; } { appId = "org.videolan.VLC"; origin = "flathub"; } - { appId = "com.obsproject.Studio"; origin = "flathub"; } - { appId = "io.github.achetagames.epic_asset_manager"; origin = "flathub"; } ]; }; }; diff --git a/modules/home/apps/jetbrainsToolbox/default.nix b/modules/home/apps/jetbrainsToolbox/default.nix index c79f09f..c495cc2 100644 --- a/modules/home/apps/jetbrainsToolbox/default.nix +++ b/modules/home/apps/jetbrainsToolbox/default.nix @@ -11,6 +11,6 @@ in ''; }; config = mkIf cfg.enable { - home.packages = with pkgs; [jetbrains-toolbox]; + home.packages = with pkgs; [jetbrains-toolbox graalvm-ce]; }; } \ No newline at end of file diff --git a/modules/home/default.nix b/modules/home/default.nix index 6d528ce..adfece8 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -2,6 +2,7 @@ { imports = [ + ../common.nix ./apps ./editors ./desktop @@ -16,6 +17,5 @@ }; programs.home-manager.enable = true; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; } diff --git a/modules/home/editors/default.nix b/modules/home/editors/default.nix index 40db812..f265d2c 100644 --- a/modules/home/editors/default.nix +++ b/modules/home/editors/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./emacs ./vscode ]; } \ No newline at end of file diff --git a/modules/home/editors/emacs/default.nix b/modules/home/editors/emacs/default.nix new file mode 100644 index 0000000..5a70616 --- /dev/null +++ b/modules/home/editors/emacs/default.nix @@ -0,0 +1,19 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.home.editors.emacs; +in +{ + options.modules.home.editors.emacs = { + enable = mkEnableOption '' + Enable emacs with my custom configurations + ''; + }; + config = mkIf cfg.enable { + programs.doom-emacs = { + enable = true; + doomPrivateDir = ./doom.d; + }; + }; +} \ No newline at end of file diff --git a/modules/home/editors/emacs/doom.d/config.el b/modules/home/editors/emacs/doom.d/config.el new file mode 100644 index 0000000..576a6e5 --- /dev/null +++ b/modules/home/editors/emacs/doom.d/config.el @@ -0,0 +1,76 @@ +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;; Place your private configuration here! Remember, you do not need to run 'doom +;; sync' after modifying this file! + + +;; Some functionality uses this to identify you, e.g. GPG configuration, email +;; clients, file templates and snippets. It is optional. +;; (setq user-full-name "John Doe" +;; user-mail-address "john@doe.com") + +;; Doom exposes five (optional) variables for controlling fonts in Doom: +;; +;; - `doom-font' -- the primary font to use +;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable) +;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for +;; presentations or streaming. +;; - `doom-symbol-font' -- for symbols +;; - `doom-serif-font' -- for the `fixed-pitch-serif' face +;; +;; See 'C-h v doom-font' for documentation and more examples of what they +;; accept. For example: +;; +;; (setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light) +;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13)) +;; +;; If you or Emacs can't find your font, use 'M-x describe-font' to look them +;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to +;; refresh your font settings. If Emacs still can't find your font, it likely +;; wasn't installed correctly. Font issues are rarely Doom issues! + +;; There are two ways to load a theme. Both assume the theme is installed and +;; available. You can either set `doom-theme' or manually load a theme with the +;; `load-theme' function. This is the default: +(setq doom-theme 'doom-one) + +;; This determines the style of line numbers in effect. If set to `nil', line +;; numbers are disabled. For relative line numbers, set this to `relative'. +(setq display-line-numbers-type t) + +;; If you use `org' and don't want your org files in the default location below, +;; change `org-directory'. It must be set before org loads! +(setq org-directory "~/org/") + + +;; Whenever you reconfigure a package, make sure to wrap your config in an +;; `after!' block, otherwise Doom's defaults may override your settings. E.g. +;; +;; (after! PACKAGE +;; (setq x y)) +;; +;; The exceptions to this rule: +;; +;; - Setting file/directory variables (like `org-directory') +;; - Setting variables which explicitly tell you to set them before their +;; package is loaded (see 'C-h v VARIABLE' to look up their documentation). +;; - Setting doom variables (which start with 'doom-' or '+'). +;; +;; Here are some additional functions/macros that will help you configure Doom. +;; +;; - `load!' for loading external *.el files relative to this one +;; - `use-package!' for configuring packages +;; - `after!' for running code after a package has loaded +;; - `add-load-path!' for adding directories to the `load-path', relative to +;; this file. Emacs searches the `load-path' when you load packages with +;; `require' or `use-package'. +;; - `map!' for binding new keys +;; +;; To get information about any of these functions/macros, move the cursor over +;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k'). +;; This will open documentation for it, including demos of how they are used. +;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces, +;; etc). +;; +;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how +;; they are implemented. \ No newline at end of file diff --git a/modules/home/editors/emacs/doom.d/init.el b/modules/home/editors/emacs/doom.d/init.el new file mode 100644 index 0000000..aa00999 --- /dev/null +++ b/modules/home/editors/emacs/doom.d/init.el @@ -0,0 +1,195 @@ +;;; init.el -*- lexical-binding: t; -*- + +;; This file controls what Doom modules are enabled and what order they load +;; in. Remember to run 'doom sync' after modifying it! + +;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's +;; documentation. There you'll find a link to Doom's Module Index where all +;; of our modules are listed, including what flags they support. + +;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or +;; 'C-c c k' for non-vim users) to view its documentation. This works on +;; flags as well (those symbols that start with a plus). +;; +;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its +;; directory (for easy access to its source code). + +(doom! :input + ;;bidi ; (tfel ot) thgir etirw uoy gnipleh + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ;;ivy ; a search engine for love and life + vertico ; the search engine of the future + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + ;;doom-quit ; DOOM quit-message prompts when you quit Emacs + (emoji +unicode) ; 🙂 + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + ;;indent-guides ; highlighted indent columns + ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + nav-flash ; blink cursor line after big motions + ;;neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults) ; tame sudden yet inevitable temporary windows + tabs ; a tab bar for Emacs + (treemacs +lsp) ; a project drawer, like neotree but cooler + ;;unicode ; extended unicode support for various languages + (vc-gutter +pretty) ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + ;;window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + ;;zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + ;;(format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + ;;word-wrap ; soft wrapping with language-aware indent + + :emacs + dired ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + (ibuffer +icons) ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + eshell ; the elisp shell that works everywhere + ;;shell ; simple shell REPL for Emacs + ;;term ; basic terminal emulator for Emacs + ;;vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + ;;(spell +flyspell) ; tasing you for misspelling mispelling + ;;grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + ;;biblio ; Writes a PhD for you (citation needed) + ;;collab ; buffers with friends + (debugger +lsp) ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + lsp ; M-x vscode + magit ; a git porcelain for Emacs + ;;make ; run make tasks from Emacs + ;;pass ; password manager for nerds + ;;pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + tree-sitter ; syntax and parsing, sitting in a tree... + ;;upload ; map local to remote projects via ssh/ftp + + :os + (:if IS-MAC macos) ; improve compatibility with macOS + ;;tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + (cc +lsp) ; C > C++ == 1 + ;;cloju + ;;common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + ;;data ; config/data formats + (dart +flutter +lsp) ; paint ui and not much else + ;;dhall + (elixir +lsp) ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;factor + ;;faust ; dsp, but you get to keep your soul + ;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER) + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + ;;gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + ;;(graphql +lsp) ; Give queries a REST + ;;(haskell +lsp) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; a language you can depend on + json ; At least it ain't XML + (java +lsp) ; the poster child for carpal tunnel syndrome + ;;javascript ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + (kotlin +lsp) ; a better, slicker Java(Script) + ;;latex ; writing papers in Emacs has never been so fun + ;;lean ; for folks with too much to prove + ;;ledger ; be audit you can be + ;;lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + ;;nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + org ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + ;;python ; beautiful is better than ugly + (qt +lsp +xp) ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + (ruby +lsp +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + (rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + ;;web ; the tubes + yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + ;;(mu4e +org +gmail) + ;;notmuch + ;;(wanderlust +gmail) + + :app + ;;calendar + ;;emms + ;;everywhere ; *leave* Emacs!? You must be joking + ;;irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) \ No newline at end of file diff --git a/modules/home/editors/emacs/doom.d/packages.el b/modules/home/editors/emacs/doom.d/packages.el new file mode 100644 index 0000000..be08796 --- /dev/null +++ b/modules/home/editors/emacs/doom.d/packages.el @@ -0,0 +1,52 @@ +;; -*- no-byte-compile: t; -*- +;;; $DOOMDIR/packages.el + +;; To install a package with Doom you must declare them here and run 'doom sync' +;; on the command line, then restart Emacs for the changes to take effect -- or +;; use 'M-x doom/reload'. + + +;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: +;(package! some-package) + +;; To install a package directly from a remote git repo, you must specify a +;; `:recipe'. You'll find documentation on what `:recipe' accepts here: +;; https://github.com/radian-software/straight.el#the-recipe-format +;(package! another-package +; :recipe (:host github :repo "username/repo")) + +;; If the package you are trying to install does not contain a PACKAGENAME.el +;; file, or is located in a subdirectory of the repo, you'll need to specify +;; `:files' in the `:recipe': +;(package! this-package +; :recipe (:host github :repo "username/repo" +; :files ("some-file.el" "src/lisp/*.el"))) + +;; If you'd like to disable a package included with Doom, you can do so here +;; with the `:disable' property: +;(package! builtin-package :disable t) + +;; You can override the recipe of a built in package without having to specify +;; all the properties for `:recipe'. These will inherit the rest of its recipe +;; from Doom or MELPA/ELPA/Emacsmirror: +;(package! builtin-package :recipe (:nonrecursive t)) +;(package! builtin-package-2 :recipe (:repo "myfork/package")) + +;; Specify a `:branch' to install a package from a particular branch or tag. +;; This is required for some packages whose default branch isn't 'master' (which +;; our package manager can't deal with; see radian-software/straight.el#279) +;(package! builtin-package :recipe (:branch "develop")) + +;; Use `:pin' to specify a particular commit to install. +;(package! builtin-package :pin "1a2b3c4d5e") + + +;; Doom's packages are pinned to a specific commit and updated from release to +;; release. The `unpin!' macro allows you to unpin single packages... +;(unpin! pinned-package) +;; ...or multiple packages +;(unpin! pinned-package another-pinned-package) +;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) +;(unpin! t) + +(package! ripgrep) \ No newline at end of file diff --git a/modules/home/editors/vscode/default.nix b/modules/home/editors/vscode/default.nix index 13ed250..14cd380 100644 --- a/modules/home/editors/vscode/default.nix +++ b/modules/home/editors/vscode/default.nix @@ -26,6 +26,7 @@ in userTasks = {}; + # Waiting https://github.com/nix-community/home-manager/pull/5640 to support multi-profiles support extensions = with pkgs; with vscode-extensions; [ # Nix bbenoist.nix diff --git a/modules/home/shell/git/default.nix b/modules/home/shell/git/default.nix index ad50961..e6eb7b1 100644 --- a/modules/home/shell/git/default.nix +++ b/modules/home/shell/git/default.nix @@ -13,10 +13,20 @@ in config = mkIf cfg.enable { programs.git = { enable = true; + lfs.enable = true; + userName = "Florian RICHER"; userEmail = "florian.richer@protonmail.com"; - # signing.signByDefault = true; + signing = { + signByDefault = true; + key = "B19E3F4A2D806AB4793FDF2FC73D37CBED7BFC77"; + }; + + extraConfig = { + url."https://invent.kde.org/".insteadOf = "kde:"; + url."ssh://git@invent.kde.org/".pushInsteadOf = "kde:"; + }; }; }; -} \ No newline at end of file +} diff --git a/modules/system/apps/default.nix b/modules/system/apps/default.nix new file mode 100644 index 0000000..557c5f2 --- /dev/null +++ b/modules/system/apps/default.nix @@ -0,0 +1,7 @@ +{ ... }: + +{ + imports = [ + ./steam + ]; +} diff --git a/modules/system/apps/steam/default.nix b/modules/system/apps/steam/default.nix new file mode 100644 index 0000000..448421c --- /dev/null +++ b/modules/system/apps/steam/default.nix @@ -0,0 +1,22 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.system.apps.steam; +in +{ + options.modules.system.apps.steam = { + enable = mkEnableOption '' + Enable steam with my custom configurations + ''; + }; + config = mkIf cfg.enable { + programs.steam = { + enable = true; + extraPackages = with pkgs; [ gamescope ]; + extraCompatPackages = with pkgs; [ proton-ge-bin ]; + }; + + hardware.steam-hardware.enable = true; + }; +} diff --git a/modules/system/common.nix b/modules/system/common.nix index 43cc570..5838226 100644 --- a/modules/system/common.nix +++ b/modules/system/common.nix @@ -1,6 +1,10 @@ { pkgs, ... }: { + imports = [ + ../common.nix + ]; + # Set your time zone. time.timeZone = "Europe/Paris"; @@ -21,13 +25,39 @@ nixpkgs.config.allowUnfree = true; + services.udev.packages = [ pkgs.yubikey-personalization ]; + services.pcscd.enable = true; + + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + # List packages installed in system profile. To search, run: # $ nix search wget environment.systemPackages = with pkgs; [ vim nixd + + # Usefull tools to debug + gdb + lldb + gammaray # QT Inspector + + yubikey-manager + + # Usefull for automatic informations collect software like KDE + vulkan-tools # For vulkaninfo command + wayland-utils # For wayland-info command + glxinfo + clinfo + aha + usbutils + pciutils ]; + services.fwupd.enable = true; + # Define a user account. Don't forget to set a password with ‘passwd’. users.users.florian = { isNormalUser = true; @@ -37,6 +67,10 @@ services.flatpak.enable = true; # Important can't be enabled from home-manager + # Downloads and provides debug symbols and source code for nix derivations to gdb and other debuginfod-capable debuggers as needed. + # Require https://github.com/symphorien/nixseparatedebuginfod?tab=readme-ov-file#gdb + services.nixseparatedebuginfod.enable = true; + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. # Configure network proxy if necessary diff --git a/modules/system/default.nix b/modules/system/default.nix index 49a302c..08983d8 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./apps ./desktop ./hardware ./server diff --git a/modules/system/desktop/plasma/default.nix b/modules/system/desktop/plasma/default.nix index b0387fe..261b54f 100644 --- a/modules/system/desktop/plasma/default.nix +++ b/modules/system/desktop/plasma/default.nix @@ -26,17 +26,6 @@ in environment.systemPackages = with pkgs; with kdePackages; [ krfb # Use by kdeconnect for virtualmonitorplugin "krfb-virtualmonitor" discover - - # Usefull for automatic informations collect software like KDE - vulkan-tools # For vulkaninfo command - wayland-utils # For wayland-info command - glxinfo - clinfo - ]; - - # Uncomment when kwin is available in nixpkgs and NVIDIA 555 - nixpkgs.overlays = [ - (import ../../../../overlays/kwin) ]; }; -} \ No newline at end of file +} diff --git a/modules/system/hardware/nvidia/default.nix b/modules/system/hardware/nvidia/default.nix index fa6625a..f58b698 100644 --- a/modules/system/hardware/nvidia/default.nix +++ b/modules/system/hardware/nvidia/default.nix @@ -11,41 +11,51 @@ in ''; }; config = mkIf cfg.enable { - # Enable OpenGL - hardware.opengl = { - enable = true; - driSupport = true; - driSupport32Bit = true; - }; - # Load nvidia driver for Xorg and Wayland services.xserver.videoDrivers = ["nvidia"]; - hardware.nvidia = { - # Modesetting is required. - modesetting.enable = true; + hardware = { + graphics = { + enable = true; + enable32Bit = true; + }; - # Nvidia power management. Experimental, and can cause sleep/suspend to fail. - powerManagement.enable = false; - # Fine-grained power management. Turns off GPU when not in use. - # Experimental and only works on modern Nvidia GPUs (Turing or newer). - powerManagement.finegrained = false; + nvidia-container-toolkit.enable = true; - # Use the NVidia open source kernel module (not to be confused with the - # independent third-party "nouveau" open source driver). - # Support is limited to the Turing and later architectures. Full list of - # supported GPUs is at: - # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus - # Only available from driver 515.43.04+ - # Currently alpha-quality/buggy, so false is currently the recommended setting. - open = false; + nvidia = { + # Modesetting is required. + modesetting.enable = true; - # Enable the Nvidia settings menu, - # accessible via `nvidia-settings`. - nvidiaSettings = true; + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement.enable = true; - # Optionally, you may need to select the appropriate driver version for your specific GPU. - package = config.boot.kernelPackages.nvidiaPackages.beta; + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # Currently alpha-quality/buggy, so false is currently the recommended setting. + open = true; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + package = config.boot.kernelPackages.nvidiaPackages.latest; + }; }; + + # boot.extraModprobeConfig = '' + # options nvidia NVreg_EnableGpuFirmware=0 + # ''; }; -} \ No newline at end of file +} diff --git a/modules/system/hardware/pipewire/default.nix b/modules/system/hardware/pipewire/default.nix index 1f46de4..75a6a5e 100644 --- a/modules/system/hardware/pipewire/default.nix +++ b/modules/system/hardware/pipewire/default.nix @@ -12,7 +12,6 @@ in }; config = mkIf cfg.enable { # Enable sound with pipewire. - sound.enable = true; hardware.pulseaudio.enable = false; security.rtkit.enable = true; services.pipewire = { @@ -28,4 +27,4 @@ in #media-session.enable = true; }; }; -} \ No newline at end of file +} diff --git a/modules/system/server/default.nix b/modules/system/server/default.nix index d75b7fd..7533a63 100644 --- a/modules/system/server/default.nix +++ b/modules/system/server/default.nix @@ -2,7 +2,9 @@ { imports = [ + ./distrobox ./docker + ./ollama ./openssh ]; } \ No newline at end of file diff --git a/modules/system/server/distrobox/default.nix b/modules/system/server/distrobox/default.nix new file mode 100644 index 0000000..fec6131 --- /dev/null +++ b/modules/system/server/distrobox/default.nix @@ -0,0 +1,17 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.system.server.distrobox; +in +{ + options.modules.system.server.distrobox = { + enable = mkEnableOption '' + Enable distrobox with my custom configurations + ''; + }; + config = mkIf cfg.enable { + modules.system.server.docker.enable = true; + environment.systemPackages = with pkgs; [ distrobox ]; + }; +} \ No newline at end of file diff --git a/modules/system/server/docker/default.nix b/modules/system/server/docker/default.nix index 39c121a..dfdd13b 100644 --- a/modules/system/server/docker/default.nix +++ b/modules/system/server/docker/default.nix @@ -13,7 +13,8 @@ in config = mkIf cfg.enable { virtualisation.docker = { enable = true; - enableNvidia = config.modules.system.hardware.nvidia.enable; }; + + users.users.florian.extraGroups = [ "docker" ]; }; } \ No newline at end of file diff --git a/modules/system/server/ollama/default.nix b/modules/system/server/ollama/default.nix new file mode 100644 index 0000000..79e1a6c --- /dev/null +++ b/modules/system/server/ollama/default.nix @@ -0,0 +1,21 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.system.server.ollama; + nvidiaEnabled = config.modules.system.hardware.nvidia.enable; +in +{ + options.modules.system.server.ollama = { + enable = mkEnableOption '' + Enable ollama with my custom configurations + ''; + }; + config = mkIf cfg.enable { + services.ollama = { + enable = true; + + acceleration = if nvidiaEnabled then "cuda" else null; + }; + }; +} diff --git a/overlays/.gitkeep b/overlays/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/overlays/kwin/5511.patch b/overlays/kwin/5511.patch deleted file mode 100644 index 341dc2e..0000000 --- a/overlays/kwin/5511.patch +++ /dev/null @@ -1,2027 +0,0 @@ -From e1791de663807bc93c09418481cb844c7daeb8f7 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl <xaver.hugl@gmail.com> -Date: Wed, 22 Nov 2023 19:51:24 +0100 -Subject: [PATCH 1/5] wayland: implement linux-drm-syncobj-v1 - -linux-drm-syncobj-v1 allows drivers and apps to synchronize KWin's buffer access -to their rendering, and synchronize their rendering to KWin's buffer release. This -fixes severe glitches with the proprietary NVidia driver and allows for some -performance improvements with Mesa too. - -(cherry picked from commit 32addf4d599135678a5120470bc27a881f34a3d9) ---- - src/CMakeLists.txt | 1 + - src/backends/drm/drm_egl_backend.cpp | 16 ++ - src/backends/drm/drm_egl_backend.h | 3 + - src/backends/drm/drm_gpu.cpp | 8 + - src/backends/drm/drm_gpu.h | 2 + - src/compositor_wayland.cpp | 2 +- - src/core/graphicsbuffer.cpp | 6 + - src/core/graphicsbuffer.h | 8 + - src/core/renderbackend.cpp | 11 + - src/core/renderbackend.h | 5 + - src/core/syncobjtimeline.cpp | 83 ++++++ - src/core/syncobjtimeline.h | 72 +++++ - src/opengl/eglnativefence.cpp | 5 + - src/opengl/eglnativefence.h | 1 + - .../scenes/opengl/abstract_egl_backend.cpp | 5 + - .../scenes/opengl/abstract_egl_backend.h | 2 +- - .../scenes/opengl/openglbackend.cpp | 4 + - .../scenes/opengl/openglbackend.h | 3 + - src/scene/item.h | 1 + - src/scene/itemrenderer_opengl.cpp | 20 +- - src/scene/itemrenderer_opengl.h | 9 +- - src/scene/surfaceitem.cpp | 5 + - src/scene/surfaceitem.h | 3 + - src/scene/surfaceitem_wayland.cpp | 6 + - src/scene/surfaceitem_wayland.h | 1 + - src/scene/workspacescene_opengl.cpp | 2 +- - src/wayland/CMakeLists.txt | 8 + - src/wayland/linux_drm_syncobj_v1.cpp | 190 +++++++++++++ - src/wayland/linux_drm_syncobj_v1.h | 63 +++++ - src/wayland/linux_drm_syncobj_v1_p.h | 32 +++ - .../protocols/linux-drm-syncobj-v1.xml | 261 ++++++++++++++++++ - src/wayland/surface.cpp | 20 ++ - src/wayland/surface.h | 8 + - src/wayland/surface_p.h | 9 + - src/wayland/transaction.cpp | 27 +- - src/wayland/transaction_p.h | 15 + - src/wayland_server.cpp | 17 ++ - src/wayland_server.h | 7 + - 38 files changed, 935 insertions(+), 6 deletions(-) - create mode 100644 src/core/syncobjtimeline.cpp - create mode 100644 src/core/syncobjtimeline.h - create mode 100644 src/wayland/linux_drm_syncobj_v1.cpp - create mode 100644 src/wayland/linux_drm_syncobj_v1.h - create mode 100644 src/wayland/linux_drm_syncobj_v1_p.h - create mode 100644 src/wayland/protocols/linux-drm-syncobj-v1.xml - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 4e0db4fe9a9..0130caf3b8e 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -73,6 +73,7 @@ target_sources(kwin PRIVATE - core/session_logind.cpp - core/session_noop.cpp - core/shmgraphicsbufferallocator.cpp -+ core/syncobjtimeline.cpp - cursor.cpp - cursorsource.cpp - dbusinterface.cpp -diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp -index cfb7a482a03..943407e1d9b 100644 ---- a/src/backends/drm/drm_egl_backend.cpp -+++ b/src/backends/drm/drm_egl_backend.cpp -@@ -9,6 +9,7 @@ - #include "drm_egl_backend.h" - #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" - // kwin -+#include "core/syncobjtimeline.h" - #include "drm_abstract_output.h" - #include "drm_backend.h" - #include "drm_egl_cursor_layer.h" -@@ -199,6 +200,21 @@ DrmGpu *EglGbmBackend::gpu() const - return m_backend->primaryGpu(); - } - -+bool EglGbmBackend::supportsTimelines() const -+{ -+ return m_backend->primaryGpu()->syncObjTimelinesSupported(); -+} -+ -+std::unique_ptr<SyncTimeline> EglGbmBackend::importTimeline(FileDescriptor &&syncObjFd) -+{ -+ uint32_t handle = 0; -+ if (drmSyncobjFDToHandle(m_backend->primaryGpu()->fd(), syncObjFd.get(), &handle) != 0) { -+ qCWarning(KWIN_DRM) << "importing syncobj timeline failed!" << strerror(errno); -+ return nullptr; -+ } -+ return std::make_unique<SyncTimeline>(m_backend->primaryGpu()->fd(), handle); -+} -+ - } // namespace KWin - - #include "moc_drm_egl_backend.cpp" -diff --git a/src/backends/drm/drm_egl_backend.h b/src/backends/drm/drm_egl_backend.h -index 43c431f07be..4a47e900cd3 100644 ---- a/src/backends/drm/drm_egl_backend.h -+++ b/src/backends/drm/drm_egl_backend.h -@@ -63,6 +63,9 @@ public: - EglDisplay *displayForGpu(DrmGpu *gpu); - std::shared_ptr<EglContext> contextForGpu(DrmGpu *gpu); - -+ bool supportsTimelines() const override; -+ std::unique_ptr<SyncTimeline> importTimeline(FileDescriptor &&syncObjFd) override; -+ - private: - bool initializeEgl(); - bool initRenderingContext(); -diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp -index c5d258a2d7c..7141ed8beac 100644 ---- a/src/backends/drm/drm_gpu.cpp -+++ b/src/backends/drm/drm_gpu.cpp -@@ -76,6 +76,9 @@ DrmGpu::DrmGpu(DrmBackend *backend, const QString &devNode, int fd, dev_t device - m_addFB2ModifiersSupported = drmGetCap(fd, DRM_CAP_ADDFB2_MODIFIERS, &capability) == 0 && capability == 1; - qCDebug(KWIN_DRM) << "drmModeAddFB2WithModifiers is" << (m_addFB2ModifiersSupported ? "supported" : "not supported") << "on GPU" << m_devNode; - -+ m_supportsSyncTimelines = drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE, &capability) == 0 && capability == 1; -+ qCDebug(KWIN_DRM) << "sync obj timelines are" << (m_supportsSyncTimelines ? "supported" : "not supported") << "on GPU" << this; -+ - // find out what driver this kms device is using - DrmUniquePtr<drmVersion> version(drmGetVersion(fd)); - m_isI915 = strstr(version->name, "i915"); -@@ -699,6 +702,11 @@ bool DrmGpu::asyncPageflipSupported() const - return m_asyncPageflipSupported; - } - -+bool DrmGpu::syncObjTimelinesSupported() const -+{ -+ return m_supportsSyncTimelines; -+} -+ - bool DrmGpu::isI915() const - { - return m_isI915; -diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h -index 0cc6b2126a3..c8dbde47af7 100644 ---- a/src/backends/drm/drm_gpu.h -+++ b/src/backends/drm/drm_gpu.h -@@ -77,6 +77,7 @@ public: - bool atomicModeSetting() const; - bool addFB2ModifiersSupported() const; - bool asyncPageflipSupported() const; -+ bool syncObjTimelinesSupported() const; - bool isI915() const; - bool isNVidia() const; - bool isVmwgfx() const; -@@ -146,6 +147,7 @@ private: - bool m_isRemoved = false; - bool m_isActive = true; - bool m_forceModeset = false; -+ bool m_supportsSyncTimelines = false; - clockid_t m_presentationClock; - gbm_device *m_gbmDevice; - FileDescriptor m_gbmFd; -diff --git a/src/compositor_wayland.cpp b/src/compositor_wayland.cpp -index f63ead77964..69916e9d348 100644 ---- a/src/compositor_wayland.cpp -+++ b/src/compositor_wayland.cpp -@@ -86,7 +86,7 @@ bool WaylandCompositor::attemptOpenGLCompositing() - } - - m_scene = std::make_unique<WorkspaceSceneOpenGL>(backend.get()); -- m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererOpenGL>()); -+ m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererOpenGL>(backend->eglDisplayObject())); - m_backend = std::move(backend); - - qCDebug(KWIN_CORE) << "OpenGL compositing has been successfully initialized"; -diff --git a/src/core/graphicsbuffer.cpp b/src/core/graphicsbuffer.cpp -index f234d09fa9f..e83fcd7bf8a 100644 ---- a/src/core/graphicsbuffer.cpp -+++ b/src/core/graphicsbuffer.cpp -@@ -40,6 +40,7 @@ void GraphicsBuffer::unref() - if (m_dropped) { - delete this; - } else { -+ m_releasePoints.clear(); - Q_EMIT released(); - } - } -@@ -73,6 +74,11 @@ const ShmAttributes *GraphicsBuffer::shmAttributes() const - return nullptr; - } - -+void GraphicsBuffer::addReleasePoint(const std::shared_ptr<SyncReleasePoint> &releasePoint) -+{ -+ m_releasePoints.push_back(releasePoint); -+} -+ - bool GraphicsBuffer::alphaChannelFromDrmFormat(uint32_t format) - { - const auto info = FormatInfo::get(format); -diff --git a/src/core/graphicsbuffer.h b/src/core/graphicsbuffer.h -index cacf49dde5a..2e046e58de0 100644 ---- a/src/core/graphicsbuffer.h -+++ b/src/core/graphicsbuffer.h -@@ -16,6 +16,8 @@ - namespace KWin - { - -+class SyncReleasePoint; -+ - struct DmaBufAttributes - { - int planeCount = 0; -@@ -87,6 +89,11 @@ public: - virtual const DmaBufAttributes *dmabufAttributes() const; - virtual const ShmAttributes *shmAttributes() const; - -+ /** -+ * the added release point will be referenced as long as this buffer is referenced -+ */ -+ void addReleasePoint(const std::shared_ptr<SyncReleasePoint> &releasePoint); -+ - static bool alphaChannelFromDrmFormat(uint32_t format); - - Q_SIGNALS: -@@ -95,6 +102,7 @@ Q_SIGNALS: - protected: - int m_refCount = 0; - bool m_dropped = false; -+ std::vector<std::shared_ptr<SyncReleasePoint>> m_releasePoints; - }; - - /** -diff --git a/src/core/renderbackend.cpp b/src/core/renderbackend.cpp -index 98276385cec..5bbf37d9a4b 100644 ---- a/src/core/renderbackend.cpp -+++ b/src/core/renderbackend.cpp -@@ -7,6 +7,7 @@ - #include "renderbackend.h" - #include "renderloop_p.h" - #include "scene/surfaceitem.h" -+#include "syncobjtimeline.h" - - #include <drm_fourcc.h> - -@@ -103,6 +104,16 @@ std::unique_ptr<SurfaceTexture> RenderBackend::createSurfaceTextureWayland(Surfa - return nullptr; - } - -+bool RenderBackend::supportsTimelines() const -+{ -+ return false; -+} -+ -+std::unique_ptr<SyncTimeline> RenderBackend::importTimeline(FileDescriptor &&syncObjFd) -+{ -+ return nullptr; -+} -+ - } // namespace KWin - - #include "moc_renderbackend.cpp" -diff --git a/src/core/renderbackend.h b/src/core/renderbackend.h -index b902a28984a..682e35aa0b8 100644 ---- a/src/core/renderbackend.h -+++ b/src/core/renderbackend.h -@@ -8,6 +8,7 @@ - - #include "core/rendertarget.h" - #include "effect/globals.h" -+#include "utils/filedescriptor.h" - - #include <QObject> - -@@ -26,6 +27,7 @@ class SurfacePixmapX11; - class SurfaceTexture; - class PresentationFeedback; - class RenderLoop; -+class SyncTimeline; - - class PresentationFeedback - { -@@ -88,6 +90,9 @@ public: - - virtual std::unique_ptr<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *pixmap); - virtual std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmap *pixmap); -+ -+ virtual bool supportsTimelines() const; -+ virtual std::unique_ptr<SyncTimeline> importTimeline(FileDescriptor &&syncObjFd); - }; - - } // namespace KWin -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -new file mode 100644 -index 00000000000..3e2c100370a ---- /dev/null -+++ b/src/core/syncobjtimeline.cpp -@@ -0,0 +1,83 @@ -+/* -+ SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#include "syncobjtimeline.h" -+ -+#include <sys/eventfd.h> -+#include <xf86drm.h> -+ -+namespace KWin -+{ -+ -+SyncReleasePoint::SyncReleasePoint(const std::shared_ptr<SyncTimeline> &timeline, uint64_t timelinePoint) -+ : m_timeline(timeline) -+ , m_timelinePoint(timelinePoint) -+{ -+} -+ -+SyncReleasePoint::~SyncReleasePoint() -+{ -+ m_timeline->signal(m_timelinePoint); -+} -+ -+SyncTimeline *SyncReleasePoint::timeline() const -+{ -+ return m_timeline.get(); -+} -+ -+uint64_t SyncReleasePoint::timelinePoint() const -+{ -+ return m_timelinePoint; -+} -+ -+SyncTimeline::SyncTimeline(int drmFd, uint32_t handle) -+ : m_drmFd(drmFd) -+ , m_handle(handle) -+{ -+} -+ -+SyncTimeline::~SyncTimeline() -+{ -+ drmSyncobjDestroy(m_drmFd, m_handle); -+} -+ -+FileDescriptor SyncTimeline::eventFd(uint64_t timelinePoint) const -+{ -+ FileDescriptor ret{eventfd(0, EFD_CLOEXEC)}; -+ if (!ret.isValid()) { -+ return {}; -+ } -+ struct drm_syncobj_eventfd args -+ { -+ .handle = m_handle, -+ .flags = 0, -+ .point = timelinePoint, -+ .fd = ret.get(), -+ }; -+ if (drmIoctl(m_drmFd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args) != 0) { -+ return {}; -+ } -+ return ret; -+} -+ -+void SyncTimeline::signal(uint64_t timelinePoint) -+{ -+ drmSyncobjTimelineSignal(m_drmFd, &m_handle, &timelinePoint, 1); -+} -+ -+SyncReleasePointHolder::SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints) -+ : m_fence(std::move(requirement)) -+ , m_notifier(m_fence.get(), QSocketNotifier::Type::Read) -+ , m_releasePoints(std::move(releasePoints)) -+{ -+ connect(&m_notifier, &QSocketNotifier::activated, this, &SyncReleasePointHolder::signaled); -+ m_notifier.setEnabled(true); -+} -+ -+void SyncReleasePointHolder::signaled() -+{ -+ delete this; -+} -+} -diff --git a/src/core/syncobjtimeline.h b/src/core/syncobjtimeline.h -new file mode 100644 -index 00000000000..cffdb75e330 ---- /dev/null -+++ b/src/core/syncobjtimeline.h -@@ -0,0 +1,72 @@ -+/* -+ SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+#include "kwin_export.h" -+#include "utils/filedescriptor.h" -+ -+#include <QObject> -+#include <QSocketNotifier> -+#include <memory> -+#include <stdint.h> -+#include <unordered_set> -+ -+namespace KWin -+{ -+ -+class SyncTimeline; -+ -+/** -+ * A helper to signal the release point when it goes out of scope -+ */ -+class KWIN_EXPORT SyncReleasePoint -+{ -+public: -+ explicit SyncReleasePoint(const std::shared_ptr<SyncTimeline> &timeline, uint64_t timelinePoint); -+ ~SyncReleasePoint(); -+ -+ SyncTimeline *timeline() const; -+ uint64_t timelinePoint() const; -+ -+private: -+ const std::shared_ptr<SyncTimeline> m_timeline; -+ const uint64_t m_timelinePoint; -+}; -+ -+class KWIN_EXPORT SyncTimeline -+{ -+public: -+ explicit SyncTimeline(int drmFd, uint32_t handle); -+ ~SyncTimeline(); -+ -+ /** -+ * @returns an event fd that gets signalled when the timeline point gets signalled -+ */ -+ FileDescriptor eventFd(uint64_t timelinePoint) const; -+ -+ void signal(uint64_t timelinePoint); -+ -+private: -+ const int32_t m_drmFd; -+ const uint32_t m_handle; -+}; -+ -+class SyncReleasePointHolder : public QObject -+{ -+ Q_OBJECT -+public: -+ /** -+ * @param requirement the filedescriptor that needs to be readable before the release points may be signalled. Once that's happened, this object deletes itself!' -+ */ -+ explicit SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints); -+ -+private: -+ void signaled(); -+ -+ const FileDescriptor m_fence; -+ QSocketNotifier m_notifier; -+ const std::unordered_set<std::shared_ptr<SyncReleasePoint>> m_releasePoints; -+}; -+} -diff --git a/src/opengl/eglnativefence.cpp b/src/opengl/eglnativefence.cpp -index e68098bc768..13c42ade543 100644 ---- a/src/opengl/eglnativefence.cpp -+++ b/src/opengl/eglnativefence.cpp -@@ -51,6 +51,11 @@ const FileDescriptor &EGLNativeFence::fileDescriptor() const - return m_fileDescriptor; - } - -+FileDescriptor &&EGLNativeFence::fileDescriptor() -+{ -+ return std::move(m_fileDescriptor); -+} -+ - bool EGLNativeFence::waitSync() const - { - return eglWaitSync(m_display->handle(), m_sync, 0) == EGL_TRUE; -diff --git a/src/opengl/eglnativefence.h b/src/opengl/eglnativefence.h -index d5f6bdbbba2..05c248ff8e0 100644 ---- a/src/opengl/eglnativefence.h -+++ b/src/opengl/eglnativefence.h -@@ -27,6 +27,7 @@ public: - - bool isValid() const; - const FileDescriptor &fileDescriptor() const; -+ FileDescriptor &&fileDescriptor(); - bool waitSync() const; - - static EGLNativeFence importFence(EglDisplay *display, FileDescriptor &&fd); -diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -index 4e227aef462..4ad2064148b 100644 ---- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -+++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -@@ -13,6 +13,7 @@ - #include "opengl/egl_context_attribute_builder.h" - #include "utils/common.h" - #include "wayland/drmclientbuffer.h" -+#include "wayland/linux_drm_syncobj_v1.h" - #include "wayland_server.h" - // kwin libs - #include "opengl/eglimagetexture.h" -@@ -217,9 +218,13 @@ void AbstractEglBackend::initWayland() - .formatTable = includeShaderConversions(filterFormats({}, true)), - }); - -+ waylandServer()->setRenderBackend(this); - LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf(); - dmabuf->setRenderBackend(this); - dmabuf->setSupportedFormatsWithModifiers(m_tranches); -+ if (auto syncObj = waylandServer()->linuxSyncObj()) { -+ syncObj->setRenderBackend(this); -+ } - } - - void AbstractEglBackend::initClientExtensions() -diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h -index 0abd331ed6b..1f77898db50 100644 ---- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h -+++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h -@@ -34,7 +34,7 @@ public: - - EGLSurface surface() const; - EGLConfig config() const; -- EglDisplay *eglDisplayObject() const; -+ EglDisplay *eglDisplayObject() const override; - EglContext *contextObject(); - - bool testImportBuffer(GraphicsBuffer *buffer) override; -diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp -index 92ca501d96e..0bb6de64021 100644 ---- a/src/platformsupport/scenes/opengl/openglbackend.cpp -+++ b/src/platformsupport/scenes/opengl/openglbackend.cpp -@@ -93,6 +93,10 @@ bool OpenGLBackend::checkGraphicsReset() - return true; - } - -+EglDisplay *OpenGLBackend::eglDisplayObject() const -+{ -+ return nullptr; -+} - } - - #include "moc_openglbackend.cpp" -diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h -index 3318f4da187..e0749561826 100644 ---- a/src/platformsupport/scenes/opengl/openglbackend.h -+++ b/src/platformsupport/scenes/opengl/openglbackend.h -@@ -19,6 +19,7 @@ namespace KWin - class Output; - class OpenGLBackend; - class GLTexture; -+class EglDisplay; - - /** - * @brief The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap. -@@ -97,6 +98,8 @@ public: - - virtual std::pair<std::shared_ptr<GLTexture>, ColorDescription> textureForOutput(Output *output) const; - -+ virtual EglDisplay *eglDisplayObject() const; -+ - protected: - /** - * @brief Sets the backend initialization to failed. -diff --git a/src/scene/item.h b/src/scene/item.h -index 5e9e4f1c92a..b77fc91c64b 100644 ---- a/src/scene/item.h -+++ b/src/scene/item.h -@@ -22,6 +22,7 @@ namespace KWin - - class SceneDelegate; - class Scene; -+class SyncReleasePoint; - - /** - * The Item class is the base class for items in the scene. -diff --git a/src/scene/itemrenderer_opengl.cpp b/src/scene/itemrenderer_opengl.cpp -index 44ec0918e33..3fee3863f2c 100644 ---- a/src/scene/itemrenderer_opengl.cpp -+++ b/src/scene/itemrenderer_opengl.cpp -@@ -8,7 +8,9 @@ - #include "core/pixelgrid.h" - #include "core/rendertarget.h" - #include "core/renderviewport.h" -+#include "core/syncobjtimeline.h" - #include "effect/effect.h" -+#include "opengl/eglnativefence.h" - #include "platformsupport/scenes/opengl/openglsurfacetexture.h" - #include "scene/decorationitem.h" - #include "scene/imageitem.h" -@@ -20,7 +22,8 @@ - namespace KWin - { - --ItemRendererOpenGL::ItemRendererOpenGL() -+ItemRendererOpenGL::ItemRendererOpenGL(EglDisplay *eglDisplay) -+ : m_eglDisplay(eglDisplay) - { - const QString visualizeOptionsString = qEnvironmentVariable("KWIN_SCENE_VISUALIZE"); - if (!visualizeOptionsString.isEmpty()) { -@@ -46,6 +49,14 @@ void ItemRendererOpenGL::endFrame() - { - GLVertexBuffer::streamingBuffer()->endOfFrame(); - GLFramebuffer::popFramebuffer(); -+ -+ if (m_eglDisplay) { -+ EGLNativeFence fence(m_eglDisplay); -+ if (fence.isValid()) { -+ new SyncReleasePointHolder(std::move(fence.fileDescriptor()), std::move(m_releasePoints)); -+ } -+ } -+ m_releasePoints.clear(); - } - - QVector4D ItemRendererOpenGL::modulate(float opacity, float brightness) const -@@ -173,6 +184,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = UnnormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } else if (auto decorationItem = qobject_cast<DecorationItem *>(item)) { -@@ -187,6 +199,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = UnnormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } else if (auto surfaceItem = qobject_cast<SurfaceItem *>(item)) { -@@ -202,6 +215,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = NormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = surfaceItem->bufferReleasePoint(), - }); - } - } -@@ -216,6 +230,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = NormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } -@@ -407,6 +422,9 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend - contents.planes[plane]->unbind(); - } - } -+ if (renderNode.bufferReleasePoint) { -+ m_releasePoints.insert(renderNode.bufferReleasePoint); -+ } - } - if (shader) { - ShaderManager::instance()->popShader(); -diff --git a/src/scene/itemrenderer_opengl.h b/src/scene/itemrenderer_opengl.h -index c35839335c6..11ab8cea386 100644 ---- a/src/scene/itemrenderer_opengl.h -+++ b/src/scene/itemrenderer_opengl.h -@@ -10,9 +10,13 @@ - #include "platformsupport/scenes/opengl/openglsurfacetexture.h" - #include "scene/itemrenderer.h" - -+#include <unordered_set> -+ - namespace KWin - { - -+class EglDisplay; -+ - class KWIN_EXPORT ItemRendererOpenGL : public ItemRenderer - { - public: -@@ -28,6 +32,7 @@ public: - TextureCoordinateType coordinateType = UnnormalizedCoordinates; - qreal scale = 1.0; - ColorDescription colorDescription; -+ std::shared_ptr<SyncReleasePoint> bufferReleasePoint; - }; - - struct RenderContext -@@ -41,7 +46,7 @@ public: - const qreal renderTargetScale; - }; - -- ItemRendererOpenGL(); -+ ItemRendererOpenGL(EglDisplay *eglDisplay); - - void beginFrame(const RenderTarget &renderTarget, const RenderViewport &viewport) override; - void endFrame() override; -@@ -58,6 +63,8 @@ private: - void visualizeFractional(const RenderViewport &viewport, const QRegion ®ion, const RenderContext &renderContext); - - bool m_blendingEnabled = false; -+ EglDisplay *const m_eglDisplay; -+ std::unordered_set<std::shared_ptr<SyncReleasePoint>> m_releasePoints; - - struct - { -diff --git a/src/scene/surfaceitem.cpp b/src/scene/surfaceitem.cpp -index 4404dbc3c6c..f04053f3566 100644 ---- a/src/scene/surfaceitem.cpp -+++ b/src/scene/surfaceitem.cpp -@@ -270,6 +270,11 @@ std::chrono::nanoseconds SurfaceItem::frameTimeEstimation() const - } - } - -+std::shared_ptr<SyncReleasePoint> SurfaceItem::bufferReleasePoint() const -+{ -+ return m_bufferReleasePoint; -+} -+ - SurfaceTexture::~SurfaceTexture() - { - } -diff --git a/src/scene/surfaceitem.h b/src/scene/surfaceitem.h -index 5dfcfd0ad16..f6c8ca5d56d 100644 ---- a/src/scene/surfaceitem.h -+++ b/src/scene/surfaceitem.h -@@ -38,6 +38,8 @@ public: - QSize bufferSize() const; - void setBufferSize(const QSize &size); - -+ std::shared_ptr<SyncReleasePoint> bufferReleasePoint() const; -+ - QRegion mapFromBuffer(const QRegion ®ion) const; - - void addDamage(const QRegion ®ion); -@@ -82,6 +84,7 @@ protected: - std::deque<std::chrono::nanoseconds> m_lastDamageTimeDiffs; - std::optional<std::chrono::steady_clock::time_point> m_lastDamage; - std::chrono::nanoseconds m_frameTimeEstimation = std::chrono::days(1000); -+ std::shared_ptr<SyncReleasePoint> m_bufferReleasePoint; - }; - - class KWIN_EXPORT SurfaceTexture -diff --git a/src/scene/surfaceitem_wayland.cpp b/src/scene/surfaceitem_wayland.cpp -index 82863c3a456..6f16c47142f 100644 ---- a/src/scene/surfaceitem_wayland.cpp -+++ b/src/scene/surfaceitem_wayland.cpp -@@ -41,6 +41,7 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Scene *scene, - this, &SurfaceItemWayland::handleColorDescriptionChanged); - connect(surface, &SurfaceInterface::presentationModeHintChanged, - this, &SurfaceItemWayland::handlePresentationModeHintChanged); -+ connect(surface, &SurfaceInterface::bufferReleasePointChanged, this, &SurfaceItemWayland::handleReleasePointChanged); - - SubSurfaceInterface *subsurface = surface->subSurface(); - if (subsurface) { -@@ -184,6 +185,11 @@ void SurfaceItemWayland::handlePresentationModeHintChanged() - setPresentationHint(m_surface->presentationModeHint()); - } - -+void SurfaceItemWayland::handleReleasePointChanged() -+{ -+ m_bufferReleasePoint = m_surface->bufferReleasePoint(); -+} -+ - SurfacePixmapWayland::SurfacePixmapWayland(SurfaceItemWayland *item, QObject *parent) - : SurfacePixmap(Compositor::self()->backend()->createSurfaceTextureWayland(this), parent) - , m_item(item) -diff --git a/src/scene/surfaceitem_wayland.h b/src/scene/surfaceitem_wayland.h -index ab31192cb9a..c428f1ea417 100644 ---- a/src/scene/surfaceitem_wayland.h -+++ b/src/scene/surfaceitem_wayland.h -@@ -48,6 +48,7 @@ private Q_SLOTS: - void handleSubSurfaceMappedChanged(); - void handleColorDescriptionChanged(); - void handlePresentationModeHintChanged(); -+ void handleReleasePointChanged(); - - protected: - std::unique_ptr<SurfacePixmap> createPixmap() override; -diff --git a/src/scene/workspacescene_opengl.cpp b/src/scene/workspacescene_opengl.cpp -index 3a024f56bd9..aabee9be151 100644 ---- a/src/scene/workspacescene_opengl.cpp -+++ b/src/scene/workspacescene_opengl.cpp -@@ -40,7 +40,7 @@ namespace KWin - ***********************************************/ - - WorkspaceSceneOpenGL::WorkspaceSceneOpenGL(OpenGLBackend *backend) -- : WorkspaceScene(std::make_unique<ItemRendererOpenGL>()) -+ : WorkspaceScene(std::make_unique<ItemRendererOpenGL>(backend->eglDisplayObject())) - , m_backend(backend) - { - } -diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt -index 41ee1c5581a..9d2add111fc 100644 ---- a/src/wayland/CMakeLists.txt -+++ b/src/wayland/CMakeLists.txt -@@ -231,6 +231,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml - PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/xx-color-management-v2.xml - BASENAME xx-color-management-v2 - ) -+ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml -+ PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/linux-drm-syncobj-v1.xml -+ BASENAME linux-drm-syncobj-v1 -+) - - target_sources(kwin PRIVATE - abstract_data_source.cpp -@@ -265,6 +269,7 @@ target_sources(kwin PRIVATE - keyboard_shortcuts_inhibit_v1.cpp - keystate.cpp - layershell_v1.cpp -+ linux_drm_syncobj_v1.cpp - linuxdmabufv1clientbuffer.cpp - lockscreen_overlay_v1.cpp - output.cpp -@@ -344,6 +349,7 @@ install(FILES - keyboard_shortcuts_inhibit_v1.h - keystate.h - layershell_v1.h -+ linux_drm_syncobj_v1.h - lockscreen_overlay_v1.h - output.h - output_order_v1.h -@@ -390,10 +396,12 @@ install(FILES - - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-content-type-v1.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-frog-color-management-v1.h -+ ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-linux-drm-syncobj-v1.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-presentation-time.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-xx-color-management-v2.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-content-type-v1-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-frog-color-management-v1-server-protocol.h -+ ${CMAKE_CURRENT_BINARY_DIR}/wayland-linux-drm-syncobj-v1-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-presentation-time-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-xx-color-management-v2-server-protocol.h - -diff --git a/src/wayland/linux_drm_syncobj_v1.cpp b/src/wayland/linux_drm_syncobj_v1.cpp -new file mode 100644 -index 00000000000..589ccd78c3b ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1.cpp -@@ -0,0 +1,190 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#include "linux_drm_syncobj_v1.h" -+#include "core/syncobjtimeline.h" -+#include "display.h" -+#include "linux_drm_syncobj_v1_p.h" -+#include "surface.h" -+#include "surface_p.h" -+#include "transaction.h" -+#include "utils/resource.h" -+ -+#include <xf86drm.h> -+ -+namespace KWin -+{ -+ -+static constexpr uint32_t s_version = 1; -+ -+LinuxDrmSyncObjV1Interface::LinuxDrmSyncObjV1Interface(Display *display, QObject *parent) -+ : QObject(parent) -+ , QtWaylandServer::wp_linux_drm_syncobj_manager_v1(*display, s_version) -+{ -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_get_surface(Resource *resource, uint32_t id, wl_resource *surface) -+{ -+ SurfaceInterface *surf = SurfaceInterface::get(surface); -+ SurfaceInterfacePrivate *priv = SurfaceInterfacePrivate::get(surf); -+ if (priv->syncObjV1) { -+ wl_resource_post_error(resource->handle, error_surface_exists, "surface already exists"); -+ return; -+ } -+ priv->syncObjV1 = new LinuxDrmSyncObjSurfaceV1(surf, resource->client(), id); -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_import_timeline(Resource *resource, uint32_t id, int32_t rawFd) -+{ -+ FileDescriptor fd(rawFd); -+ // TODO add a GPU abstraction, instead of using the render backend -+ if (!m_renderBackend || isGlobalRemoved()) { -+ // to not crash the client, create an inert timeline -+ new LinuxDrmSyncObjTimelineV1(resource->client(), id, nullptr); -+ return; -+ } -+ auto timeline = m_renderBackend->importTimeline(std::move(fd)); -+ if (!timeline) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Importing timeline failed"); -+ return; -+ } -+ new LinuxDrmSyncObjTimelineV1(resource->client(), id, std::move(timeline)); -+} -+ -+void LinuxDrmSyncObjV1Interface::setRenderBackend(RenderBackend *backend) -+{ -+ m_renderBackend = backend; -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+void LinuxDrmSyncObjV1Interface::remove() -+{ -+ QtWaylandServer::wp_linux_drm_syncobj_manager_v1::globalRemove(); -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_destroy_global() -+{ -+ delete this; -+} -+ -+LinuxDrmSyncObjTimelineV1::LinuxDrmSyncObjTimelineV1(wl_client *client, uint32_t id, std::unique_ptr<SyncTimeline> &&timeline) -+ : QtWaylandServer::wp_linux_drm_syncobj_timeline_v1(client, id, s_version) -+ , m_timeline(std::move(timeline)) -+{ -+} -+ -+LinuxDrmSyncObjTimelineV1::~LinuxDrmSyncObjTimelineV1() -+{ -+} -+ -+void LinuxDrmSyncObjTimelineV1::wp_linux_drm_syncobj_timeline_v1_destroy_resource(Resource *resource) -+{ -+ delete this; -+} -+ -+void LinuxDrmSyncObjTimelineV1::wp_linux_drm_syncobj_timeline_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+std::shared_ptr<SyncTimeline> LinuxDrmSyncObjTimelineV1::timeline() const -+{ -+ return m_timeline; -+} -+ -+LinuxDrmSyncObjSurfaceV1::LinuxDrmSyncObjSurfaceV1(SurfaceInterface *surface, wl_client *client, uint32_t id) -+ : QtWaylandServer::wp_linux_drm_syncobj_surface_v1(client, id, s_version) -+ , m_surface(surface) -+{ -+} -+ -+LinuxDrmSyncObjSurfaceV1::~LinuxDrmSyncObjSurfaceV1() -+{ -+ if (m_surface) { -+ SurfaceInterfacePrivate::get(m_surface)->syncObjV1 = nullptr; -+ } -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_set_acquire_point(Resource *resource, wl_resource *timeline_resource, uint32_t point_hi, uint32_t point_lo) -+{ -+ if (!m_surface) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface got destroyed already"); -+ return; -+ } -+ const auto timeline = resource_cast<LinuxDrmSyncObjTimelineV1 *>(timeline_resource); -+ if (!timeline->timeline()) { -+ // in the normal case this should never happen, but if it does, -+ // there's nothing we can do about it without killing the client -+ return; -+ } -+ const uint64_t point = (uint64_t(point_hi) << 32) | point_lo; -+ const auto priv = SurfaceInterfacePrivate::get(m_surface); -+ priv->pending->acquirePoint.timeline = timeline->timeline(); -+ priv->pending->acquirePoint.point = point; -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_set_release_point(Resource *resource, wl_resource *timeline_resource, uint32_t point_hi, uint32_t point_lo) -+{ -+ if (!m_surface) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface got destroyed already"); -+ return; -+ } -+ const auto timeline = resource_cast<LinuxDrmSyncObjTimelineV1 *>(timeline_resource); -+ if (!timeline->timeline()) { -+ // in the normal case this should never happen, but if it does, -+ // there's nothing we can do about it without killing the client -+ return; -+ } -+ const uint64_t point = (uint64_t(point_hi) << 32) | point_lo; -+ SurfaceInterfacePrivate::get(m_surface)->pending->releasePoint = std::make_unique<SyncReleasePoint>(timeline->timeline(), point); -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_destroy_resource(Resource *resource) -+{ -+ delete this; -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+bool LinuxDrmSyncObjSurfaceV1::maybeEmitProtocolErrors() -+{ -+ const auto priv = SurfaceInterfacePrivate::get(m_surface); -+ if (!priv->pending->bufferIsSet && !priv->pending->acquirePoint.timeline && !priv->pending->releasePoint) { -+ return false; -+ } -+ if (!priv->pending->acquirePoint.timeline) { -+ wl_resource_post_error(resource()->handle, error_no_acquire_point, "explicit sync is used, but no acquire point is set"); -+ return true; -+ } -+ if (!priv->pending->releasePoint) { -+ wl_resource_post_error(resource()->handle, error_no_release_point, "explicit sync is used, but no release point is set"); -+ return true; -+ } -+ if (priv->pending->acquirePoint.timeline.get() == priv->pending->releasePoint->timeline() -+ && priv->pending->acquirePoint.point >= priv->pending->releasePoint->timelinePoint()) { -+ wl_resource_post_error(resource()->handle, error_conflicting_points, "acquire and release points are on the same timeline and acquire >= release"); -+ return true; -+ } -+ if (!priv->pending->buffer) { -+ wl_resource_post_error(resource()->handle, error_no_buffer, "explicit sync is used, but no buffer is attached"); -+ return true; -+ } -+ if (!priv->pending->buffer->dmabufAttributes()) { -+ wl_resource_post_error(resource()->handle, error_unsupported_buffer, "only linux dmabuf buffers are allowed to use explicit sync"); -+ return true; -+ } -+ return false; -+} -+} -diff --git a/src/wayland/linux_drm_syncobj_v1.h b/src/wayland/linux_drm_syncobj_v1.h -new file mode 100644 -index 00000000000..ff6ddbe0340 ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1.h -@@ -0,0 +1,63 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+ -+#include "kwin_export.h" -+#include "qwayland-server-linux-drm-syncobj-v1.h" -+ -+#include <QObject> -+#include <QPointer> -+ -+namespace KWin -+{ -+ -+class Display; -+class SurfaceInterface; -+class RenderBackend; -+class SyncTimeline; -+ -+class KWIN_EXPORT LinuxDrmSyncObjV1Interface : public QObject, private QtWaylandServer::wp_linux_drm_syncobj_manager_v1 -+{ -+ Q_OBJECT -+public: -+ explicit LinuxDrmSyncObjV1Interface(Display *display, QObject *parent = nullptr); -+ -+ void setRenderBackend(RenderBackend *backend); -+ void remove(); -+ -+private: -+ void wp_linux_drm_syncobj_manager_v1_get_surface(Resource *resource, uint32_t id, wl_resource *surface) override; -+ void wp_linux_drm_syncobj_manager_v1_import_timeline(Resource *resource, uint32_t id, int32_t fd) override; -+ void wp_linux_drm_syncobj_manager_v1_destroy(Resource *resource) override; -+ void wp_linux_drm_syncobj_manager_v1_destroy_global() override; -+ -+ QPointer<RenderBackend> m_renderBackend; -+}; -+ -+class LinuxDrmSyncObjSurfaceV1 : private QtWaylandServer::wp_linux_drm_syncobj_surface_v1 -+{ -+public: -+ explicit LinuxDrmSyncObjSurfaceV1(SurfaceInterface *surface, wl_client *client, uint32_t id); -+ ~LinuxDrmSyncObjSurfaceV1() override; -+ -+ /** -+ * checks for protocol errors that may need to be sent at commit time -+ * @returns if any protocol errors were actually emitted -+ */ -+ bool maybeEmitProtocolErrors(); -+ -+private: -+ void wp_linux_drm_syncobj_surface_v1_set_acquire_point(Resource *resource, wl_resource *timeline, uint32_t point_hi, uint32_t point_lo) override; -+ void wp_linux_drm_syncobj_surface_v1_set_release_point(Resource *resource, wl_resource *timeline, uint32_t point_hi, uint32_t point_lo) override; -+ void wp_linux_drm_syncobj_surface_v1_destroy_resource(Resource *resource) override; -+ void wp_linux_drm_syncobj_surface_v1_destroy(Resource *resource) override; -+ -+ const QPointer<SurfaceInterface> m_surface; -+}; -+} -diff --git a/src/wayland/linux_drm_syncobj_v1_p.h b/src/wayland/linux_drm_syncobj_v1_p.h -new file mode 100644 -index 00000000000..6efbc12ee30 ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1_p.h -@@ -0,0 +1,32 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+#include "linux_drm_syncobj_v1.h" -+ -+namespace KWin -+{ -+ -+class LinuxDrmSyncObjTimelineV1 : public QtWaylandServer::wp_linux_drm_syncobj_timeline_v1 -+{ -+public: -+ explicit LinuxDrmSyncObjTimelineV1(wl_client *client, uint32_t id, std::unique_ptr<SyncTimeline> &&timeline); -+ ~LinuxDrmSyncObjTimelineV1() override; -+ -+ /** -+ * May return nullptr if the timeline resource is inert -+ */ -+ std::shared_ptr<SyncTimeline> timeline() const; -+ -+private: -+ void wp_linux_drm_syncobj_timeline_v1_destroy_resource(Resource *resource) override; -+ void wp_linux_drm_syncobj_timeline_v1_destroy(Resource *resource) override; -+ -+ const std::shared_ptr<SyncTimeline> m_timeline; -+}; -+} -diff --git a/src/wayland/protocols/linux-drm-syncobj-v1.xml b/src/wayland/protocols/linux-drm-syncobj-v1.xml -new file mode 100644 -index 00000000000..2c491eaf43a ---- /dev/null -+++ b/src/wayland/protocols/linux-drm-syncobj-v1.xml -@@ -0,0 +1,261 @@ -+<?xml version="1.0" encoding="UTF-8"?> -+<protocol name="linux_drm_syncobj_v1"> -+ <copyright> -+ Copyright 2016 The Chromium Authors. -+ Copyright 2017 Intel Corporation -+ Copyright 2018 Collabora, Ltd -+ Copyright 2021 Simon Ser -+ -+ Permission is hereby granted, free of charge, to any person obtaining a -+ copy of this software and associated documentation files (the "Software"), -+ to deal in the Software without restriction, including without limitation -+ the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ and/or sell copies of the Software, and to permit persons to whom the -+ Software is furnished to do so, subject to the following conditions: -+ -+ The above copyright notice and this permission notice (including the next -+ paragraph) shall be included in all copies or substantial portions of the -+ Software. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ DEALINGS IN THE SOFTWARE. -+ </copyright> -+ -+ <description summary="protocol for providing explicit synchronization"> -+ This protocol allows clients to request explicit synchronization for -+ buffers. It is tied to the Linux DRM synchronization object framework. -+ -+ Synchronization refers to co-ordination of pipelined operations performed -+ on buffers. Most GPU clients will schedule an asynchronous operation to -+ render to the buffer, then immediately send the buffer to the compositor -+ to be attached to a surface. -+ -+ With implicit synchronization, ensuring that the rendering operation is -+ complete before the compositor displays the buffer is an implementation -+ detail handled by either the kernel or userspace graphics driver. -+ -+ By contrast, with explicit synchronization, DRM synchronization object -+ timeline points mark when the asynchronous operations are complete. When -+ submitting a buffer, the client provides a timeline point which will be -+ waited on before the compositor accesses the buffer, and another timeline -+ point that the compositor will signal when it no longer needs to access the -+ buffer contents for the purposes of the surface commit. -+ -+ Linux DRM synchronization objects are documented at: -+ https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects -+ -+ Warning! The protocol described in this file is currently in the testing -+ phase. Backward compatible changes may be added together with the -+ corresponding interface version bump. Backward incompatible changes can -+ only be done by creating a new major version of the extension. -+ </description> -+ -+ <interface name="wp_linux_drm_syncobj_manager_v1" version="1"> -+ <description summary="global for providing explicit synchronization"> -+ This global is a factory interface, allowing clients to request -+ explicit synchronization for buffers on a per-surface basis. -+ -+ See wp_linux_drm_syncobj_surface_v1 for more information. -+ </description> -+ -+ <request name="destroy" type="destructor"> -+ <description summary="destroy explicit synchronization factory object"> -+ Destroy this explicit synchronization factory object. Other objects -+ shall not be affected by this request. -+ </description> -+ </request> -+ -+ <enum name="error"> -+ <entry name="surface_exists" value="0" -+ summary="the surface already has a synchronization object associated"/> -+ <entry name="invalid_timeline" value="1" -+ summary="the timeline object could not be imported"/> -+ </enum> -+ -+ <request name="get_surface"> -+ <description summary="extend surface interface for explicit synchronization"> -+ Instantiate an interface extension for the given wl_surface to provide -+ explicit synchronization. -+ -+ If the given wl_surface already has an explicit synchronization object -+ associated, the surface_exists protocol error is raised. -+ -+ Graphics APIs, like EGL or Vulkan, that manage the buffer queue and -+ commits of a wl_surface themselves, are likely to be using this -+ extension internally. If a client is using such an API for a -+ wl_surface, it should not directly use this extension on that surface, -+ to avoid raising a surface_exists protocol error. -+ </description> -+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_surface_v1" -+ summary="the new synchronization surface object id"/> -+ <arg name="surface" type="object" interface="wl_surface" -+ summary="the surface"/> -+ </request> -+ -+ <request name="import_timeline"> -+ <description summary="import a DRM syncobj timeline"> -+ Import a DRM synchronization object timeline. -+ -+ If the FD cannot be imported, the invalid_timeline error is raised. -+ </description> -+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_timeline_v1"/> -+ <arg name="fd" type="fd" summary="drm_syncobj file descriptor"/> -+ </request> -+ </interface> -+ -+ <interface name="wp_linux_drm_syncobj_timeline_v1" version="1"> -+ <description summary="synchronization object timeline"> -+ This object represents an explicit synchronization object timeline -+ imported by the client to the compositor. -+ </description> -+ -+ <request name="destroy" type="destructor"> -+ <description summary="destroy the timeline"> -+ Destroy the synchronization object timeline. Other objects are not -+ affected by this request, in particular timeline points set by -+ set_acquire_point and set_release_point are not unset. -+ </description> -+ </request> -+ </interface> -+ -+ <interface name="wp_linux_drm_syncobj_surface_v1" version="1"> -+ <description summary="per-surface explicit synchronization"> -+ This object is an add-on interface for wl_surface to enable explicit -+ synchronization. -+ -+ Each surface can be associated with only one object of this interface at -+ any time. -+ -+ Explicit synchronization is guaranteed to be supported for buffers -+ created with any version of the linux-dmabuf protocol. Compositors are -+ free to support explicit synchronization for additional buffer types. -+ If at surface commit time the attached buffer does not support explicit -+ synchronization, an unsupported_buffer error is raised. -+ -+ As long as the wp_linux_drm_syncobj_surface_v1 object is alive, the -+ compositor may ignore implicit synchronization for buffers attached and -+ committed to the wl_surface. The delivery of wl_buffer.release events -+ for buffers attached to the surface becomes undefined. -+ -+ Clients must set both acquire and release points if and only if a -+ non-null buffer is attached in the same surface commit. See the -+ no_buffer, no_acquire_point and no_release_point protocol errors. -+ -+ If at surface commit time the acquire and release DRM syncobj timelines -+ are identical, the acquire point value must be strictly less than the -+ release point value, or else the conflicting_points protocol error is -+ raised. -+ </description> -+ -+ <request name="destroy" type="destructor"> -+ <description summary="destroy the surface synchronization object"> -+ Destroy this surface synchronization object. -+ -+ Any timeline point set by this object with set_acquire_point or -+ set_release_point since the last commit may be discarded by the -+ compositor. Any timeline point set by this object before the last -+ commit will not be affected. -+ </description> -+ </request> -+ -+ <enum name="error"> -+ <entry name="no_surface" value="1" -+ summary="the associated wl_surface was destroyed"/> -+ <entry name="unsupported_buffer" value="2" -+ summary="the buffer does not support explicit synchronization"/> -+ <entry name="no_buffer" value="3" summary="no buffer was attached"/> -+ <entry name="no_acquire_point" value="4" -+ summary="no acquire timeline point was set"/> -+ <entry name="no_release_point" value="5" -+ summary="no release timeline point was set"/> -+ <entry name="conflicting_points" value="6" -+ summary="acquire and release timeline points are in conflict"/> -+ </enum> -+ -+ <request name="set_acquire_point"> -+ <description summary="set the acquire timeline point"> -+ Set the timeline point that must be signalled before the compositor may -+ sample from the buffer attached with wl_surface.attach. -+ -+ The 64-bit unsigned value combined from point_hi and point_lo is the -+ point value. -+ -+ The acquire point is double-buffered state, and will be applied on the -+ next wl_surface.commit request for the associated surface. Thus, it -+ applies only to the buffer that is attached to the surface at commit -+ time. -+ -+ If an acquire point has already been attached during the same commit -+ cycle, the new point replaces the old one. -+ -+ If the associated wl_surface was destroyed, a no_surface error is -+ raised. -+ -+ If at surface commit time there is a pending acquire timeline point set -+ but no pending buffer attached, a no_buffer error is raised. If at -+ surface commit time there is a pending buffer attached but no pending -+ acquire timeline point set, the no_acquire_point protocol error is -+ raised. -+ </description> -+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/> -+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/> -+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/> -+ </request> -+ -+ <request name="set_release_point"> -+ <description summary="set the release timeline point"> -+ Set the timeline point that must be signalled by the compositor when it -+ has finished its usage of the buffer attached with wl_surface.attach -+ for the relevant commit. -+ -+ Once the timeline point is signaled, and assuming the associated buffer -+ is not pending release from other wl_surface.commit requests, no -+ additional explicit or implicit synchronization with the compositor is -+ required to safely re-use the buffer. -+ -+ Note that clients cannot rely on the release point being always -+ signaled after the acquire point: compositors may release buffers -+ without ever reading from them. In addition, the compositor may use -+ different presentation paths for different commits, which may have -+ different release behavior. As a result, the compositor may signal the -+ release points in a different order than the client committed them. -+ -+ Because signaling a timeline point also signals every previous point, -+ it is generally not safe to use the same timeline object for the -+ release points of multiple buffers. The out-of-order signaling -+ described above may lead to a release point being signaled before the -+ compositor has finished reading. To avoid this, it is strongly -+ recommended that each buffer should use a separate timeline for its -+ release points. -+ -+ The 64-bit unsigned value combined from point_hi and point_lo is the -+ point value. -+ -+ The release point is double-buffered state, and will be applied on the -+ next wl_surface.commit request for the associated surface. Thus, it -+ applies only to the buffer that is attached to the surface at commit -+ time. -+ -+ If a release point has already been attached during the same commit -+ cycle, the new point replaces the old one. -+ -+ If the associated wl_surface was destroyed, a no_surface error is -+ raised. -+ -+ If at surface commit time there is a pending release timeline point set -+ but no pending buffer attached, a no_buffer error is raised. If at -+ surface commit time there is a pending buffer attached but no pending -+ release timeline point set, the no_release_point protocol error is -+ raised. -+ </description> -+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/> -+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/> -+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/> -+ </request> -+ </interface> -+</protocol> -diff --git a/src/wayland/surface.cpp b/src/wayland/surface.cpp -index 23f981f2f81..6a33c5fca10 100644 ---- a/src/wayland/surface.cpp -+++ b/src/wayland/surface.cpp -@@ -13,6 +13,7 @@ - #include "fractionalscale_v1_p.h" - #include "frog_colormanagement_v1.h" - #include "idleinhibit_v1_p.h" -+#include "linux_drm_syncobj_v1.h" - #include "linuxdmabufv1clientbuffer.h" - #include "output.h" - #include "pointerconstraints_v1_p.h" -@@ -342,6 +343,10 @@ void SurfaceInterfacePrivate::surface_commit(Resource *resource) - { - const bool sync = subsurface.handle && subsurface.handle->isSynchronized(); - -+ if (syncObjV1 && syncObjV1->maybeEmitProtocolErrors()) { -+ return; -+ } -+ - Transaction *transaction; - if (sync) { - if (!subsurface.transaction) { -@@ -518,6 +523,9 @@ void SurfaceState::mergeInto(SurfaceState *target) - target->offset = offset; - target->damage = damage; - target->bufferDamage = bufferDamage; -+ target->acquirePoint.timeline = std::exchange(acquirePoint.timeline, nullptr); -+ target->acquirePoint.point = acquirePoint.point; -+ target->releasePoint = std::move(releasePoint); - target->bufferIsSet = true; - } - if (viewport.sourceGeometryIsSet) { -@@ -600,6 +608,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer); - const bool colorDescriptionChanged = next->colorDescriptionIsSet; - const bool presentationModeHintChanged = next->presentationModeHintIsSet; -+ const bool bufferReleasePointChanged = next->releasePointIsSet; - - const QSizeF oldSurfaceSize = surfaceSize; - const QSize oldBufferSize = bufferSize; -@@ -608,6 +617,9 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - - next->mergeInto(current.get()); - bufferRef = current->buffer; -+ if (bufferRef && current->releasePoint) { -+ bufferRef->addReleasePoint(current->releasePoint); -+ } - scaleOverride = pendingScaleOverride; - - if (current->buffer) { -@@ -689,6 +701,9 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - if (presentationModeHintChanged) { - Q_EMIT q->presentationModeHintChanged(); - } -+ if (bufferReleasePointChanged) { -+ Q_EMIT q->bufferReleasePointChanged(); -+ } - - if (bufferChanged) { - if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) { -@@ -1179,6 +1194,11 @@ void SurfaceInterface::traverseTree(std::function<void(SurfaceInterface *surface - } - } - -+std::shared_ptr<SyncReleasePoint> SurfaceInterface::bufferReleasePoint() const -+{ -+ return d->current->releasePoint; -+} -+ - } // namespace KWin - - #include "moc_surface.cpp" -diff --git a/src/wayland/surface.h b/src/wayland/surface.h -index 597f06774f8..80d1fa55708 100644 ---- a/src/wayland/surface.h -+++ b/src/wayland/surface.h -@@ -32,6 +32,7 @@ class SlideInterface; - class SubSurfaceInterface; - class SurfaceInterfacePrivate; - class Transaction; -+class SyncReleasePoint; - - /** - * The SurfaceRole class represents a role assigned to a wayland surface. -@@ -342,6 +343,12 @@ public: - - void setPreferredColorDescription(const ColorDescription &descr); - -+ /** -+ * @returns the release point that should be referenced as long as the buffer on this surface -+ * is, or may still be used by the compositor -+ */ -+ std::shared_ptr<SyncReleasePoint> bufferReleasePoint() const; -+ - /** - * Traverses the surface sub-tree with this surface as the root. - */ -@@ -426,6 +433,7 @@ Q_SIGNALS: - - void colorDescriptionChanged(); - void presentationModeHintChanged(); -+ void bufferReleasePointChanged(); - - /** - * Emitted when the Surface has been committed. -diff --git a/src/wayland/surface_p.h b/src/wayland/surface_p.h -index f78bd107b44..775f9d7bd2e 100644 ---- a/src/wayland/surface_p.h -+++ b/src/wayland/surface_p.h -@@ -28,6 +28,7 @@ class FractionalScaleV1Interface; - class FrogColorManagementSurfaceV1; - class PresentationTimeFeedback; - class XXColorSurfaceV2; -+class LinuxDrmSyncObjSurfaceV1; - - struct SurfaceState - { -@@ -58,6 +59,7 @@ struct SurfaceState - bool contentTypeIsSet = false; - bool presentationModeHintIsSet = false; - bool colorDescriptionIsSet = false; -+ bool releasePointIsSet = false; - qint32 bufferScale = 1; - OutputTransform bufferTransform = OutputTransform::Normal; - wl_list frameCallbacks; -@@ -71,6 +73,12 @@ struct SurfaceState - PresentationModeHint presentationHint = PresentationModeHint::VSync; - ColorDescription colorDescription = ColorDescription::sRGB; - std::unique_ptr<PresentationTimeFeedback> presentationFeedback; -+ struct -+ { -+ std::shared_ptr<SyncTimeline> timeline; -+ uint64_t point = 0; -+ } acquirePoint; -+ std::shared_ptr<SyncReleasePoint> releasePoint; - - struct - { -@@ -169,6 +177,7 @@ public: - TearingControlV1Interface *tearing = nullptr; - FrogColorManagementSurfaceV1 *frogColorManagement = nullptr; - XXColorSurfaceV2 *xxColorSurface = nullptr; -+ LinuxDrmSyncObjSurfaceV1 *syncObjV1 = nullptr; - - struct - { -diff --git a/src/wayland/transaction.cpp b/src/wayland/transaction.cpp -index 93004ba863d..fcd19d4036f 100644 ---- a/src/wayland/transaction.cpp -+++ b/src/wayland/transaction.cpp -@@ -5,7 +5,9 @@ - */ - - #include "wayland/transaction.h" -+#include "core/syncobjtimeline.h" - #include "utils/filedescriptor.h" -+#include "wayland/clientconnection.h" - #include "wayland/subcompositor.h" - #include "wayland/surface_p.h" - #include "wayland/transaction_p.h" -@@ -76,6 +78,24 @@ bool TransactionDmaBufLocker::arm() - return !m_pending.isEmpty(); - } - -+TransactionEventFdLocker::TransactionEventFdLocker(Transaction *transaction, FileDescriptor &&eventFd, ClientConnection *client) -+ : m_transaction(transaction) -+ , m_client(client) -+ , m_eventFd(std::move(eventFd)) -+ , m_notifier(m_eventFd.get(), QSocketNotifier::Type::Read) -+{ -+ transaction->lock(); -+ connect(&m_notifier, &QSocketNotifier::activated, this, &TransactionEventFdLocker::unlock); -+ // when the client quits, the eventfd may never be signaled -+ connect(m_client, &ClientConnection::aboutToBeDestroyed, this, &TransactionEventFdLocker::unlock); -+} -+ -+void TransactionEventFdLocker::unlock() -+{ -+ m_transaction->unlock(); -+ delete this; -+} -+ - Transaction::Transaction() - { - } -@@ -248,7 +268,12 @@ void Transaction::commit() - for (TransactionEntry &entry : m_entries) { - if (entry.state->bufferIsSet && entry.state->buffer) { - // Avoid applying the transaction until all graphics buffers have become idle. -- if (auto locker = TransactionDmaBufLocker::get(entry.state->buffer)) { -+ if (entry.state->acquirePoint.timeline) { -+ auto eventFd = entry.state->acquirePoint.timeline->eventFd(entry.state->acquirePoint.point); -+ if (entry.surface && eventFd.isValid()) { -+ new TransactionEventFdLocker(this, std::move(eventFd), entry.surface->client()); -+ } -+ } else if (auto locker = TransactionDmaBufLocker::get(entry.state->buffer)) { - locker->add(this); - } - } -diff --git a/src/wayland/transaction_p.h b/src/wayland/transaction_p.h -index 5bcf148aaad..29a9921e81f 100644 ---- a/src/wayland/transaction_p.h -+++ b/src/wayland/transaction_p.h -@@ -33,4 +33,19 @@ private: - std::vector<std::unique_ptr<QSocketNotifier>> m_notifiers; - }; - -+class TransactionEventFdLocker : public QObject -+{ -+ Q_OBJECT -+public: -+ TransactionEventFdLocker(Transaction *transaction, FileDescriptor &&eventFd, ClientConnection *client); -+ -+private: -+ void unlock(); -+ -+ Transaction *const m_transaction; -+ const QPointer<ClientConnection> m_client; -+ const FileDescriptor m_eventFd; -+ QSocketNotifier m_notifier; -+}; -+ - } // namespace KWin -diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp -index 2b02eb2fa69..037b633fc6c 100644 ---- a/src/wayland_server.cpp -+++ b/src/wayland_server.cpp -@@ -41,6 +41,7 @@ - #include "wayland/inputmethod_v1.h" - #include "wayland/keyboard_shortcuts_inhibit_v1.h" - #include "wayland/keystate.h" -+#include "wayland/linux_drm_syncobj_v1.h" - #include "wayland/linuxdmabufv1clientbuffer.h" - #include "wayland/lockscreen_overlay_v1.h" - #include "wayland/output.h" -@@ -811,6 +812,22 @@ QString WaylandServer::socketName() const - return QString(); - } - -+LinuxDrmSyncObjV1Interface *WaylandServer::linuxSyncObj() const -+{ -+ return m_linuxDrmSyncObj; -+} -+ -+void WaylandServer::setRenderBackend(RenderBackend *backend) -+{ -+ if (backend->supportsTimelines()) { -+ if (!m_linuxDrmSyncObj) { -+ m_linuxDrmSyncObj = new LinuxDrmSyncObjV1Interface(m_display, m_display); -+ } -+ } else if (m_linuxDrmSyncObj) { -+ m_linuxDrmSyncObj->remove(); -+ } -+} -+ - #if KWIN_BUILD_SCREENLOCKER - WaylandServer::LockScreenPresentationWatcher::LockScreenPresentationWatcher(WaylandServer *server) - { -diff --git a/src/wayland_server.h b/src/wayland_server.h -index 8eb6f31a176..60dc67d9670 100644 ---- a/src/wayland_server.h -+++ b/src/wayland_server.h -@@ -58,6 +58,8 @@ class XdgSurfaceWindow; - class XdgToplevelWindow; - class PresentationTime; - class XXColorManagerV2; -+class LinuxDrmSyncObjV1Interface; -+class RenderBackend; - - class KWIN_EXPORT WaylandServer : public QObject - { -@@ -226,6 +228,10 @@ public: - return m_xdgActivationIntegration; - } - -+ LinuxDrmSyncObjV1Interface *linuxSyncObj() const; -+ -+ void setRenderBackend(RenderBackend *backend); -+ - Q_SIGNALS: - void windowAdded(KWin::Window *); - void windowRemoved(KWin::Window *); -@@ -284,6 +290,7 @@ private: - TearingControlManagerV1Interface *m_tearingControlInterface = nullptr; - XwaylandShellV1Interface *m_xwaylandShell = nullptr; - PresentationTime *m_presentationTime = nullptr; -+ LinuxDrmSyncObjV1Interface *m_linuxDrmSyncObj = nullptr; - QList<Window *> m_windows; - InitializationFlags m_initFlags; - QHash<Output *, OutputInterface *> m_waylandOutputs; --- -GitLab - - -From 489761e5d772ad11d195c3eb679f6747d1aa2e46 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl <xaver.hugl@gmail.com> -Date: Sat, 6 Apr 2024 18:51:01 +0200 -Subject: [PATCH 2/5] core/syncobjtimeline: make explicit sync use - SYNC_IOC_MERGE instead of waiting on the CPU side - -This brings some performance benefits, because the application can potentially reuse -the buffer earlier, and it simplifies the code a bit - -(cherry picked from commit 4c6000b3e1829da5f0ccb81bbccfee37fb28cd24) ---- - src/core/syncobjtimeline.cpp | 63 +++++++++++++++++++++++++------ - src/core/syncobjtimeline.h | 28 ++++---------- - src/scene/itemrenderer_opengl.cpp | 5 ++- - src/wayland/surface.h | 6 ++- - 4 files changed, 67 insertions(+), 35 deletions(-) - -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -index 3e2c100370a..1152e895722 100644 ---- a/src/core/syncobjtimeline.cpp -+++ b/src/core/syncobjtimeline.cpp -@@ -6,8 +6,24 @@ - #include "syncobjtimeline.h" - - #include <sys/eventfd.h> -+#include <sys/ioctl.h> - #include <xf86drm.h> - -+#if defined(Q_OS_LINUX) -+#include <linux/sync_file.h> -+#else -+struct sync_merge_data -+{ -+ char name[32]; -+ __s32 fd2; -+ __s32 fence; -+ __u32 flags; -+ __u32 pad; -+}; -+#define SYNC_IOC_MAGIC '>' -+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) -+#endif -+ - namespace KWin - { - -@@ -19,7 +35,39 @@ SyncReleasePoint::SyncReleasePoint(const std::shared_ptr<SyncTimeline> &timeline - - SyncReleasePoint::~SyncReleasePoint() - { -- m_timeline->signal(m_timelinePoint); -+ if (m_releaseFence.isValid()) { -+ m_timeline->moveInto(m_timelinePoint, m_releaseFence); -+ } else { -+ m_timeline->signal(m_timelinePoint); -+ } -+} -+ -+static FileDescriptor mergeSyncFds(const FileDescriptor &fd1, const FileDescriptor &fd2) -+{ -+ struct sync_merge_data data -+ { -+ .name = "merged release fence", -+ .fd2 = fd2.get(), -+ .fence = -1, -+ }; -+ int err = -1; -+ do { -+ err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data); -+ } while (err == -1 && (errno == EINTR || errno == EAGAIN)); -+ if (err < 0) { -+ return FileDescriptor{}; -+ } else { -+ return FileDescriptor(data.fence); -+ } -+} -+ -+void SyncReleasePoint::addReleaseFence(const FileDescriptor &fd) -+{ -+ if (m_releaseFence.isValid()) { -+ m_releaseFence = mergeSyncFds(m_releaseFence, fd); -+ } else { -+ m_releaseFence = fd.duplicate(); -+ } - } - - SyncTimeline *SyncReleasePoint::timeline() const -@@ -67,17 +115,8 @@ void SyncTimeline::signal(uint64_t timelinePoint) - drmSyncobjTimelineSignal(m_drmFd, &m_handle, &timelinePoint, 1); - } - --SyncReleasePointHolder::SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints) -- : m_fence(std::move(requirement)) -- , m_notifier(m_fence.get(), QSocketNotifier::Type::Read) -- , m_releasePoints(std::move(releasePoints)) --{ -- connect(&m_notifier, &QSocketNotifier::activated, this, &SyncReleasePointHolder::signaled); -- m_notifier.setEnabled(true); --} -- --void SyncReleasePointHolder::signaled() -+void SyncTimeline::moveInto(uint64_t timelinePoint, const FileDescriptor &fd) - { -- delete this; -+ drmSyncobjImportSyncFile(m_drmFd, m_handle, fd.get()); - } - } -diff --git a/src/core/syncobjtimeline.h b/src/core/syncobjtimeline.h -index cffdb75e330..4ced3e06272 100644 ---- a/src/core/syncobjtimeline.h -+++ b/src/core/syncobjtimeline.h -@@ -7,11 +7,8 @@ - #include "kwin_export.h" - #include "utils/filedescriptor.h" - --#include <QObject> --#include <QSocketNotifier> - #include <memory> - #include <stdint.h> --#include <unordered_set> - - namespace KWin - { -@@ -30,9 +27,16 @@ public: - SyncTimeline *timeline() const; - uint64_t timelinePoint() const; - -+ /** -+ * Adds the fence of a graphics job that this release point should wait for -+ * before the timeline point is signaled -+ */ -+ void addReleaseFence(const FileDescriptor &fd); -+ - private: - const std::shared_ptr<SyncTimeline> m_timeline; - const uint64_t m_timelinePoint; -+ FileDescriptor m_releaseFence; - }; - - class KWIN_EXPORT SyncTimeline -@@ -47,26 +51,10 @@ public: - FileDescriptor eventFd(uint64_t timelinePoint) const; - - void signal(uint64_t timelinePoint); -+ void moveInto(uint64_t timelinePoint, const FileDescriptor &fd); - - private: - const int32_t m_drmFd; - const uint32_t m_handle; - }; -- --class SyncReleasePointHolder : public QObject --{ -- Q_OBJECT --public: -- /** -- * @param requirement the filedescriptor that needs to be readable before the release points may be signalled. Once that's happened, this object deletes itself!' -- */ -- explicit SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints); -- --private: -- void signaled(); -- -- const FileDescriptor m_fence; -- QSocketNotifier m_notifier; -- const std::unordered_set<std::shared_ptr<SyncReleasePoint>> m_releasePoints; --}; - } -diff --git a/src/scene/itemrenderer_opengl.cpp b/src/scene/itemrenderer_opengl.cpp -index 3fee3863f2c..ffcc6de3914 100644 ---- a/src/scene/itemrenderer_opengl.cpp -+++ b/src/scene/itemrenderer_opengl.cpp -@@ -53,7 +53,10 @@ void ItemRendererOpenGL::endFrame() - if (m_eglDisplay) { - EGLNativeFence fence(m_eglDisplay); - if (fence.isValid()) { -- new SyncReleasePointHolder(std::move(fence.fileDescriptor()), std::move(m_releasePoints)); -+ for (const auto &releasePoint : m_releasePoints) { -+ releasePoint->addReleaseFence(fence.fileDescriptor()); -+ } -+ m_releasePoints.clear(); - } - } - m_releasePoints.clear(); -diff --git a/src/wayland/surface.h b/src/wayland/surface.h -index 80d1fa55708..152f1accc10 100644 ---- a/src/wayland/surface.h -+++ b/src/wayland/surface.h -@@ -344,8 +344,10 @@ public: - void setPreferredColorDescription(const ColorDescription &descr); - - /** -- * @returns the release point that should be referenced as long as the buffer on this surface -- * is, or may still be used by the compositor -+ * Returns the current release point for the buffer on this surface. The buffer keeps the -+ * release point referenced as long as it's referenced itself; for synchronization on the -+ * GPU side, the compositor has to either keep the release point referenced as long as the -+ * GPU task is running, or add a fence for each GPU task to the release point - */ - std::shared_ptr<SyncReleasePoint> bufferReleasePoint() const; - --- -GitLab - - -From eef4cbe0278e81c33b496932400854a74a08bfa4 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl <xaver.hugl@gmail.com> -Date: Tue, 16 Apr 2024 13:51:42 +0200 -Subject: [PATCH 3/5] wayland_server: guard against DRM_IOCTL_SYNCOBJ_EVENTFD - being broken - -...either because it's not implemented, or because it's buggy. - -(cherry picked from commit 26afbfb6fa030c3dadf6a22309686f96ca033f59) ---- - src/wayland_server.cpp | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp -index 037b633fc6c..d9240f0e8ce 100644 ---- a/src/wayland_server.cpp -+++ b/src/wayland_server.cpp -@@ -19,6 +19,7 @@ - #include "layershellv1window.h" - #include "main.h" - #include "options.h" -+#include "utils/kernel.h" - #include "utils/serviceutils.h" - #include "virtualdesktops.h" - #include "wayland/appmenu.h" -@@ -820,6 +821,15 @@ LinuxDrmSyncObjV1Interface *WaylandServer::linuxSyncObj() const - void WaylandServer::setRenderBackend(RenderBackend *backend) - { - if (backend->supportsTimelines()) { -+ // ensure the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl is supported -+ const auto linuxVersion = linuxKernelVersion(); -+ if (linuxVersion.majorVersion() < 6 && linuxVersion.minorVersion() < 6) { -+ return; -+ } -+ // also ensure the implementation isn't totally broken, see https://lists.freedesktop.org/archives/dri-devel/2024-January/439101.html -+ if (linuxVersion.majorVersion() == 6 && (linuxVersion.minorVersion() == 7 || (linuxVersion.minorVersion() == 6 && linuxVersion.patchVersion() < 19))) { -+ return; -+ } - if (!m_linuxDrmSyncObj) { - m_linuxDrmSyncObj = new LinuxDrmSyncObjV1Interface(m_display, m_display); - } --- -GitLab - - -From 2e9ecb0edf137309fb526adc7c8504e8c669b17f Mon Sep 17 00:00:00 2001 -From: Erik Kurzinger <ekurzinger@nvidia.com> -Date: Tue, 16 Apr 2024 14:44:50 -0700 -Subject: [PATCH 4/5] core/syncobjtimeline: import release fence at correct - timeline point - -SyncTimeline::moveInto imports the provided fence to the syncobj by -calling drmSyncobjImportSyncFile. However, that function assumes the -syncobj a binary syncobj, meaning the fence will be imported at timeline -point 0, not at the intended timeline point. - -Since there is no timeline equivalent of drmSyncobjImportSyncFile, to -achieve the correct behavior we create a temporary binary syncobj, -import the fence into that, and then use drmSyncobjTransfer to transfer -the fence to the desired timeline point on the destination syncobj. - -Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com> -(cherry picked from commit 9ca7b9b1cf292e790223419dc197737f875109d4) ---- - src/core/syncobjtimeline.cpp | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -index 1152e895722..80054e93480 100644 ---- a/src/core/syncobjtimeline.cpp -+++ b/src/core/syncobjtimeline.cpp -@@ -117,6 +117,10 @@ void SyncTimeline::signal(uint64_t timelinePoint) - - void SyncTimeline::moveInto(uint64_t timelinePoint, const FileDescriptor &fd) - { -- drmSyncobjImportSyncFile(m_drmFd, m_handle, fd.get()); -+ uint32_t tempHandle = 0; -+ drmSyncobjCreate(m_drmFd, 0, &tempHandle); -+ drmSyncobjImportSyncFile(m_drmFd, tempHandle, fd.get()); -+ drmSyncobjTransfer(m_drmFd, m_handle, timelinePoint, tempHandle, 0, 0); -+ drmSyncobjDestroy(m_drmFd, tempHandle); - } - } --- -GitLab - - -From 463ae633e878004b1799f618641a0c44573c10f4 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl <xaver.hugl@gmail.com> -Date: Wed, 17 Apr 2024 03:26:34 +0200 -Subject: [PATCH 5/5] wayland/surface: fix the change signal for release points - not being emitted - -(cherry picked from commit eed7943939524895225ab4cf4eb3a1fa880b42bf) ---- - src/wayland/surface.cpp | 2 +- - src/wayland/surface_p.h | 1 - - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/src/wayland/surface.cpp b/src/wayland/surface.cpp -index 6a33c5fca10..6a77e98d0ee 100644 ---- a/src/wayland/surface.cpp -+++ b/src/wayland/surface.cpp -@@ -608,7 +608,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer); - const bool colorDescriptionChanged = next->colorDescriptionIsSet; - const bool presentationModeHintChanged = next->presentationModeHintIsSet; -- const bool bufferReleasePointChanged = next->releasePointIsSet; -+ const bool bufferReleasePointChanged = next->bufferIsSet && current->releasePoint != next->releasePoint; - - const QSizeF oldSurfaceSize = surfaceSize; - const QSize oldBufferSize = bufferSize; -diff --git a/src/wayland/surface_p.h b/src/wayland/surface_p.h -index 775f9d7bd2e..7bcf95c0bef 100644 ---- a/src/wayland/surface_p.h -+++ b/src/wayland/surface_p.h -@@ -59,7 +59,6 @@ struct SurfaceState - bool contentTypeIsSet = false; - bool presentationModeHintIsSet = false; - bool colorDescriptionIsSet = false; -- bool releasePointIsSet = false; - qint32 bufferScale = 1; - OutputTransform bufferTransform = OutputTransform::Normal; - wl_list frameCallbacks; --- -GitLab - diff --git a/overlays/kwin/default.nix b/overlays/kwin/default.nix deleted file mode 100644 index d766a6e..0000000 --- a/overlays/kwin/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -self: super: { - kdePackages = super.kdePackages.overrideScope (kde-self: kde-super: rec { - kwin = kde-super.kwin.overrideAttrs (oldAttrs: rec { - patches = oldAttrs.patches ++ [ - ./5511.patch # https://invent.kde.org/plasma/kwin/-/merge_requests/5511 - ]; - }); - }); -} \ No newline at end of file diff --git a/tips/debug_insecure_package.md b/tips/debug_insecure_package.md new file mode 100644 index 0000000..837ca9c --- /dev/null +++ b/tips/debug_insecure_package.md @@ -0,0 +1,30 @@ +## If package is marked as insecure + +Example: + +> error: Package 'nix-2.16.2' in /nix/store/nra828scc8qs92b9pxra5csqzffb6hpl-source/pkgs/tools/package-management/nix/default.nix:229 is marked as insecure, refusing to evaluate. +> +> Known issues: +> - CVE-2024-27297 + +```bash +nix path-info -r /run/current-system | grep nix-2.16.2 +``` +Result: +> [...] +> +> /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 +> +> [...] + +```bash +nix-store -q --referrers /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 +``` +Result: +> /nix/store/g4ss2h40n3j37bq20x1qw5s7nl82lch5-nix-2.16.2 +> +> /nix/store/72pfc05339izcwqhlbs8441brrdasas7-nix-2.16.2-dev +> +> /nix/store/ln2z5d5izn8icm3wx94ci13ad19lzjhr-nixd-1.2.3 + +nixd is not up to date and require nix 2.16.2 diff --git a/tips/distrobox/kde/.kde_bashrc b/tips/distrobox/kde/.kde_bashrc new file mode 100644 index 0000000..1167121 --- /dev/null +++ b/tips/distrobox/kde/.kde_bashrc @@ -0,0 +1,24 @@ +# Required for kde-builder command +if [[ $PATH != *".local/bin"* ]]; then + export PATH="$HOME/.local/bin:$PATH" +fi + +# Workaround for NixOS +# ENVs have nix store references and made conflict during build or run of KDE Apps, Shells, Frameworks +alias new_shell="env -u PATH -u QML2_IMPORT_PATH -u QT_PLUGIN_PATH -u NIXPKGS_QT6_QML_IMPORT_PATH -u XDG_CONFIG_DIRS bash -l" + +alias build_plasma_mobile="kde-builder plasma-mobile plasma-settings plasma-desktop kactivitymanagerd" + +function run_mobile() { + source "$HOME/kde/build/plasma-mobile/prefix.sh" + + QT_QPA_PLATFORM=offscreen plasma-mobile-envmanager --apply-settings + + # Environment variables + export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 + export QT_QUICK_CONTROLS_MOBILE=1 + export PLASMA_PLATFORM=phone:handheld + export QT_QUICK_CONTROLS_STYLE=org.kde.breeze + + QT_QPA_PLATFORM=wayland dbus-run-session kwin_wayland --xwayland "plasmashell -p org.kde.plasma.mobileshell" --width 360 --height 720 +} \ No newline at end of file diff --git a/tips/distrobox/kde/configure.sh b/tips/distrobox/kde/configure.sh new file mode 100755 index 0000000..f6e0812 --- /dev/null +++ b/tips/distrobox/kde/configure.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if ! grep -Fxq "source ~/.kde_bashrc" ~/.bashrc +then + cp .kde_bashrc ~/.kde_bashrc + echo "source ~/.kde_bashrc" > ~/.bashrc + source ~/.bashrc +fi + +echo "Installing kde-builder" +curl 'https://invent.kde.org/sdk/kde-builder/-/raw/master/scripts/initial_setup.sh?ref_type=heads' > ~/initial_setup.sh +bash ~/initial_setup.sh && rm ~/initial_setup.sh + +echo "Run initial setup from kde-builder" +kde-builder --initial-setup + +echo "Install missing dependencies" +sudo dnf install qt6-*-devel librsvg2-devel + +echo "Configuration DONE" \ No newline at end of file diff --git a/tips/distrobox/kde/distrobox.ini b/tips/distrobox/kde/distrobox.ini new file mode 100644 index 0000000..180ff56 --- /dev/null +++ b/tips/distrobox/kde/distrobox.ini @@ -0,0 +1,6 @@ +[kdedev] +image=quay.io/fedora/fedora:latest +home="${HOME}/.distrobox_home/kdedev" +nvidia=true +root=false +pull=true diff --git a/tips/distrobox/kde/use_distrobox.md b/tips/distrobox/kde/use_distrobox.md new file mode 100644 index 0000000..deda652 --- /dev/null +++ b/tips/distrobox/kde/use_distrobox.md @@ -0,0 +1,19 @@ +# How to develop on KDE + +## First configuration + +1. `distrobox assemble` + > You can add --replace to recreate distrobox container +2. `distrobox enter kdedev` +3. `bash configure.sh` +4. `kde-builder run solid` + > You use NixOS ? It's necessary to run `new_shell` alias before. + > The alias unset all nixos env variables with nix store references to avoid conflicts with build or run of KDE Shells/Apps/Tools. + +## Usefull config in ~/.config/kdesrc-buildrc + +Autogenerate editor configuration + +- generate-clion-project-config +- generate-vscode-project-config +- generate-qtcreator-project-config diff --git a/tips/how_to_test_pr.md b/tips/how_to_test_pr.md new file mode 100644 index 0000000..3b4773e --- /dev/null +++ b/tips/how_to_test_pr.md @@ -0,0 +1,36 @@ +# Example for ollama + +```nix +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.modules.system.server.ollama; + nvidiaEnabled = config.modules.system.hardware.nvidia.enable; + nixpkgsPr = builtins.fetchTarball { + url = "https://github.com/abysssol/nixpkgs/archive/ollama-driver-runpath.tar.gz"; + sha256 = "1ixfvdpi2v4r9yrkvqnfk9whs8lyjhrkdph47bcznh8ak9aipr8p"; + }; +in +{ + disabledModules = [ "services/misc/ollama.nix" ]; + imports = [ + (import "${nixpkgsPr}/nixos/modules/services/misc/ollama.nix") + ]; + + options.modules.system.server.ollama = { + enable = mkEnableOption '' + Enable ollama with my custom configurations + ''; + }; + config = mkIf cfg.enable { + services.ollama = { + enable = true; + + package = (import nixpkgsPr { inherit (pkgs) system; config.allowUnfree = true; }).ollama; + + acceleration = if nvidiaEnabled then "cuda" else null; + }; + }; +} +``` diff --git a/tips/test_on_vm.md b/tips/test_on_vm.md new file mode 100644 index 0000000..ddaab4b --- /dev/null +++ b/tips/test_on_vm.md @@ -0,0 +1,24 @@ +## Configure VM + +Configure VM +```nix +users.users.<user>.initialPassword = "<password>"; +virtualisation.vmVariant = { + # following configuration is added only when building VM with build-vm + virtualisation = { + memorySize = <RAM in MiB>; # Use 8192MiB memory. + cores = <CPU Core number>; + # And more here https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/virtualisation/qemu-vm.nix + }; +}; +``` + +Build +```bash +nixos-rebuild build-vm --flake .#nixos-test +``` + +Run +```bash +./result/bin/run-nixos-vm-vm +```