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,252 @@
|
||||
#version 450
|
||||
// Copyright (c) 2025 Hans-Kristian Arntzen
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#extension GL_EXT_control_flow_attributes : require
|
||||
|
||||
layout(location = 0) in vec2 vUV;
|
||||
layout(location = 0, component = 2) in float vIntCoord;
|
||||
|
||||
#if CHROMA_CONFIG == 0
|
||||
#define OUTPUT_PLANES 1
|
||||
#define INPUT_PLANES 1
|
||||
#elif CHROMA_CONFIG == 1
|
||||
#define OUTPUT_PLANES 2
|
||||
#define INPUT_PLANES 3
|
||||
#elif CHROMA_CONFIG == 2
|
||||
#define OUTPUT_PLANES 3
|
||||
#define INPUT_PLANES 2
|
||||
#else
|
||||
#error "Invalid chroma config"
|
||||
#endif
|
||||
|
||||
layout(location = 0) out mediump float oY;
|
||||
#if OUTPUT_PLANES == 2
|
||||
layout(location = 1) out mediump vec2 oCbCr;
|
||||
#elif OUTPUT_PLANES == 3
|
||||
layout(location = 1) out mediump float oCb;
|
||||
layout(location = 2) out mediump float oCr;
|
||||
#endif
|
||||
|
||||
layout(set = 0, binding = 0) uniform mediump texture2D uYEven;
|
||||
layout(set = 0, binding = 1) uniform mediump texture2D uYOdd;
|
||||
layout(set = 0, binding = 2) uniform mediump sampler uSampler;
|
||||
#if INPUT_PLANES == 3
|
||||
layout(set = 0, binding = 3) uniform mediump texture2D uCbEven;
|
||||
layout(set = 0, binding = 4) uniform mediump texture2D uCbOdd;
|
||||
layout(set = 0, binding = 5) uniform mediump texture2D uCrEven;
|
||||
layout(set = 0, binding = 6) uniform mediump texture2D uCrOdd;
|
||||
#elif INPUT_PLANES == 2
|
||||
layout(set = 0, binding = 3) uniform mediump texture2D uCbCrEven;
|
||||
layout(set = 0, binding = 4) uniform mediump texture2D uCbCrOdd;
|
||||
#endif
|
||||
|
||||
// Direct and naive implementing of the CDF 9/7 synthesis filters.
|
||||
// Optimized for the mobile GPUs which don't have any
|
||||
// competent compute/shared memory performance whatsoever,
|
||||
// i.e. anything not AMD/NV/Intel.
|
||||
|
||||
layout(constant_id = 0) const bool VERTICAL = false;
|
||||
layout(constant_id = 1) const bool FINAL_Y = false;
|
||||
layout(constant_id = 2) const bool FINAL_CBCR = false;
|
||||
layout(constant_id = 3) const int EDGE_CONDITION = 0;
|
||||
const ivec2 OFFSET_M2 = VERTICAL ? ivec2(0, 0) : ivec2(0, 0);
|
||||
const ivec2 OFFSET_M1 = VERTICAL ? ivec2(0, 1) : ivec2(1, 0);
|
||||
const ivec2 OFFSET_C = VERTICAL ? ivec2(0, 2) : ivec2(2, 0);
|
||||
const ivec2 OFFSET_P1 = VERTICAL ? ivec2(0, 3) : ivec2(3, 0);
|
||||
const ivec2 OFFSET_P2 = VERTICAL ? ivec2(0, 4) : ivec2(4, 0);
|
||||
|
||||
const float SYNTHESIS_LP_0 = 1.11508705;
|
||||
const float SYNTHESIS_LP_1 = 0.591271763114;
|
||||
const float SYNTHESIS_LP_2 = -0.057543526229;
|
||||
const float SYNTHESIS_LP_3 = -0.091271763114;
|
||||
|
||||
const float SYNTHESIS_HP_0 = 0.602949018236;
|
||||
const float SYNTHESIS_HP_1 = -0.266864118443;
|
||||
const float SYNTHESIS_HP_2 = -0.078223266529;
|
||||
const float SYNTHESIS_HP_3 = 0.016864118443;
|
||||
const float SYNTHESIS_HP_4 = 0.026748757411;
|
||||
|
||||
layout(push_constant) uniform Registers
|
||||
{
|
||||
vec2 uv_offset;
|
||||
vec2 half_texel_offset;
|
||||
float res_scale;
|
||||
int aligned_transform_size;
|
||||
};
|
||||
|
||||
float[10] sample_component_gather(mediump texture2D tex_even, mediump texture2D tex_odd)
|
||||
{
|
||||
float components[10];
|
||||
vec2 gather_uv = vUV + half_texel_offset;
|
||||
vec2 even0, even1, odd0, odd1;
|
||||
|
||||
if (VERTICAL)
|
||||
{
|
||||
even0 = textureGatherOffset(sampler2D(tex_even, uSampler), gather_uv, OFFSET_M1).wx;
|
||||
even1 = textureGatherOffset(sampler2D(tex_even, uSampler), gather_uv, OFFSET_P1).wx;
|
||||
odd0 = textureGatherOffset(sampler2D(tex_odd, uSampler), gather_uv, OFFSET_M2).wx;
|
||||
odd1 = textureGatherOffset(sampler2D(tex_odd, uSampler), gather_uv, OFFSET_C).wx;
|
||||
}
|
||||
else
|
||||
{
|
||||
even0 = textureGatherOffset(sampler2D(tex_even, uSampler), gather_uv, OFFSET_M1).wz;
|
||||
even1 = textureGatherOffset(sampler2D(tex_even, uSampler), gather_uv, OFFSET_P1).wz;
|
||||
odd0 = textureGatherOffset(sampler2D(tex_odd, uSampler), gather_uv, OFFSET_M2).wz;
|
||||
odd1 = textureGatherOffset(sampler2D(tex_odd, uSampler), gather_uv, OFFSET_C).wz;
|
||||
}
|
||||
|
||||
components[0] = 0.0;
|
||||
components[1] = odd0.x;
|
||||
components[2] = even0.x;
|
||||
components[3] = odd0.y;
|
||||
components[4] = even0.y;
|
||||
components[5] = odd1.x;
|
||||
components[6] = even1.x;
|
||||
components[7] = odd1.y;
|
||||
components[8] = even1.y;
|
||||
components[9] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_P2).x;
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
vec2[10] sample_component_gather2(mediump texture2D tex_even, mediump texture2D tex_odd)
|
||||
{
|
||||
vec2 components[10];
|
||||
|
||||
// Little point in using gather here, at least for now.
|
||||
components[0] = vec2(0.0);
|
||||
components[1] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_M2).xy;
|
||||
components[2] = textureLodOffset(sampler2D(tex_even, uSampler), vUV, 0.0, OFFSET_M1).xy;
|
||||
components[3] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_M1).xy;
|
||||
components[4] = textureLodOffset(sampler2D(tex_even, uSampler), vUV, 0.0, OFFSET_C).xy;
|
||||
components[5] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_C).xy;
|
||||
components[6] = textureLodOffset(sampler2D(tex_even, uSampler), vUV, 0.0, OFFSET_P1).xy;
|
||||
components[7] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_P1).xy;
|
||||
components[8] = textureLodOffset(sampler2D(tex_even, uSampler), vUV, 0.0, OFFSET_P2).xy;
|
||||
components[9] = textureLodOffset(sampler2D(tex_odd, uSampler), vUV, 0.0, OFFSET_P2).xy;
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
bool is_odd = (int(vIntCoord) & 1) != 0;
|
||||
|
||||
float Y[10] = sample_component_gather(uYEven, uYOdd);
|
||||
#if INPUT_PLANES == 2
|
||||
vec2 CbCr[10] = sample_component_gather2(uCbCrEven, uCbCrOdd);
|
||||
#elif INPUT_PLANES == 3
|
||||
float Cb[10] = sample_component_gather(uCbEven, uCbOdd);
|
||||
float Cr[10] = sample_component_gather(uCrEven, uCrOdd);
|
||||
vec2 CbCr[10];
|
||||
[[unroll]]
|
||||
for (int i = 0; i < 10; i++)
|
||||
CbCr[i] = vec2(Cb[i], Cr[i]);
|
||||
#endif
|
||||
|
||||
if (EDGE_CONDITION < 0)
|
||||
{
|
||||
// The mirroring rules are particular.
|
||||
// For odd inputs we can rely on the mirrored sampling to get intended behavior.
|
||||
if (vIntCoord < 1.0)
|
||||
{
|
||||
// Y4 is the pivot.
|
||||
Y[2] = Y[6];
|
||||
#if INPUT_SAMPLES > 1
|
||||
CbCr[2] = CbCr[6];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (EDGE_CONDITION > 0)
|
||||
{
|
||||
if (vIntCoord + 2.0 > aligned_transform_size)
|
||||
{
|
||||
// We're on the last two pixels.
|
||||
// Y5 is the pivot. LP inputs behave as expected when using mirroring.
|
||||
Y[7] = Y[3];
|
||||
Y[9] = Y[1];
|
||||
#if INPUT_SAMPLES > 1
|
||||
CbCr[7] = CbCr[3];
|
||||
CbCr[9] = CbCr[1];
|
||||
#endif
|
||||
}
|
||||
else if (vIntCoord + 4.0 >= aligned_transform_size)
|
||||
{
|
||||
// Y7 is the pivot.
|
||||
Y[9] = Y[5];
|
||||
#if INPUT_SAMPLES > 1
|
||||
CbCr[9] = CbCr[5];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if INPUT_PLANES > 1
|
||||
#define AccumT vec3
|
||||
#define GenInput(comp) vec3(Y[comp], CbCr[comp])
|
||||
#else
|
||||
#define AccumT float
|
||||
#define GenInput(comp) Y[comp]
|
||||
#endif
|
||||
|
||||
AccumT C0, C1, C2, C3, C4;
|
||||
float W0, W1, W2, W3, W4;
|
||||
|
||||
// Not ideal, but gotta do what we gotta do.
|
||||
// GPU will have to take both paths here,
|
||||
// but at least we avoid dynamic load-store which is RIP perf on these chips ...
|
||||
if (is_odd)
|
||||
{
|
||||
C0 = GenInput(5);
|
||||
C1 = GenInput(4) + GenInput(6);
|
||||
C2 = GenInput(3) + GenInput(7);
|
||||
C3 = GenInput(2) + GenInput(8);
|
||||
C4 = GenInput(1) + GenInput(9);
|
||||
|
||||
W0 = SYNTHESIS_HP_0;
|
||||
W1 = SYNTHESIS_LP_1;
|
||||
W2 = SYNTHESIS_HP_2;
|
||||
W3 = SYNTHESIS_LP_3;
|
||||
W4 = SYNTHESIS_HP_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
C0 = GenInput(4);
|
||||
C1 = GenInput(3) + GenInput(5);
|
||||
C2 = GenInput(2) + GenInput(6);
|
||||
C3 = GenInput(1) + GenInput(7);
|
||||
C4 = AccumT(0.0);
|
||||
|
||||
W0 = SYNTHESIS_LP_0;
|
||||
W1 = SYNTHESIS_HP_1;
|
||||
W2 = SYNTHESIS_LP_2;
|
||||
W3 = SYNTHESIS_HP_3;
|
||||
W4 = 0.0;
|
||||
}
|
||||
|
||||
AccumT result = C0 * W0 + C1 * W1 + C2 * W2 + C3 * W3 + C4 * W4;
|
||||
|
||||
#if OUTPUT_PLANES == 3
|
||||
oY = result.x;
|
||||
oCb = result.y;
|
||||
oCr = result.z;
|
||||
#elif OUTPUT_PLANES == 2
|
||||
oY = result.x;
|
||||
oCbCr = result.yz;
|
||||
#else
|
||||
oY = result;
|
||||
#endif
|
||||
|
||||
if (FINAL_Y)
|
||||
oY += 0.5;
|
||||
|
||||
if (FINAL_CBCR)
|
||||
{
|
||||
#if OUTPUT_PLANES == 3
|
||||
oCb += 0.5;
|
||||
oCr += 0.5;
|
||||
#elif OUTPUT_PLANES == 2
|
||||
oCbCr += 0.5;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user