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,155 @@
/* 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.
*/
#include "frustum.hpp"
namespace Granite
{
// For reference, should always use SIMD-version.
bool Frustum::intersects_slow(const AABB &aabb) const
{
for (auto &plane : planes)
{
bool intersects_plane = false;
for (unsigned i = 0; i < 8; i++)
{
if (dot(vec4(aabb.get_corner(i), 1.0f), plane) >= 0.0f)
{
intersects_plane = true;
break;
}
}
if (!intersects_plane)
return false;
}
return true;
}
bool Frustum::intersects_sphere(const AABB &aabb) const
{
vec4 center(aabb.get_center(), 1.0f);
float radius = aabb.get_radius();
for (auto &plane : planes)
if (dot(plane, center) < -radius)
return false;
return true;
}
static constexpr float FarClipInfiniteClamp = 1e-10f;
vec3 Frustum::get_coord(float dx, float dy, float dz) const
{
dz = 1.0f - dz;
bool infinite_z = inv_view_projection[3][3] == 0.0f;
if (infinite_z)
dz = muglm::max<float>(dz, FarClipInfiniteClamp);
vec4 clip = vec4(2.0f * dx - 1.0f, 2.0f * dy - 1.0f, dz, 1.0f);
clip = inv_view_projection * clip;
return clip.xyz() / clip.w;
}
vec4 Frustum::get_bounding_sphere(const mat4 &inv_projection, const mat4 &inv_view)
{
// Make sure that radius is numerically stable throughout, since we use that as a snapping factor potentially.
// Use the inverse projection to create the radius.
const auto get_coord = [&](float x, float y, float z) -> vec3 {
vec4 clip = vec4(x, y, z, 1.0f);
clip = inv_projection * clip;
return clip.xyz() / clip.w;
};
vec3 center_near = get_coord(0.0f, 0.0f, 0.0f);
vec3 center_far = get_coord(0.0f, 0.0f, 1.0f);
vec3 near_pos = get_coord(-1.0f, -1.0f, 0.0f);
vec3 far_pos = get_coord(+1.0f, +1.0f, 1.0f);
float C = length(center_far - center_near);
float N = dot(near_pos - center_near, near_pos - center_near);
float F = dot(far_pos - center_far, far_pos - center_far);
// Solve the equation:
// n^2 + x^2 == f^2 + (C - x)^2 =>
// N + x^2 == F + C^2 - 2Cx + x^2.
// x = (F - N + C^2) / 2C
float center_distance = (F - N + C * C) / (2.0f * C);
float radius = muglm::sqrt(center_distance * center_distance + N);
vec3 view_space_center = center_near + center_distance * normalize(center_far - center_near);
vec3 center = (inv_view * vec4(view_space_center, 1.0f)).xyz();
return vec4(center, radius);
}
void Frustum::build_planes(const mat4 &inv_view_projection_)
{
inv_view_projection = inv_view_projection_;
bool infinite_z = inv_view_projection[3][3] == 0.0f;
float far_clip_z = infinite_z ? FarClipInfiniteClamp : 0.0f;
const vec4 tln(-1.0f, -1.0f, 1.0f, 1.0f);
const vec4 bln(-1.0f, +1.0f, 1.0f, 1.0f);
const vec4 blf(-1.0f, +1.0f, far_clip_z, 1.0f);
const vec4 trn(+1.0f, -1.0f, 1.0f, 1.0f);
const vec4 trf(+1.0f, -1.0f, far_clip_z, 1.0f);
const vec4 brn(+1.0f, +1.0f, 1.0f, 1.0f);
const vec4 brf(+1.0f, +1.0f, far_clip_z, 1.0f);
const vec4 c(0.0f, 0.0f, 0.5f, 1.0f);
const auto project = [](const vec4 &v) {
return v.xyz() / vec3(v.w);
};
vec3 TLN = project(inv_view_projection * tln);
vec3 BLN = project(inv_view_projection * bln);
vec3 BLF = project(inv_view_projection * blf);
vec3 TRN = project(inv_view_projection * trn);
vec3 TRF = project(inv_view_projection * trf);
vec3 BRN = project(inv_view_projection * brn);
vec3 BRF = project(inv_view_projection * brf);
vec4 center = inv_view_projection * c;
vec3 l = normalize(cross(BLF - BLN, TLN - BLN));
vec3 r = normalize(cross(TRF - TRN, BRN - TRN));
vec3 n = normalize(cross(BLN - BRN, TRN - BRN));
vec3 f = normalize(cross(TRF - BRF, BLF - BRF));
vec3 t = normalize(cross(TLN - TRN, TRF - TRN));
vec3 b = normalize(cross(BRF - BRN, BLN - BRN));
planes[0] = vec4(l, -dot(l, BLN));
planes[1] = vec4(r, -dot(r, TRN));
planes[2] = vec4(n, -dot(n, BRN));
planes[3] = infinite_z ? vec4(0.0f) : vec4(f, -dot(f, BRF));
planes[4] = vec4(t, -dot(t, TRN));
planes[5] = vec4(b, -dot(b, BRN));
// Winding order checks.
for (auto &p : planes)
if (dot(center, p) < 0.0f)
p = -p;
}
}