Skip to main content

EGUI_WGSL

Constant EGUI_WGSL 

Source
pub const EGUI_WGSL: &str = "// ============================================================\n// egui overlay shader \u{2014} renders egui UI primitives\n// ============================================================\n// Vertex format matches egui::epaint::Vertex:\n//   pos:   vec2<f32>  (screen-space pixel coordinates)\n//   uv:    vec2<f32>  (texture coordinates)\n//   color: vec4<f32>  (sRGB-normalized [0,1] via Unorm8x4 \u{2014} NOT linear)\n//\n// Color space contract:\n//   - Vertex colors come from egui Color32 (sRGB bytes) normalized by\n//     Unorm8x4 to [0,1]. They must be decoded sRGB\u{2192}linear before use.\n//   - Textures use Rgba8UnormSrgb; the GPU auto-decodes them to linear.\n//   - The render target is Bgra8UnormSrgb; the GPU auto-encodes linear\u{2192}sRGB.\n//   - All arithmetic in the fragment shader must be in linear space.\n// ============================================================\n\nstruct VertexInput {\n    @location(0) position: vec2<f32>,\n    @location(1) uv: vec2<f32>,\n    @location(2) color: vec4<f32>,\n};\n\nstruct VertexOutput {\n    @builtin(position) clip_position: vec4<f32>,\n    @location(0) uv: vec2<f32>,\n    @location(1) color: vec4<f32>,\n};\n\n@group(0) @binding(0)\nvar<uniform> screen_size: vec2<f32>;\n\n@vertex\nfn vs_main(in: VertexInput) -> VertexOutput {\n    var out: VertexOutput;\n    // Convert pixel coordinates to NDC: x \u{2208} [-1, 1], y \u{2208} [-1, 1]\n    // Screen origin is top-left, NDC origin is center.\n    out.clip_position = vec4<f32>(\n        2.0 * in.position.x / screen_size.x - 1.0,\n        1.0 - 2.0 * in.position.y / screen_size.y,\n        0.0,\n        1.0,\n    );\n    out.uv = in.uv;\n    // Pass sRGB-normalized color to the fragment stage for linear decode.\n    out.color = in.color;\n    return out;\n}\n\n@group(1) @binding(0)\nvar t_egui: texture_2d<f32>;\n@group(1) @binding(1)\nvar s_egui: sampler;\n\n// sRGB \u{2192} linear conversion per IEC 61966-2-1.\nfn srgb_to_linear(c: f32) -> f32 {\n    if c <= 0.04045 {\n        return c / 12.92;\n    }\n    return pow((c + 0.055) / 1.055, 2.4);\n}\n\n// Vertex colors from egui\'s tessellator are **premultiplied sRGB**\n// (RGB bytes have already been multiplied by alpha/255 before normalization).\n// To decode correctly:\n//   1. Unpremultiply: recover straight sRGB channels (rgb / a).\n//   2. Apply sRGB \u{2192} linear per-channel.\n//   3. Re-premultiply: multiply linear RGB by alpha.\n// This preserves correct blending for fully-opaque pixels and for the\n// anti-aliased feathering edge pixels (alpha < 1) that dominate small shapes.\nfn linear_from_premult_srgb(c: vec4<f32>) -> vec4<f32> {\n    let a = c.a;\n    if a < 0.0001 { return vec4<f32>(0.0); }\n    let srgb = c.rgb / a;\n    let lin  = vec3<f32>(srgb_to_linear(srgb.r), srgb_to_linear(srgb.g), srgb_to_linear(srgb.b));\n    return vec4<f32>(lin * a, a);\n}\n\n@fragment\nfn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {\n    // tex_color is already linear (Rgba8UnormSrgb auto-decoded by the GPU).\n    let tex_color = textureSample(t_egui, s_egui, in.uv);\n    // Decode premultiplied sRGB vertex color to premultiplied linear.\n    let linear = linear_from_premult_srgb(in.color);\n    // Both operands are now in linear premultiplied space; the sRGB surface encodes the result.\n    return linear * tex_color;\n}\n";
Expand description

Shader for the egui editor overlay. Consumed by khora_infra::WgpuRenderSystem::create_editor_overlay_and_shell as a raw &str.