use anyhow::{Context, Result};
use crate::bundled;
const BASE_GL: &str = "https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/main/xml/";
const BASE_EGL: &str = "https://raw.githubusercontent.com/KhronosGroup/EGL-Registry/main/api/";
const BASE_VK: &str = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/main/xml/";
#[allow(dead_code)]
const BASE_VK_HEADERS: &str =
"https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/";
const BASE_ANGLE: &str = "https://raw.githubusercontent.com/google/angle/main/scripts/";
const GLSL_EXTS_URL: &str = "https://www.uplinklabs.net/glsl_exts.xml";
pub struct SpecSources {
pub primary: String,
pub supplementals: Vec<String>,
}
pub fn load_spec(spec_name: &str, use_fetch: bool) -> Result<SpecSources> {
if use_fetch {
fetch_spec(spec_name)
} else {
bundled_spec(spec_name)
}
}
#[allow(dead_code)]
pub fn load_auxiliary_header(path: &str, use_fetch: bool) -> Result<String> {
if use_fetch {
let url = auxiliary_url(path)
.ok_or_else(|| anyhow::anyhow!("no remote URL known for '{}'", path))?;
fetch_text(&url).with_context(|| format!("fetching auxiliary header '{}'", path))
} else {
bundled_auxiliary(path).map(str::to_string)
}
}
fn bundled_spec(spec_name: &str) -> Result<SpecSources> {
let primary = match spec_name {
"gl" => bundled::gl_xml()?,
"egl" => bundled::egl_xml()?,
"glx" => bundled::glx_xml()?,
"wgl" => bundled::wgl_xml()?,
"vk" => bundled::vk_xml()?,
other => anyhow::bail!("unknown spec name '{}'", other),
}
.to_string();
let supplementals = match spec_name {
"gl" => vec![
bundled::glsl_exts_xml()?.to_string(),
bundled::gl_angle_ext_xml()?.to_string(),
],
"egl" => vec![bundled::egl_angle_ext_xml()?.to_string()],
_ => vec![],
};
Ok(SpecSources {
primary,
supplementals,
})
}
#[allow(dead_code)]
fn bundled_auxiliary(path: &str) -> Result<&'static str> {
use bundled::*;
Ok(match path {
"xxhash.h" => XXHASH_H,
"KHR/khrplatform.h" => KHR_PLATFORM_H,
"EGL/eglplatform.h" => EGL_PLATFORM_H,
"vk_platform.h" => VK_PLATFORM_H,
"vk_video/vulkan_video_codecs_common.h" => VK_VIDEO_CODECS_COMMON_H,
"vk_video/vulkan_video_codec_h264std.h" => VK_VIDEO_H264STD_H,
"vk_video/vulkan_video_codec_h264std_decode.h" => VK_VIDEO_H264STD_DECODE_H,
"vk_video/vulkan_video_codec_h264std_encode.h" => VK_VIDEO_H264STD_ENCODE_H,
"vk_video/vulkan_video_codec_h265std.h" => VK_VIDEO_H265STD_H,
"vk_video/vulkan_video_codec_h265std_decode.h" => VK_VIDEO_H265STD_DECODE_H,
"vk_video/vulkan_video_codec_h265std_encode.h" => VK_VIDEO_H265STD_ENCODE_H,
"vk_video/vulkan_video_codec_av1std.h" => VK_VIDEO_AV1STD_H,
"vk_video/vulkan_video_codec_av1std_decode.h" => VK_VIDEO_AV1STD_DECODE_H,
"vk_video/vulkan_video_codec_av1std_encode.h" => VK_VIDEO_AV1STD_ENCODE_H,
"vk_video/vulkan_video_codec_vp9std.h" => VK_VIDEO_VP9STD_H,
"vk_video/vulkan_video_codec_vp9std_decode.h" => VK_VIDEO_VP9STD_DECODE_H,
other => anyhow::bail!("unknown auxiliary header '{}'", other),
})
}
fn fetch_spec(spec_name: &str) -> Result<SpecSources> {
let primary_url = match spec_name {
"gl" => format!("{}gl.xml", BASE_GL),
"egl" => format!("{}egl.xml", BASE_EGL),
"glx" => format!("{}glx.xml", BASE_GL),
"wgl" => format!("{}wgl.xml", BASE_GL),
"vk" => format!("{}vk.xml", BASE_VK),
other => anyhow::bail!("unknown spec name '{}'", other),
};
let primary = fetch_text(&primary_url)
.with_context(|| format!("fetching primary XML for '{}'", spec_name))?;
let supp_urls: Vec<String> = match spec_name {
"gl" => vec![
GLSL_EXTS_URL.to_string(),
format!("{}gl_angle_ext.xml", BASE_ANGLE),
],
"egl" => vec![format!("{}egl_angle_ext.xml", BASE_ANGLE)],
_ => vec![],
};
let supplementals = supp_urls
.iter()
.map(|url| fetch_text(url).with_context(|| format!("fetching supplemental '{}'", url)))
.collect::<Result<Vec<_>>>()?;
Ok(SpecSources {
primary,
supplementals,
})
}
#[allow(dead_code)]
fn auxiliary_url(path: &str) -> Option<String> {
if path.starts_with("vk_video/") || path == "vk_platform.h" {
Some(format!("{}vulkan/{}", BASE_VK_HEADERS, path))
} else if path.starts_with("KHR/") || path.starts_with("EGL/") {
Some(format!("{}{}", BASE_EGL, path))
} else {
None
}
}
fn fetch_text(url: &str) -> Result<String> {
let resp = reqwest::blocking::get(url)
.with_context(|| format!("GET {}", url))?
.error_for_status()
.with_context(|| format!("HTTP error from {}", url))?;
Ok(resp.text()?)
}