mirror of
https://github.com/hyprwm/hyprgraphics.git
synced 2025-12-20 08:40:04 +01:00
asyncResourceGatherer: add new module (#36)
Some checks are pending
Some checks are pending
Adds a new module based on the hyprlock gatherer --------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
parent
aa9d14963b
commit
b86c4d9ed3
12 changed files with 476 additions and 8 deletions
4
.github/workflows/arch.yml
vendored
4
.github/workflows/arch.yml
vendored
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
pacman --noconfirm --noprogressbar -Syyu
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp libpng
|
pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang libc++ pango pixman cairo hyprutils libjpeg-turbo libjxl libwebp libpng ttf-dejavu
|
||||||
|
|
||||||
- name: Build hyprgraphics with gcc
|
- name: Build hyprgraphics with gcc
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||||
pacman --noconfirm --noprogressbar -Syyu
|
pacman --noconfirm --noprogressbar -Syyu
|
||||||
pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp libpng
|
pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang libc++ pango pixman cairo hyprutils libjpeg-turbo libjxl libwebp libpng ttf-dejavu
|
||||||
|
|
||||||
- name: Build hyprgraphics with clang
|
- name: Build hyprgraphics with clang
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ pkg_check_modules(
|
||||||
IMPORTED_TARGET
|
IMPORTED_TARGET
|
||||||
pixman-1
|
pixman-1
|
||||||
cairo
|
cairo
|
||||||
|
pangocairo
|
||||||
hyprutils
|
hyprutils
|
||||||
libjpeg
|
libjpeg
|
||||||
libwebp
|
libwebp
|
||||||
|
|
@ -113,6 +114,13 @@ add_test(
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
|
||||||
COMMAND hyprgraphics_image "image")
|
COMMAND hyprgraphics_image "image")
|
||||||
add_dependencies(tests hyprgraphics_image)
|
add_dependencies(tests hyprgraphics_image)
|
||||||
|
add_executable(hyprgraphics_arg "tests/arg.cpp")
|
||||||
|
target_link_libraries(hyprgraphics_arg PRIVATE hyprgraphics PkgConfig::deps)
|
||||||
|
add_test(
|
||||||
|
NAME "ARG"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
|
||||||
|
COMMAND hyprgraphics_arg "image")
|
||||||
|
add_dependencies(tests hyprgraphics_arg)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
install(TARGETS hyprgraphics)
|
install(TARGETS hyprgraphics)
|
||||||
|
|
|
||||||
12
flake.lock
generated
12
flake.lock
generated
|
|
@ -10,11 +10,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1749135356,
|
"lastModified": 1756117388,
|
||||||
"narHash": "sha256-Q8mAKMDsFbCEuq7zoSlcTuxgbIBVhfIYpX0RjE32PS0=",
|
"narHash": "sha256-oRDel6pNl/T2tI+nc/USU9ZP9w08dxtl7hiZxa0C/Wc=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprutils",
|
"repo": "hyprutils",
|
||||||
"rev": "e36db00dfb3a3d3fdcc4069cb292ff60d2699ccb",
|
"rev": "b2ae3204845f5f2f79b4703b441252d8ad2ecfd0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -25,11 +25,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748929857,
|
"lastModified": 1757745802,
|
||||||
"narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=",
|
"narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4",
|
"rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
38
include/hyprgraphics/resource/AsyncResourceGatherer.hpp
Normal file
38
include/hyprgraphics/resource/AsyncResourceGatherer.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include "../cairo/CairoSurface.hpp"
|
||||||
|
#include "./resources/AsyncResource.hpp"
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
|
||||||
|
namespace Hyprgraphics {
|
||||||
|
class CAsyncResourceGatherer {
|
||||||
|
public:
|
||||||
|
CAsyncResourceGatherer();
|
||||||
|
~CAsyncResourceGatherer();
|
||||||
|
|
||||||
|
void enqueue(Hyprutils::Memory::CAtomicSharedPointer<IAsyncResource> resource);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_gatherThread;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
std::mutex requestMutex;
|
||||||
|
std::condition_variable requestsCV;
|
||||||
|
|
||||||
|
bool exit = false;
|
||||||
|
bool needsToProcess = false;
|
||||||
|
} m_asyncLoopState;
|
||||||
|
|
||||||
|
std::vector<Hyprutils::Memory::CAtomicSharedPointer<IAsyncResource>> m_targetsToLoad;
|
||||||
|
std::mutex m_targetsToLoadMutex;
|
||||||
|
|
||||||
|
//
|
||||||
|
void asyncAssetSpinLock();
|
||||||
|
void wakeUpMainThread();
|
||||||
|
};
|
||||||
|
}
|
||||||
33
include/hyprgraphics/resource/resources/AsyncResource.hpp
Normal file
33
include/hyprgraphics/resource/resources/AsyncResource.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprutils/memory/UniquePtr.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
|
#include "../../cairo/CairoSurface.hpp"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace Hyprgraphics {
|
||||||
|
class IAsyncResource {
|
||||||
|
public:
|
||||||
|
IAsyncResource() = default;
|
||||||
|
virtual ~IAsyncResource() = default;
|
||||||
|
|
||||||
|
virtual void render() = 0;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// this signal fires on the worker thread. **Really** consider making this signal handler call something to wake your
|
||||||
|
// main event loop up and do things there.
|
||||||
|
Hyprutils::Signal::CSignalT<> finished;
|
||||||
|
} m_events;
|
||||||
|
|
||||||
|
// you probably shouldn't use this but it's here just in case.
|
||||||
|
std::atomic<bool> m_ready = false;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// This pointer can be made not thread safe as after .finished the worker thread will not touch it anymore
|
||||||
|
// and before that you shouldnt touch it either
|
||||||
|
Hyprutils::Memory::CSharedPointer<CCairoSurface> cairoSurface;
|
||||||
|
Hyprutils::Math::Vector2D pixelSize;
|
||||||
|
} m_asset;
|
||||||
|
};
|
||||||
|
}
|
||||||
27
include/hyprgraphics/resource/resources/ImageResource.hpp
Normal file
27
include/hyprgraphics/resource/resources/ImageResource.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AsyncResource.hpp"
|
||||||
|
#include "../../color/Color.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
|
namespace Hyprgraphics {
|
||||||
|
class CImageResource : public IAsyncResource {
|
||||||
|
public:
|
||||||
|
enum eTextAlignmentMode : uint8_t {
|
||||||
|
TEXT_ALIGN_LEFT = 0,
|
||||||
|
TEXT_ALIGN_CENTER,
|
||||||
|
TEXT_ALIGN_RIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
CImageResource(const std::string& path);
|
||||||
|
virtual ~CImageResource() = default;
|
||||||
|
|
||||||
|
virtual void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_path;
|
||||||
|
};
|
||||||
|
};
|
||||||
36
include/hyprgraphics/resource/resources/TextResource.hpp
Normal file
36
include/hyprgraphics/resource/resources/TextResource.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AsyncResource.hpp"
|
||||||
|
#include "../../color/Color.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
|
namespace Hyprgraphics {
|
||||||
|
class CTextResource : public IAsyncResource {
|
||||||
|
public:
|
||||||
|
enum eTextAlignmentMode : uint8_t {
|
||||||
|
TEXT_ALIGN_LEFT = 0,
|
||||||
|
TEXT_ALIGN_CENTER,
|
||||||
|
TEXT_ALIGN_RIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct STextResourceData {
|
||||||
|
std::string text = "Sample Text";
|
||||||
|
std::string font = "Sans Serif";
|
||||||
|
size_t fontSize = 16;
|
||||||
|
CColor color = CColor{CColor::SSRGB{.r = 1.F, .g = 1.F, .b = 1.F}};
|
||||||
|
eTextAlignmentMode align = TEXT_ALIGN_LEFT;
|
||||||
|
std::optional<Hyprutils::Math::Vector2D> maxSize = std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
CTextResource(STextResourceData&& data);
|
||||||
|
virtual ~CTextResource() = default;
|
||||||
|
|
||||||
|
virtual void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
STextResourceData m_data;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
libjxl,
|
libjxl,
|
||||||
libspng,
|
libspng,
|
||||||
libwebp,
|
libwebp,
|
||||||
|
pango,
|
||||||
pixman,
|
pixman,
|
||||||
version ? "git",
|
version ? "git",
|
||||||
doCheck ? false,
|
doCheck ? false,
|
||||||
|
|
@ -55,6 +56,7 @@ in
|
||||||
libjxl
|
libjxl
|
||||||
libspng
|
libspng
|
||||||
libwebp
|
libwebp
|
||||||
|
pango
|
||||||
pixman
|
pixman
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
63
src/resource/AsyncResourceGatherer.cpp
Normal file
63
src/resource/AsyncResourceGatherer.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include <hyprgraphics/resource/AsyncResourceGatherer.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprgraphics;
|
||||||
|
|
||||||
|
CAsyncResourceGatherer::CAsyncResourceGatherer() {
|
||||||
|
m_gatherThread = std::thread([this]() { asyncAssetSpinLock(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
CAsyncResourceGatherer::~CAsyncResourceGatherer() {
|
||||||
|
m_asyncLoopState.exit = true;
|
||||||
|
wakeUpMainThread();
|
||||||
|
|
||||||
|
if (m_gatherThread.joinable())
|
||||||
|
m_gatherThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAsyncResourceGatherer::wakeUpMainThread() {
|
||||||
|
m_asyncLoopState.needsToProcess = true;
|
||||||
|
m_asyncLoopState.requestsCV.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAsyncResourceGatherer::enqueue(Hyprutils::Memory::CAtomicSharedPointer<IAsyncResource> resource) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lg(m_targetsToLoadMutex);
|
||||||
|
m_targetsToLoad.emplace_back(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
wakeUpMainThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAsyncResourceGatherer::asyncAssetSpinLock() {
|
||||||
|
while (!m_asyncLoopState.exit) {
|
||||||
|
|
||||||
|
std::unique_lock lk(m_asyncLoopState.requestMutex);
|
||||||
|
if (!m_asyncLoopState.needsToProcess) // avoid a lock if a thread managed to request something already since we .unlock()ed
|
||||||
|
m_asyncLoopState.requestsCV.wait_for(lk, std::chrono::seconds(5), [this] { return m_asyncLoopState.needsToProcess; }); // wait for events
|
||||||
|
|
||||||
|
if (m_asyncLoopState.exit)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_asyncLoopState.needsToProcess = false;
|
||||||
|
lk.unlock();
|
||||||
|
m_targetsToLoadMutex.lock();
|
||||||
|
|
||||||
|
if (m_targetsToLoad.empty()) {
|
||||||
|
m_targetsToLoadMutex.unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto requests = m_targetsToLoad;
|
||||||
|
m_targetsToLoad.clear();
|
||||||
|
|
||||||
|
m_targetsToLoadMutex.unlock();
|
||||||
|
|
||||||
|
// process requests
|
||||||
|
for (auto& r : requests) {
|
||||||
|
r->render();
|
||||||
|
|
||||||
|
r->m_ready = true;
|
||||||
|
r->m_events.finished.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/resource/resources/ImageResource.cpp
Normal file
21
src/resource/resources/ImageResource.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <hyprgraphics/resource/resources/ImageResource.hpp>
|
||||||
|
#include <hyprgraphics/image/Image.hpp>
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
using namespace Hyprgraphics;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
CImageResource::CImageResource(const std::string& path) : m_path(path) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CImageResource::render() {
|
||||||
|
auto image = CImage(m_path);
|
||||||
|
|
||||||
|
m_asset.cairoSurface = image.cairoSurface();
|
||||||
|
m_asset.pixelSize = m_asset.cairoSurface && m_asset.cairoSurface->cairo() ? m_asset.cairoSurface->size() : Hyprutils::Math::Vector2D{};
|
||||||
|
}
|
||||||
101
src/resource/resources/TextResource.cpp
Normal file
101
src/resource/resources/TextResource.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include <hyprgraphics/resource/resources/TextResource.hpp>
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
using namespace Hyprgraphics;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
CTextResource::CTextResource(CTextResource::STextResourceData&& data) : m_data(std::move(data)) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextResource::render() {
|
||||||
|
auto CAIROSURFACE = makeUnique<CCairoSurface>(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */));
|
||||||
|
auto CAIRO = cairo_create(CAIROSURFACE->cairo());
|
||||||
|
|
||||||
|
PangoLayout* layout = pango_cairo_create_layout(CAIRO);
|
||||||
|
|
||||||
|
PangoFontDescription* fontDesc = pango_font_description_from_string(m_data.font.c_str());
|
||||||
|
pango_font_description_set_size(fontDesc, m_data.fontSize * PANGO_SCALE);
|
||||||
|
pango_layout_set_font_description(layout, fontDesc);
|
||||||
|
pango_font_description_free(fontDesc);
|
||||||
|
|
||||||
|
cairo_font_options_t* options = cairo_font_options_create();
|
||||||
|
cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GOOD);
|
||||||
|
pango_cairo_context_set_font_options(pango_layout_get_context(layout), options);
|
||||||
|
cairo_font_options_destroy(options);
|
||||||
|
|
||||||
|
PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
|
||||||
|
|
||||||
|
switch (m_data.align) {
|
||||||
|
case TEXT_ALIGN_LEFT: break;
|
||||||
|
case TEXT_ALIGN_CENTER: pangoAlign = PANGO_ALIGN_CENTER; break;
|
||||||
|
case TEXT_ALIGN_RIGHT: pangoAlign = PANGO_ALIGN_RIGHT; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pango_layout_set_alignment(layout, pangoAlign);
|
||||||
|
|
||||||
|
PangoAttrList* attrList = nullptr;
|
||||||
|
GError* gError = nullptr;
|
||||||
|
char* buf = nullptr;
|
||||||
|
if (pango_parse_markup(m_data.text.c_str(), -1, 0, &attrList, &buf, nullptr, &gError))
|
||||||
|
pango_layout_set_text(layout, buf, -1);
|
||||||
|
else {
|
||||||
|
g_error_free(gError);
|
||||||
|
pango_layout_set_text(layout, m_data.text.c_str(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attrList)
|
||||||
|
attrList = pango_attr_list_new();
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
pango_attr_list_insert(attrList, pango_attr_scale_new(1));
|
||||||
|
pango_layout_set_attributes(layout, attrList);
|
||||||
|
pango_attr_list_unref(attrList);
|
||||||
|
|
||||||
|
int layoutWidth, layoutHeight;
|
||||||
|
pango_layout_get_size(layout, &layoutWidth, &layoutHeight);
|
||||||
|
|
||||||
|
if (m_data.maxSize) {
|
||||||
|
layoutWidth = std::min(layoutWidth, sc<int>(m_data.maxSize->x * PANGO_SCALE));
|
||||||
|
layoutHeight = std::min(layoutHeight, sc<int>(m_data.maxSize->y * PANGO_SCALE));
|
||||||
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||||
|
pango_layout_set_width(layout, layoutWidth);
|
||||||
|
pango_layout_set_height(layout, layoutHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: avoid this?
|
||||||
|
cairo_destroy(CAIRO);
|
||||||
|
|
||||||
|
CAIROSURFACE.reset();
|
||||||
|
|
||||||
|
m_asset.cairoSurface = makeShared<CCairoSurface>(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layoutWidth / PANGO_SCALE, layoutHeight / PANGO_SCALE));
|
||||||
|
CAIRO = cairo_create(m_asset.cairoSurface->cairo());
|
||||||
|
|
||||||
|
// clear the pixmap
|
||||||
|
cairo_save(CAIRO);
|
||||||
|
cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR);
|
||||||
|
cairo_paint(CAIRO);
|
||||||
|
cairo_restore(CAIRO);
|
||||||
|
|
||||||
|
// render the thing
|
||||||
|
const auto RGB = m_data.color.asRgb();
|
||||||
|
cairo_set_source_rgba(CAIRO, RGB.r, RGB.g, RGB.b, 1.F);
|
||||||
|
|
||||||
|
cairo_move_to(CAIRO, 0, 0);
|
||||||
|
pango_cairo_show_layout(CAIRO, layout);
|
||||||
|
|
||||||
|
g_object_unref(layout);
|
||||||
|
|
||||||
|
cairo_surface_flush(m_asset.cairoSurface->cairo());
|
||||||
|
|
||||||
|
m_asset.pixelSize = {layoutWidth / (double)PANGO_SCALE, layoutHeight / (double)PANGO_SCALE};
|
||||||
|
|
||||||
|
cairo_destroy(CAIRO);
|
||||||
|
}
|
||||||
139
tests/arg.cpp
Normal file
139
tests/arg.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <print>
|
||||||
|
#include <format>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <hyprgraphics/resource/AsyncResourceGatherer.hpp>
|
||||||
|
#include <hyprgraphics/resource/resources/TextResource.hpp>
|
||||||
|
#include <hyprgraphics/resource/resources/ImageResource.hpp>
|
||||||
|
#include <hyprutils/memory/UniquePtr.hpp>
|
||||||
|
#include <hyprutils/memory/Atomic.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include "shared.hpp"
|
||||||
|
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
using namespace Hyprutils::Math;
|
||||||
|
using namespace Hyprgraphics;
|
||||||
|
|
||||||
|
#define UP CUniquePointer
|
||||||
|
|
||||||
|
static UP<CAsyncResourceGatherer> g_asyncResourceGatherer;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
std::mutex wakeupMutex;
|
||||||
|
std::condition_variable wakeup;
|
||||||
|
|
||||||
|
bool exit = false;
|
||||||
|
bool needsToProcess = false;
|
||||||
|
|
||||||
|
int loadedAssets = 0;
|
||||||
|
|
||||||
|
std::mutex resourcesMutex;
|
||||||
|
std::vector<CAtomicSharedPointer<IAsyncResource>> resources;
|
||||||
|
} state;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool renderText(const std::string& text, Vector2D max = {}) {
|
||||||
|
// this stinks a bit but it's due to our ASP impl.
|
||||||
|
auto resource =
|
||||||
|
makeAtomicShared<CTextResource>(CTextResource::STextResourceData{.text = text, .fontSize = 72, .maxSize = max.x == 0 ? std::nullopt : std::optional<Vector2D>(max)});
|
||||||
|
CAtomicSharedPointer<IAsyncResource> resourceGeneric(resource);
|
||||||
|
|
||||||
|
g_asyncResourceGatherer->enqueue(resourceGeneric);
|
||||||
|
|
||||||
|
state.resourcesMutex.lock();
|
||||||
|
state.resources.emplace_back(std::move(resourceGeneric));
|
||||||
|
state.resourcesMutex.unlock();
|
||||||
|
|
||||||
|
resource->m_events.finished.listenStatic([]() {
|
||||||
|
state.needsToProcess = true;
|
||||||
|
state.wakeup.notify_all();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::println("Enqueued \"{}\" successfully.", text);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool renderImage(const std::string& path) {
|
||||||
|
// this stinks a bit but it's due to our ASP impl.
|
||||||
|
auto resource = makeAtomicShared<CImageResource>(path);
|
||||||
|
CAtomicSharedPointer<IAsyncResource> resourceGeneric(resource);
|
||||||
|
|
||||||
|
g_asyncResourceGatherer->enqueue(resourceGeneric);
|
||||||
|
|
||||||
|
state.resourcesMutex.lock();
|
||||||
|
state.resources.emplace_back(std::move(resourceGeneric));
|
||||||
|
state.resourcesMutex.unlock();
|
||||||
|
|
||||||
|
resource->m_events.finished.listenStatic([]() {
|
||||||
|
state.needsToProcess = true;
|
||||||
|
state.wakeup.notify_all();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::println("Enqueued \"{}\" successfully.", path);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** envp) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
g_asyncResourceGatherer = makeUnique<CAsyncResourceGatherer>();
|
||||||
|
|
||||||
|
EXPECT(renderText("Hello World"), true);
|
||||||
|
EXPECT(renderText("<b><i>Test markup</i></b>"), true);
|
||||||
|
EXPECT(renderText("Test ellipsis!!!!!", {512, 190}),
|
||||||
|
true);
|
||||||
|
EXPECT(renderImage("./resource/images/hyprland.png"), true);
|
||||||
|
|
||||||
|
while (!state.exit) {
|
||||||
|
std::unique_lock lk(state.wakeupMutex);
|
||||||
|
if (!state.needsToProcess) // avoid a lock if a thread managed to request something already since we .unlock()ed
|
||||||
|
state.wakeup.wait_for(lk, std::chrono::seconds(5), [] { return state.needsToProcess; }); // wait for events
|
||||||
|
|
||||||
|
if (state.exit)
|
||||||
|
break;
|
||||||
|
|
||||||
|
state.needsToProcess = false;
|
||||||
|
|
||||||
|
state.resourcesMutex.lock();
|
||||||
|
|
||||||
|
const bool SHOULD_EXIT = std::ranges::all_of(state.resources, [](const auto& e) { return !!e->m_ready; });
|
||||||
|
|
||||||
|
state.resourcesMutex.unlock();
|
||||||
|
|
||||||
|
if (SHOULD_EXIT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
lk.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// all assets should be done, let's render them
|
||||||
|
size_t idx = 0;
|
||||||
|
for (const auto& r : state.resources) {
|
||||||
|
const auto TEST_DIR = std::filesystem::current_path().string() + "/test_output";
|
||||||
|
|
||||||
|
// try to write it for inspection
|
||||||
|
if (!std::filesystem::exists(TEST_DIR))
|
||||||
|
std::filesystem::create_directory(TEST_DIR);
|
||||||
|
|
||||||
|
std::string name = std::format("render-arg-{}", idx);
|
||||||
|
|
||||||
|
EXPECT(!!r->m_asset.cairoSurface->cairo(), true);
|
||||||
|
|
||||||
|
//NOLINTNEXTLINE
|
||||||
|
if (!r->m_asset.cairoSurface->cairo())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
EXPECT(cairo_surface_write_to_png(r->m_asset.cairoSurface->cairo(), (TEST_DIR + "/" + name + ".png").c_str()), CAIRO_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_asyncResourceGatherer.reset();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue