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:
2026-07-15 00:35:10 +02:00
parent 1b73361372
commit 4c3b11445c
396 changed files with 140058 additions and 0 deletions
@@ -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;
};
}