Skip to content

Commit

Permalink
today's work. obs crashes while screensharing.
Browse files Browse the repository at this point in the history
  • Loading branch information
vaxerski committed Aug 27, 2023
1 parent b32c560 commit daa9a23
Show file tree
Hide file tree
Showing 10 changed files with 1,074 additions and 34 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ include_directories(
)

set(CMAKE_CXX_STANDARD 23)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -fpermissive)

message(STATUS "Checking deps...")
add_subdirectory(subprojects/sdbus-cpp)
Expand Down Expand Up @@ -69,4 +69,5 @@ protocol("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreig
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
##
131 changes: 123 additions & 8 deletions src/core/PortalManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
#include <protocols/hyprland-toplevel-export-v1-protocol.h>
#include <protocols/wlr-foreign-toplevel-management-unstable-v1-protocol.h>
#include <protocols/wlr-screencopy-unstable-v1-protocol.h>
#include <protocols/linux-dmabuf-unstable-v1-protocol.h>

#include <pipewire/pipewire.h>
#include <sys/poll.h>

#include <thread>

void handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
g_pPortalManager->onGlobal(data, registry, name, interface, version);
Expand All @@ -16,11 +20,64 @@ void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name)
; // noop
}

inline const struct wl_registry_listener registryListener = {
inline const wl_registry_listener registryListener = {
.global = handleGlobal,
.global_remove = handleGlobalRemove,
};

static void handleOutputGeometry(void* data, struct wl_output* wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make,
const char* model, int32_t transform) {
;
}

static void handleOutputDone(void* data, struct wl_output* wl_output) {
;
}

static void handleOutputMode(void* data, struct wl_output* wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
;
}

static void handleOutputScale(void* data, struct wl_output* wl_output, int32_t factor) {
;
}

static void handleOutputName(void* data, struct wl_output* wl_output, const char* name) {
if (!name)
return;

const auto POUTPUT = (SOutput*)data;
POUTPUT->name = name;

Debug::log(LOG, "Found output name {}", POUTPUT->name);
}

static void handleOutputDescription(void* data, struct wl_output* wl_output, const char* description) {
;
}

inline const wl_output_listener outputListener = {
.geometry = handleOutputGeometry,
.mode = handleOutputMode,
.done = handleOutputDone,
.scale = handleOutputScale,
.name = handleOutputName,
.description = handleOutputDescription,
};

static void handleDMABUFFormat(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format) {
;
}

static void handleDMABUFModifier(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) {
g_pPortalManager->m_vDMABUFMods.push_back({format, (((uint64_t)modifier_hi) << 32) | modifier_lo});
}

inline const zwp_linux_dmabuf_v1_listener dmabufListener = {
.format = handleDMABUFFormat,
.modifier = handleDMABUFModifier,
};

//

void CPortalManager::onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
Expand All @@ -30,6 +87,34 @@ void CPortalManager::onGlobal(void* data, struct wl_registry* registry, uint32_t

if (INTERFACE == zwlr_screencopy_manager_v1_interface.name && m_sPipewire.loop)
m_sPortals.screencopy = std::make_unique<CScreencopyPortal>((zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, version));

else if (INTERFACE == hyprland_toplevel_export_manager_v1_interface.name)
m_sWaylandConnection.hyprlandToplevelMgr = wl_registry_bind(registry, name, &hyprland_toplevel_export_manager_v1_interface, version);

else if (INTERFACE == wl_output_interface.name) {
const auto POUTPUT = m_vOutputs.emplace_back(std::make_unique<SOutput>()).get();
POUTPUT->output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version);
wl_output_add_listener(POUTPUT->output, &outputListener, POUTPUT);
POUTPUT->id = name;
}

else if (INTERFACE == zwp_linux_dmabuf_v1_interface.name) {
if (version < 4) {
Debug::log(ERR, "cannot use linux_dmabuf with ver < 4");
return;
}

m_sWaylandConnection.linuxDmabuf = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version);
m_sWaylandConnection.linuxDmabufFeedback = zwp_linux_dmabuf_v1_get_default_feedback((zwp_linux_dmabuf_v1*)m_sWaylandConnection.linuxDmabuf);
// TODO: dmabuf
}

else if (INTERFACE == wl_shm_interface.name)
m_sWaylandConnection.shm = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, version);
}

void CPortalManager::onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name) {
std::erase_if(m_vOutputs, [&](const auto& other) { return other->id == name; });
}

void CPortalManager::init() {
Expand Down Expand Up @@ -72,28 +157,58 @@ void CPortalManager::init() {

if (!m_sPortals.screencopy)
Debug::log(WARN, "Screencopy not started: compositor doesn't support zwlr_screencopy_v1 or pw refused a loop");
else if (m_sWaylandConnection.hyprlandToplevelMgr)
m_sPortals.screencopy->appendToplevelExport(m_sWaylandConnection.hyprlandToplevelMgr);

wl_display_roundtrip(m_sWaylandConnection.display);

while (1) {
// dbus events
m_mEventLock.lock();

while (m_pConnection->processPendingRequest()) {
;
}

// wayland events
while (1) {
auto r = wl_display_dispatch_pending(m_sWaylandConnection.display);
wl_display_flush(m_sWaylandConnection.display);
std::vector<CTimer*> toRemove;
for (auto& t : m_vTimers) {
if (t->passed()) {
t->m_fnCallback();
toRemove.emplace_back(t.get());
Debug::log(TRACE, "[core] calling timer {}", (void*)t.get());
}
}

if (r <= 0)
break;
while (pw_loop_iterate(m_sPipewire.loop, 0) != 0) {
;
}

// TODO: pipewire loop
wl_display_flush(m_sWaylandConnection.display);
if (wl_display_prepare_read(m_sWaylandConnection.display) == 0) {
wl_display_read_events(m_sWaylandConnection.display);
wl_display_dispatch_pending(m_sWaylandConnection.display);
} else {
wl_display_dispatch(m_sWaylandConnection.display);
}

if (!toRemove.empty())
std::erase_if(m_vTimers,
[&](const auto& t) { return std::find_if(toRemove.begin(), toRemove.end(), [&](const auto& other) { return other == t.get(); }) != toRemove.end(); });

m_mEventLock.unlock();

std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}

sdbus::IConnection* CPortalManager::getConnection() {
return m_pConnection.get();
}

SOutput* CPortalManager::getOutputFromName(const std::string& name) {
for (auto& o : m_vOutputs) {
if (o->name == name)
return o.get();
}
return nullptr;
}
39 changes: 33 additions & 6 deletions src/core/PortalManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,58 @@
#include <wayland-client.h>

#include "../portals/Screencopy.hpp"
#include "../helpers/Timer.hpp"

#include <mutex>

struct pw_loop;

struct SOutput {
std::string name;
wl_output* output = nullptr;
uint32_t id = 0;
};

struct SDMABUFModifier {
uint32_t fourcc = 0;
uint64_t mod = 0;
};

class CPortalManager {
public:
void init();

void onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version);
void onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name);

sdbus::IConnection* getConnection();
SOutput* getOutputFromName(const std::string& name);

struct {
pw_loop* loop = nullptr;
} m_sPipewire;

private:
std::unique_ptr<sdbus::IConnection> m_pConnection;
struct {
std::unique_ptr<CScreencopyPortal> screencopy;
} m_sPortals;

struct {
wl_display* display = nullptr;
wl_display* display = nullptr;
void* hyprlandToplevelMgr = nullptr;
void* linuxDmabuf = nullptr;
void* linuxDmabufFeedback = nullptr;
wl_shm* shm = nullptr;
} m_sWaylandConnection;

struct {
std::unique_ptr<CScreencopyPortal> screencopy;
} m_sPortals;
std::vector<SDMABUFModifier> m_vDMABUFMods;

std::vector<std::unique_ptr<CTimer>> m_vTimers;

private:
std::unique_ptr<sdbus::IConnection> m_pConnection;
std::vector<std::unique_ptr<SOutput>> m_vOutputs;

std::mutex m_mEventLock;
};

inline std::unique_ptr<CPortalManager> g_pPortalManager;
4 changes: 3 additions & 1 deletion src/helpers/Log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

enum eLogLevel
{
INFO = 0,
TRACE = 0,
INFO,
LOG,
WARN,
ERR,
Expand All @@ -18,6 +19,7 @@ namespace Debug {
std::cout << '[';

switch (level) {
case TRACE: std::cout << "TRACE"; break;
case INFO: std::cout << "INFO"; break;
case LOG: std::cout << "LOG"; break;
case WARN: std::cout << "WARN"; break;
Expand Down
11 changes: 11 additions & 0 deletions src/helpers/Timer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "Timer.hpp"

CTimer::CTimer(float ms, std::function<void()> callback) {
m_fDuration = ms;
m_tStart = std::chrono::high_resolution_clock::now();
m_fnCallback = callback;
}

bool CTimer::passed() const {
return std::chrono::high_resolution_clock::now() > (m_tStart + std::chrono::milliseconds((uint64_t)m_fDuration));
}
17 changes: 17 additions & 0 deletions src/helpers/Timer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <functional>
#include <chrono>

class CTimer {
public:
CTimer(float ms, std::function<void()> callback);

bool passed() const;

std::function<void()> m_fnCallback;

private:
std::chrono::high_resolution_clock::time_point m_tStart;
float m_fDuration;
};
Loading

0 comments on commit daa9a23

Please sign in to comment.