Skip to content

Commit

Permalink
core: fix background screenshot on nvidia (#656)
Browse files Browse the repository at this point in the history
Fixes DMA buffer screencopy on nvidia cards. Additionally adds shm screencopy as an option
  • Loading branch information
PaideiaDilemma authored Jan 24, 2025
1 parent 742eb98 commit 07b5e1b
Show file tree
Hide file tree
Showing 13 changed files with 615 additions and 273 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ compile_commands.json
protocols/*.cpp
protocols/*.hpp
*.kdev4
.gdb_history
1 change: 1 addition & 0 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ void CConfigManager::init() {
m_config.addConfigValue("general:ignore_empty_input", Hyprlang::INT{0});
m_config.addConfigValue("general:immediate_render", Hyprlang::INT{0});
m_config.addConfigValue("general:fractional_scaling", Hyprlang::INT{2});
m_config.addConfigValue("general:screencopy_mode", Hyprlang::INT{0});

m_config.addConfigValue("auth:pam:enabled", Hyprlang::INT{1});
m_config.addConfigValue("auth:pam:module", Hyprlang::STRING{"hyprlock"});
Expand Down
6 changes: 6 additions & 0 deletions src/core/hyprlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ void CHyprlock::run() {
else if (IFACE == zwlr_screencopy_manager_v1_interface.name)
m_sWaylandState.screencopy =
makeShared<CCZwlrScreencopyManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &zwlr_screencopy_manager_v1_interface, 3));
else if (IFACE == wl_shm_interface.name)
m_sWaylandState.shm = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_shm_interface, 1));
else
return;

Expand Down Expand Up @@ -834,6 +836,10 @@ SP<CCZwlrScreencopyManagerV1> CHyprlock::getScreencopy() {
return m_sWaylandState.screencopy;
}

SP<CCWlShm> CHyprlock::getShm() {
return m_sWaylandState.shm;
}

void CHyprlock::attemptRestoreOnDeath() {
if (m_bTerminate || m_sCurrentDesktop != "Hyprland")
return;
Expand Down
2 changes: 2 additions & 0 deletions src/core/hyprlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class CHyprlock {
SP<CCWpFractionalScaleManagerV1> getFractionalMgr();
SP<CCWpViewporter> getViewporter();
SP<CCZwlrScreencopyManagerV1> getScreencopy();
SP<CCWlShm> getShm();

int32_t m_iKeebRepeatRate = 25;
int32_t m_iKeebRepeatDelay = 600;
Expand Down Expand Up @@ -130,6 +131,7 @@ class CHyprlock {
SP<CCWpFractionalScaleManagerV1> fractional = nullptr;
SP<CCWpViewporter> viewporter = nullptr;
SP<CCZwlrScreencopyManagerV1> screencopy = nullptr;
SP<CCWlShm> shm = nullptr;
} m_sWaylandState;

void addDmabufListener();
Expand Down
41 changes: 40 additions & 1 deletion src/helpers/MiscFunctions.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#include <filesystem>
#include <algorithm>
#include <cmath>
#include <fcntl.h>
#include "MiscFunctions.hpp"
#include "Log.hpp"
#include <hyprutils/string/String.hpp>
#include <unistd.h>

using namespace Hyprutils::String;

Expand All @@ -12,7 +15,7 @@ std::string absolutePath(const std::string& rawpath, const std::string& currentD
// Handling where rawpath starts with '~'
if (!rawpath.empty() && rawpath[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
path = std::filesystem::path(ENVHOME) / path.relative_path().string().substr(2);
path = std::filesystem::path(ENVHOME) / path.relative_path().string().substr(2);
}

// Handling e.g. ./, ../
Expand Down Expand Up @@ -97,4 +100,40 @@ int64_t configStringToInt(const std::string& VALUE) {
} catch (std::exception& e) { throw std::invalid_argument(std::string{"stoll threw: "} + e.what()); }

return 0;
}

int createPoolFile(size_t size, std::string& name) {
const auto XDGRUNTIMEDIR = getenv("XDG_RUNTIME_DIR");
if (!XDGRUNTIMEDIR) {
Debug::log(CRIT, "XDG_RUNTIME_DIR not set!");
return -1;
}

name = std::string(XDGRUNTIMEDIR) + "/.hyprlock_sc_XXXXXX";

const auto FD = mkstemp((char*)name.c_str());
if (FD < 0) {
Debug::log(CRIT, "createPoolFile: fd < 0");
return -1;
}
// set cloexec
long flags = fcntl(FD, F_GETFD);
if (flags == -1) {
close(FD);
return -1;
}

if (fcntl(FD, F_SETFD, flags | FD_CLOEXEC) == -1) {
close(FD);
Debug::log(CRIT, "createPoolFile: fcntl < 0");
return -1;
}

if (ftruncate(FD, size) < 0) {
close(FD);
Debug::log(CRIT, "createPoolFile: ftruncate < 0");
return -1;
}

return FD;
}
1 change: 1 addition & 0 deletions src/helpers/MiscFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

std::string absolutePath(const std::string&, const std::string&);
int64_t configStringToInt(const std::string& VALUE);
int createPoolFile(size_t size, std::string& name);
16 changes: 8 additions & 8 deletions src/renderer/AsyncResourceGatherer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ using namespace Hyprgraphics;

CAsyncResourceGatherer::CAsyncResourceGatherer() {
if (g_pHyprlock->getScreencopy())
enqueueDMAFrames();
enqueueScreencopyFrames();

initialGatherThread = std::thread([this]() { this->gather(); });
asyncLoopThread = std::thread([this]() { this->asyncAssetSpinLock(); });
}

void CAsyncResourceGatherer::enqueueDMAFrames() {
void CAsyncResourceGatherer::enqueueScreencopyFrames() {
// some things can't be done async :(
// gather background textures when needed

Expand Down Expand Up @@ -56,7 +56,7 @@ void CAsyncResourceGatherer::enqueueDMAFrames() {

const auto PMONITOR = MON->get();

dmas.emplace_back(std::make_unique<CDMAFrame>(PMONITOR));
scframes.emplace_back(std::make_unique<CScreencopyFrame>(PMONITOR));
}
}

Expand All @@ -73,9 +73,9 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
}
};

for (auto& dma : dmas) {
if (id == dma->resourceID)
return dma->asset.ready ? &dma->asset : nullptr;
for (auto& frame : scframes) {
if (id == frame->m_resourceID)
return frame->m_asset.ready ? &frame->m_asset : nullptr;
}

return nullptr;
Expand Down Expand Up @@ -130,7 +130,7 @@ void CAsyncResourceGatherer::gather() {
}
}

while (!g_pHyprlock->m_bTerminate && std::any_of(dmas.begin(), dmas.end(), [](const auto& d) { return !d->asset.ready; })) {
while (!g_pHyprlock->m_bTerminate && std::any_of(scframes.begin(), scframes.end(), [](const auto& d) { return !d->m_asset.ready; })) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}

Expand Down Expand Up @@ -216,7 +216,7 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
target.id = rq.id;

const int FONTSIZE = rq.props.contains("font_size") ? std::any_cast<int>(rq.props.at("font_size")) : 16;
const CHyprColor FONTCOLOR = rq.props.contains("color") ? std::any_cast<CHyprColor>(rq.props.at("color")) : CHyprColor(1.0, 1.0, 1.0, 1.0);
const CHyprColor FONTCOLOR = rq.props.contains("color") ? std::any_cast<CHyprColor>(rq.props.at("color")) : CHyprColor(1.0, 1.0, 1.0, 1.0);
const std::string FONTFAMILY = rq.props.contains("font_family") ? std::any_cast<std::string>(rq.props.at("font_family")) : "Sans";
const bool ISCMD = rq.props.contains("cmd") ? std::any_cast<bool>(rq.props.at("cmd")) : false;

Expand Down
6 changes: 3 additions & 3 deletions src/renderer/AsyncResourceGatherer.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "DMAFrame.hpp"
#include "Screencopy.hpp"
#include <thread>
#include <atomic>
#include <vector>
Expand Down Expand Up @@ -75,13 +75,13 @@ class CAsyncResourceGatherer {
Vector2D size;
};

std::vector<std::unique_ptr<CDMAFrame>> dmas;
std::vector<std::unique_ptr<CScreencopyFrame>> scframes;

std::vector<SPreloadTarget> preloadTargets;
std::mutex preloadTargetsMutex;

std::unordered_map<std::string, SPreloadedAsset> assets;

void gather();
void enqueueDMAFrames();
void enqueueScreencopyFrames();
};
Loading

0 comments on commit 07b5e1b

Please sign in to comment.