feat(host): vendor PyroWave + minimal Granite subset as crates/pyrowave-sys
Phase 0 of design/pyrowave-codec-plan.md — the opt-in wired-LAN ultra-low- latency codec. Vendored at upstream 509e4f88 (API 0.4.0, Granite 44362775, volk + vulkan-headers pins in PUNKTFUNK-VENDOR.txt), pruned to the 6.6 MB the standalone no-renderer build needs; scripts/vendor-pyrowave.sh reproduces the tree (a pin bump is protocol-affecting, plan §4.2). build.rs drives the wrapper CMakeLists (static archives incl. a static C-API lib upstream only ships shared) + bindgen over pyrowave.h; Linux and Windows only, empty stub elsewhere (Apple gets a native Metal port, §4.7). Offline-safe by construction: no network, no system lib, vendored Vulkan headers — same model as the opus dep (flatpak builder has no network). Phase-0 validation on .21 (RTX 5070 Ti, driver 610.43.03): - upstream pyrowave-c-test + interop test (incl. dmabuf/DRM-modifier Vulkan<->Vulkan) pass, from the pristine AND the pruned tree - GPU kernel times at ~1.6 bpp noise: encode/decode 0.090/0.042 ms @800p, 0.146/0.067 @1080p, 0.226/0.103 @1440p, 0.477/0.201 @4K — order of magnitude under NVENC's 1-2 ms retrieve, CBR lands within ~100 B of target - cargo test -p pyrowave-sys green (static link + API-version pin check) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
/* Copyright (c) 2017-2026 Hans-Kristian Arntzen
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include "compile_time_hash.hpp"
|
||||
#include "intrusive_hash_map.hpp"
|
||||
#include "global_managers.hpp"
|
||||
|
||||
#define EVENT_MANAGER_REGISTER(clazz, member, event) \
|
||||
GRANITE_EVENT_MANAGER()->register_handler<clazz, event, &clazz::member>(this)
|
||||
#define EVENT_MANAGER_REGISTER_LATCH(clazz, up_event, down_event, event) \
|
||||
GRANITE_EVENT_MANAGER()->register_latch_handler<clazz, event, &clazz::up_event, &clazz::down_event>(this)
|
||||
|
||||
namespace Granite
|
||||
{
|
||||
class Event;
|
||||
|
||||
template <typename Return, typename T, typename EventType, Return (T::*callback)(const EventType &e)>
|
||||
Return member_function_invoker(void *object, const Event &e)
|
||||
{
|
||||
return (static_cast<T *>(object)->*callback)(static_cast<const EventType &>(e));
|
||||
}
|
||||
|
||||
#define GRANITE_EVENT_TYPE_HASH(x) ::Util::compile_time_fnv1(#x)
|
||||
using EventType = uint64_t;
|
||||
|
||||
#define GRANITE_EVENT_TYPE_DECL(x) \
|
||||
enum class EventTypeWrapper : ::Granite::EventType { \
|
||||
type_id = GRANITE_EVENT_TYPE_HASH(x) \
|
||||
}; \
|
||||
static inline constexpr ::Granite::EventType get_type_id() { \
|
||||
return ::Granite::EventType(EventTypeWrapper::type_id); \
|
||||
}
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
virtual ~Event() = default;
|
||||
|
||||
Event() = default;
|
||||
|
||||
// Doesn't have to be set unless type information is going to be lost.
|
||||
// E.g. we're storing the Event some place and we have type-erasure.
|
||||
// Having this set helps us recover type information for dispatch.
|
||||
explicit Event(EventType type_)
|
||||
: type(type_)
|
||||
{
|
||||
}
|
||||
|
||||
EventType get_type_id() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
void set_cookie(uint64_t cookie_)
|
||||
{
|
||||
cookie = cookie_;
|
||||
}
|
||||
|
||||
uint64_t get_cookie() const
|
||||
{
|
||||
return cookie;
|
||||
}
|
||||
|
||||
private:
|
||||
EventType type = 0;
|
||||
uint64_t cookie = 0;
|
||||
};
|
||||
|
||||
class EventManager;
|
||||
|
||||
class EventHandler
|
||||
{
|
||||
public:
|
||||
EventHandler(const EventHandler &) = delete;
|
||||
void operator=(const EventHandler &) = delete;
|
||||
EventHandler() = default;
|
||||
~EventHandler();
|
||||
|
||||
void add_manager_reference(EventManager *manager);
|
||||
void release_manager_reference();
|
||||
|
||||
private:
|
||||
EventManager *event_manager = nullptr;
|
||||
uint32_t event_manager_ref_count = 0;
|
||||
};
|
||||
|
||||
class EventManager final : public EventManagerInterface
|
||||
{
|
||||
public:
|
||||
template<typename T, typename... P>
|
||||
void enqueue(P&&... p)
|
||||
{
|
||||
static constexpr auto type = T::get_type_id();
|
||||
auto &l = events[type];
|
||||
|
||||
auto ptr = std::unique_ptr<Event>(new T(std::forward<P>(p)...));
|
||||
l.queued_events.emplace_back(std::move(ptr));
|
||||
}
|
||||
|
||||
template<typename T, typename... P>
|
||||
uint64_t enqueue_latched(P&&... p)
|
||||
{
|
||||
static constexpr auto type = T::get_type_id();
|
||||
auto &l = latched_events[type];
|
||||
auto ptr = std::unique_ptr<Event>(new T(std::forward<P>(p)...));
|
||||
uint64_t cookie = ++cookie_counter;
|
||||
ptr->set_cookie(cookie);
|
||||
|
||||
if (l.enqueueing)
|
||||
throw std::logic_error("Cannot enqueue more latched events while handling events.");
|
||||
l.enqueueing = true;
|
||||
|
||||
auto *event = ptr.get();
|
||||
l.queued_events.emplace_back(std::move(ptr));
|
||||
dispatch_up_event(l, *event);
|
||||
l.enqueueing = false;
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void dequeue_latched(uint64_t cookie);
|
||||
void dequeue_all_latched(EventType type);
|
||||
|
||||
template<typename T>
|
||||
void dispatch_inline(const T &t)
|
||||
{
|
||||
static constexpr auto type = T::get_type_id();
|
||||
auto &l = events[type];
|
||||
dispatch_event(l.handlers, t);
|
||||
}
|
||||
|
||||
void dispatch_inline(const Event &e)
|
||||
{
|
||||
assert(e.get_type_id() != 0);
|
||||
auto &l = events[e.get_type_id()];
|
||||
dispatch_event(l.handlers, e);
|
||||
}
|
||||
|
||||
void dispatch();
|
||||
|
||||
template<typename T, typename EventType, bool (T::*mem_fn)(const EventType &)>
|
||||
void register_handler(T *handler)
|
||||
{
|
||||
handler->add_manager_reference(this);
|
||||
static constexpr auto type_id = EventType::get_type_id();
|
||||
auto &l = events[type_id];
|
||||
if (l.dispatching)
|
||||
l.recursive_handlers.push_back({ member_function_invoker<bool, T, EventType, mem_fn>, handler, handler });
|
||||
else
|
||||
l.handlers.push_back({ member_function_invoker<bool, T, EventType, mem_fn>, handler, handler });
|
||||
}
|
||||
|
||||
void unregister_handler(EventHandler *handler);
|
||||
|
||||
template<typename T, typename EventType, void (T::*up_fn)(const EventType &), void (T::*down_fn)(const EventType &)>
|
||||
void register_latch_handler(T *handler)
|
||||
{
|
||||
handler->add_manager_reference(this);
|
||||
LatchHandler h{
|
||||
member_function_invoker<void, T, EventType, up_fn>,
|
||||
member_function_invoker<void, T, EventType, down_fn>,
|
||||
handler, handler };
|
||||
|
||||
static constexpr auto type_id = EventType::get_type_id();
|
||||
auto &levents = latched_events[type_id];
|
||||
dispatch_up_events(levents.queued_events, h);
|
||||
|
||||
auto &l = latched_events[type_id];
|
||||
if (l.dispatching)
|
||||
l.recursive_handlers.push_back(h);
|
||||
else
|
||||
l.handlers.push_back(h);
|
||||
}
|
||||
|
||||
void unregister_latch_handler(EventHandler *handler);
|
||||
|
||||
~EventManager();
|
||||
|
||||
private:
|
||||
struct Handler
|
||||
{
|
||||
bool (*mem_fn)(void *object, const Event &event);
|
||||
void *handler;
|
||||
EventHandler *unregister_key;
|
||||
};
|
||||
|
||||
struct LatchHandler
|
||||
{
|
||||
void (*up_fn)(void *object, const Event &event);
|
||||
void (*down_fn)(void *object, const Event &event);
|
||||
void *handler;
|
||||
EventHandler *unregister_key;
|
||||
};
|
||||
|
||||
struct EventTypeData : Util::IntrusiveHashMapEnabled<EventTypeData>
|
||||
{
|
||||
std::vector<std::unique_ptr<Event>> queued_events;
|
||||
std::vector<Handler> handlers;
|
||||
std::vector<Handler> recursive_handlers;
|
||||
bool enqueueing = false;
|
||||
bool dispatching = false;
|
||||
|
||||
void flush_recursive_handlers();
|
||||
};
|
||||
|
||||
struct LatchEventTypeData : Util::IntrusiveHashMapEnabled<LatchEventTypeData>
|
||||
{
|
||||
std::vector<std::unique_ptr<Event>> queued_events;
|
||||
std::vector<LatchHandler> handlers;
|
||||
std::vector<LatchHandler> recursive_handlers;
|
||||
bool enqueueing = false;
|
||||
bool dispatching = false;
|
||||
|
||||
void flush_recursive_handlers();
|
||||
};
|
||||
|
||||
void dispatch_event(std::vector<Handler> &handlers, const Event &e);
|
||||
void dispatch_up_events(std::vector<std::unique_ptr<Event>> &events, const LatchHandler &handler);
|
||||
void dispatch_down_events(std::vector<std::unique_ptr<Event>> &events, const LatchHandler &handler);
|
||||
void dispatch_up_event(LatchEventTypeData &event_type, const Event &event);
|
||||
void dispatch_down_event(LatchEventTypeData &event_type, const Event &event);
|
||||
|
||||
Util::IntrusiveHashMap<EventTypeData> events;
|
||||
Util::IntrusiveHashMap<LatchEventTypeData> latched_events;
|
||||
uint64_t cookie_counter = 0;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user