also allow for dynamic label resource deduplication

use a simple counter instead of a timestamp to allow the same
widget on a different monitor to reuse a text cmd resource.

I didn't do this before, because I was worried about two labels that use
the same command with different reload times. I mitigated that by just
incrementing the revision by the time interval. This should be sufficent
to avoid clashes.
This commit is contained in:
Maximilian Seidler 2025-09-29 18:03:56 +02:00
parent 28f961a111
commit 4734f8bcd4
4 changed files with 32 additions and 17 deletions

View file

@ -29,12 +29,12 @@ ResourceID CAsyncResourceManager::resourceIDForTextRequest(const CTextResource::
return scopeResourceID(1, H1 ^ (H2 << 1) ^ (H3 << 2) ^ (H4 << 3));
}
ResourceID CAsyncResourceManager::resourceIDForTextCmdRequest(const CTextResource::STextResourceData& s) {
return scopeResourceID(2, resourceIDForTextRequest(s) ^ std::hash<size_t>{}(std::chrono::system_clock::now().time_since_epoch().count()));
ResourceID CAsyncResourceManager::resourceIDForTextCmdRequest(const CTextResource::STextResourceData& s, size_t revision) {
return scopeResourceID(2, resourceIDForTextRequest(s) ^ (revision << 32));
}
ResourceID CAsyncResourceManager::resourceIDForImageRequest(const std::string& path, size_t revision) {
return scopeResourceID(3, std::hash<std::string>{}(path) ^ std::hash<size_t>{}(revision));
return scopeResourceID(3, std::hash<std::string>{}(path) ^ (revision << 32));
}
ResourceID CAsyncResourceManager::resourceIDForScreencopy(const std::string& port) {
@ -44,29 +44,29 @@ ResourceID CAsyncResourceManager::resourceIDForScreencopy(const std::string& por
ResourceID CAsyncResourceManager::requestText(const CTextResource::STextResourceData& params, const AWP<IWidget>& widget) {
const auto RESOURCEID = resourceIDForTextRequest(params);
if (request(RESOURCEID, widget)) {
Debug::log(TRACE, "Text resource \"{}\" (resourceID: {}) already requested!", params.text, RESOURCEID);
Debug::log(TRACE, "Reusing text resource \"{}\" (resourceID: {}, widget: 0x{})", params.text, RESOURCEID, (uintptr_t)widget.get());
return RESOURCEID;
}
auto resource = makeAtomicShared<CTextResource>(CTextResource::STextResourceData{params});
CAtomicSharedPointer<IAsyncResource> resourceGeneric{resource};
Debug::log(LOG, "Requesting text resource \"{}\" (resourceID: {})", params.text, RESOURCEID);
Debug::log(TRACE, "Requesting text resource \"{}\" (resourceID: {}, widget: 0x{})", params.text, RESOURCEID, (uintptr_t)widget.get());
enqueue(RESOURCEID, resourceGeneric, widget);
return RESOURCEID;
}
ResourceID CAsyncResourceManager::requestTextCmd(const CTextResource::STextResourceData& params, const AWP<IWidget>& widget) {
const auto RESOURCEID = resourceIDForTextCmdRequest(params);
ResourceID CAsyncResourceManager::requestTextCmd(const CTextResource::STextResourceData& params, size_t revision, const AWP<IWidget>& widget) {
const auto RESOURCEID = resourceIDForTextCmdRequest(params, revision);
if (request(RESOURCEID, widget)) {
Debug::log(TRACE, "Text cmd resource \"{}\" (resourceID: {}) already requested!", params.text, RESOURCEID);
Debug::log(TRACE, "Reusing text cmd resource \"{}\" revision {} (resourceID: {}, widget: 0x{})", params.text, revision, RESOURCEID, (uintptr_t)widget.get());
return RESOURCEID;
}
auto resource = makeAtomicShared<CTextCmdResource>(CTextResource::STextResourceData{params});
CAtomicSharedPointer<IAsyncResource> resourceGeneric{resource};
Debug::log(LOG, "Enqueued text cmd resource `{}` (resourceID: {})", params.text, RESOURCEID);
Debug::log(TRACE, "Requesting text cmd resource \"{}\" revision {} (resourceID: {}, widget: 0x{})", params.text, revision, RESOURCEID, (uintptr_t)widget.get());
enqueue(RESOURCEID, resourceGeneric, widget);
return RESOURCEID;
}
@ -74,14 +74,14 @@ ResourceID CAsyncResourceManager::requestTextCmd(const CTextResource::STextResou
ResourceID CAsyncResourceManager::requestImage(const std::string& path, size_t revision, const AWP<IWidget>& widget) {
const auto RESOURCEID = resourceIDForImageRequest(path, revision);
if (request(RESOURCEID, widget)) {
Debug::log(TRACE, "Image resource {} revision {} (resourceID: {}) already requested!", path, revision, RESOURCEID);
Debug::log(TRACE, "Reusing image resource {} revision {} (resourceID: {}, widget: 0x{})", path, revision, RESOURCEID, (uintptr_t)widget.get());
return RESOURCEID;
}
auto resource = makeAtomicShared<CImageResource>(absolutePath(path, ""));
CAtomicSharedPointer<IAsyncResource> resourceGeneric{resource};
Debug::log(LOG, "Image resource {} revision {} (resourceID: {})", path, revision, RESOURCEID);
Debug::log(TRACE, "Requesting image resource {} revision {} (resourceID: {}, widget: 0x{})", path, revision, RESOURCEID, (uintptr_t)widget.get());
enqueue(RESOURCEID, resourceGeneric, widget);
return RESOURCEID;
}
@ -139,7 +139,11 @@ void CAsyncResourceManager::enqueueScreencopyFrames() {
}
void CAsyncResourceManager::screencopyToTexture(const CScreencopyFrame& scFrame) {
RASSERT(scFrame.m_ready && m_assets.contains(scFrame.m_resourceID), "Logic error in screencopy gathering.");
if (!scFrame.m_ready || !m_assets.contains(scFrame.m_resourceID)) {
Debug::log(ERR, "Bogus call to CAsyncResourceManager::screencopyToTexture. This is a bug!");
return;
}
m_assets[scFrame.m_resourceID].texture = scFrame.m_asset;
Debug::log(TRACE, "Done sc frame {}", scFrame.m_resourceID);
@ -147,7 +151,7 @@ void CAsyncResourceManager::screencopyToTexture(const CScreencopyFrame& scFrame)
std::erase_if(m_scFrames, [&scFrame](const auto& f) { return f.get() == &scFrame; });
if (m_scFrames.empty()) {
Debug::log(TRACE, "Gathered all screencopy frames - removing dmabuf listeners");
Debug::log(LOG, "Gathered all screencopy frames - removing dmabuf listeners");
g_pHyprlock->removeDmabufListener();
}
}

View file

@ -27,7 +27,8 @@ class CAsyncResourceManager {
// Those are hash functions that return the id for a requested resource.
static ResourceID resourceIDForTextRequest(const CTextResource::STextResourceData& s);
static ResourceID resourceIDForTextCmdRequest(const CTextResource::STextResourceData& s);
// Consumer needs to increment the revision parameter to get a new command evaluation.
static ResourceID resourceIDForTextCmdRequest(const CTextResource::STextResourceData& s, size_t revision);
// Image paths may be file system links, thus this function supports a revision parameter that gets factored into the resource id.
static ResourceID resourceIDForImageRequest(const std::string& path, size_t revision);
static ResourceID resourceIDForScreencopy(const std::string& port);
@ -42,7 +43,7 @@ class CAsyncResourceManager {
ResourceID requestText(const CTextResource::STextResourceData& params, const AWP<IWidget>& widget);
// Same as requestText but substitute the text with what launching sh -c request.text returns.
ResourceID requestTextCmd(const CTextResource::STextResourceData& params, const AWP<IWidget>& widget);
ResourceID requestTextCmd(const CTextResource::STextResourceData& params, size_t revision, const AWP<IWidget>& widget);
ResourceID requestImage(const std::string& path, size_t revision, const AWP<IWidget>& widget);
ASP<CTexture> getAssetByID(ResourceID id);

View file

@ -43,7 +43,12 @@ void CLabel::onTimerUpdate() {
request.text = label.formatted;
AWP<IWidget> widget(m_self);
pendingResourceID = (label.cmd) ? g_asyncResourceManager->requestTextCmd(request, widget.lock()) : g_asyncResourceManager->requestText(request, widget.lock());
if (label.cmd) {
// Don't increment by one to avoid clashes with multiple widget using the same label command.
m_dynamicRevision += label.updateEveryMs;
pendingResourceID = g_asyncResourceManager->requestTextCmd(request, m_dynamicRevision, widget.lock());
} else
pendingResourceID = g_asyncResourceManager->requestText(request, widget.lock());
}
void CLabel::plantTimer() {
@ -94,7 +99,10 @@ void CLabel::configure(const std::unordered_map<std::string, std::any>& props, c
pos = configPos; // Label size not known yet
resourceID = (label.cmd) ? g_asyncResourceManager->requestTextCmd(request, nullptr) : g_asyncResourceManager->requestText(request, nullptr);
if (label.cmd) {
resourceID = g_asyncResourceManager->requestTextCmd(request, m_dynamicRevision, nullptr);
} else
resourceID = g_asyncResourceManager->requestText(request, nullptr);
plantTimer();
}

View file

@ -51,6 +51,8 @@ class CLabel : public IWidget {
ResourceID resourceID = 0;
ResourceID pendingResourceID = 0;
size_t m_dynamicRevision = 0;
ASP<CTexture> asset = nullptr;
std::string outputStringPort;