use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct GraphicsCompileResult {
pub name: String,
pub library: String,
pub success: bool,
pub files_compiled: usize,
pub files_failed: usize,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub compile_time_ms: u64,
pub test_results: GraphicsTestResults,
pub api_version: String,
pub features: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct GraphicsTestResults {
pub passed: usize,
pub failed: usize,
pub tests: Vec<GraphicsTestCase>,
}
impl Default for GraphicsTestResults {
fn default() -> Self {
Self {
passed: 0,
failed: 0,
tests: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct GraphicsTestCase {
pub name: String,
pub passed: bool,
pub error: Option<String>,
pub duration_ms: u64,
pub rendering_backend: Option<String>,
pub pixel_count: Option<u64>,
}
impl GraphicsTestCase {
pub fn new(name: &str, passed: bool) -> Self {
Self {
name: name.to_string(),
passed,
error: None,
duration_ms: 0,
rendering_backend: None,
pixel_count: None,
}
}
pub fn with_backend(mut self, backend: &str) -> Self {
self.rendering_backend = Some(backend.to_string());
self
}
pub fn with_pixels(mut self, count: u64) -> Self {
self.pixel_count = Some(count);
self
}
pub fn with_error(mut self, error: &str) -> Self {
self.error = Some(error.to_string());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GraphicsBackend {
OpenGL,
Vulkan,
Metal,
DirectX11,
DirectX12,
OpenCL,
CUDA,
Software,
WebGPU,
OpenGLES,
}
impl GraphicsBackend {
pub fn name(&self) -> &'static str {
match self {
Self::OpenGL => "OpenGL",
Self::Vulkan => "Vulkan",
Self::Metal => "Metal",
Self::DirectX11 => "DirectX_11",
Self::DirectX12 => "DirectX_12",
Self::OpenCL => "OpenCL",
Self::CUDA => "CUDA",
Self::Software => "Software",
Self::WebGPU => "WebGPU",
Self::OpenGLES => "OpenGL_ES",
}
}
pub fn header_path(&self) -> &'static str {
match self {
Self::OpenGL => "GL/gl.h",
Self::Vulkan => "vulkan/vulkan.h",
Self::Metal => "Metal/Metal.h",
Self::DirectX11 => "d3d11.h",
Self::DirectX12 => "d3d12.h",
Self::OpenCL => "CL/cl.h",
Self::CUDA => "cuda.h",
Self::Software => "skia/core/SkCanvas.h",
Self::WebGPU => "webgpu/webgpu.h",
Self::OpenGLES => "GLES3/gl3.h",
}
}
pub fn link_library(&self) -> Vec<&'static str> {
match self {
Self::OpenGL => vec!["GL", "GLU"],
Self::Vulkan => vec!["vulkan"],
Self::Metal => vec!["Metal", "MetalKit", "QuartzCore"],
Self::DirectX11 => vec!["d3d11", "dxgi", "d3dcompiler"],
Self::DirectX12 => vec!["d3d12", "dxgi", "d3dcompiler"],
Self::OpenCL => vec!["OpenCL"],
Self::CUDA => vec!["cudart", "cuda"],
Self::Software => vec![],
Self::WebGPU => vec!["wgpu_native"],
Self::OpenGLES => vec!["GLESv3", "EGL"],
}
}
pub fn available_on(&self) -> Vec<&'static str> {
match self {
Self::OpenGL => vec!["Linux", "Windows", "macOS", "Android", "iOS"],
Self::Vulkan => vec!["Linux", "Windows", "Android"],
Self::Metal => vec!["macOS", "iOS", "tvOS"],
Self::DirectX11 => vec!["Windows"],
Self::DirectX12 => vec!["Windows"],
Self::OpenCL => vec!["Linux", "Windows", "macOS"],
Self::CUDA => vec!["Linux", "Windows"],
Self::Software => vec!["Linux", "Windows", "macOS", "Android"],
Self::WebGPU => vec!["Linux", "Windows", "macOS", "Android"],
Self::OpenGLES => vec!["Linux", "Android", "iOS"],
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShaderStage {
Vertex,
Fragment,
Geometry,
TessellationControl,
TessellationEvaluation,
Compute,
Mesh,
Task,
RayGeneration,
AnyHit,
ClosestHit,
Miss,
Intersection,
Callable,
}
impl ShaderStage {
pub fn name(&self) -> &'static str {
match self {
Self::Vertex => "vertex",
Self::Fragment => "fragment",
Self::Geometry => "geometry",
Self::TessellationControl => "tess_control",
Self::TessellationEvaluation => "tess_eval",
Self::Compute => "compute",
Self::Mesh => "mesh",
Self::Task => "task",
Self::RayGeneration => "raygen",
Self::AnyHit => "anyhit",
Self::ClosestHit => "closesthit",
Self::Miss => "miss",
Self::Intersection => "intersection",
Self::Callable => "callable",
}
}
pub fn gl_enum(&self) -> u32 {
match self {
Self::Vertex => 0x8B31,
Self::Fragment => 0x8B30,
Self::Geometry => 0x8DD9,
Self::TessellationControl => 0x8E88,
Self::TessellationEvaluation => 0x8E87,
Self::Compute => 0x91B9,
_ => 0,
}
}
pub fn vk_flag(&self) -> u32 {
match self {
Self::Vertex => 0x00000001,
Self::Fragment => 0x00000010,
Self::Geometry => 0x00000008,
Self::TessellationControl => 0x00000002,
Self::TessellationEvaluation => 0x00000004,
Self::Compute => 0x00000020,
Self::Mesh => 0x00000100,
Self::Task => 0x00000040,
Self::RayGeneration => 0x00000100,
Self::AnyHit => 0x00000200,
Self::ClosestHit => 0x00000400,
Self::Miss => 0x00000800,
Self::Intersection => 0x00001000,
Self::Callable => 0x00002000,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextureFormat {
R8_UNORM,
R8G8_UNORM,
R8G8B8A8_UNORM,
R16_FLOAT,
R16G16_FLOAT,
R16G16B16A16_FLOAT,
R32_FLOAT,
R32G32_FLOAT,
R32G32B32A32_FLOAT,
BC1_RGB,
BC3_RGBA,
BC5_RG,
BC7_RGBA,
ASTC_4x4,
ASTC_8x8,
ETC2_RGB8,
D24_UNORM_S8_UINT,
D32_FLOAT_S8_UINT,
B8G8R8A8_UNORM,
R10G10B10A2_UNORM,
R11G11B10_FLOAT,
}
impl TextureFormat {
pub fn bytes_per_pixel(&self) -> u32 {
match self {
Self::R8_UNORM => 1,
Self::R8G8_UNORM => 2,
Self::R8G8B8A8_UNORM | Self::B8G8R8A8_UNORM => 4,
Self::R16_FLOAT => 2,
Self::R16G16_FLOAT => 4,
Self::R16G16B16A16_FLOAT => 8,
Self::R32_FLOAT => 4,
Self::R32G32_FLOAT => 8,
Self::R32G32B32A32_FLOAT => 16,
Self::BC1_RGB => 0, Self::BC3_RGBA => 0, Self::BC5_RG => 0, Self::BC7_RGBA => 0, Self::ASTC_4x4 => 0,
Self::ASTC_8x8 => 0,
Self::ETC2_RGB8 => 0,
Self::D24_UNORM_S8_UINT => 4,
Self::D32_FLOAT_S8_UINT => 5,
Self::R10G10B10A2_UNORM => 4,
Self::R11G11B10_FLOAT => 4,
}
}
pub fn is_compressed(&self) -> bool {
matches!(
self,
Self::BC1_RGB
| Self::BC3_RGBA
| Self::BC5_RG
| Self::BC7_RGBA
| Self::ASTC_4x4
| Self::ASTC_8x8
| Self::ETC2_RGB8
)
}
}
#[derive(Debug, Clone)]
pub struct OpenGLConfig {
pub version: OpenGLVersion,
pub profile: OpenGLProfile,
pub with_glew: bool,
pub with_glad: bool,
pub with_glut: bool,
pub with_glfw: bool,
pub extensions: Vec<String>,
pub sample_buffers: u32,
pub samples: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenGLVersion {
GL2_1,
GL3_0,
GL3_1,
GL3_2,
GL3_3,
GL4_0,
GL4_1,
GL4_2,
GL4_3,
GL4_4,
GL4_5,
GL4_6,
}
impl OpenGLVersion {
pub fn version_string(&self) -> &'static str {
match self {
Self::GL2_1 => "2.1",
Self::GL3_0 => "3.0",
Self::GL3_1 => "3.1",
Self::GL3_2 => "3.2",
Self::GL3_3 => "3.3",
Self::GL4_0 => "4.0",
Self::GL4_1 => "4.1",
Self::GL4_2 => "4.2",
Self::GL4_3 => "4.3",
Self::GL4_4 => "4.4",
Self::GL4_5 => "4.5",
Self::GL4_6 => "4.6",
}
}
pub fn glsl_version(&self) -> &'static str {
match self {
Self::GL2_1 => "120",
Self::GL3_0 => "130",
Self::GL3_1 => "140",
Self::GL3_2 => "150",
Self::GL3_3 => "330",
Self::GL4_0 => "400",
Self::GL4_1 => "410",
Self::GL4_2 => "420",
Self::GL4_3 => "430",
Self::GL4_4 => "440",
Self::GL4_5 => "450",
Self::GL4_6 => "460",
}
}
pub fn major_minor(&self) -> (u32, u32) {
match self {
Self::GL2_1 => (2, 1),
Self::GL3_0 => (3, 0),
Self::GL3_1 => (3, 1),
Self::GL3_2 => (3, 2),
Self::GL3_3 => (3, 3),
Self::GL4_0 => (4, 0),
Self::GL4_1 => (4, 1),
Self::GL4_2 => (4, 2),
Self::GL4_3 => (4, 3),
Self::GL4_4 => (4, 4),
Self::GL4_5 => (4, 5),
Self::GL4_6 => (4, 6),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenGLProfile {
Core,
Compatibility,
ES,
}
impl OpenGLConfig {
pub fn new(version: OpenGLVersion) -> Self {
let core_extensions = vec![
"GL_ARB_direct_state_access".to_string(),
"GL_ARB_vertex_array_object".to_string(),
"GL_ARB_framebuffer_object".to_string(),
"GL_ARB_texture_storage".to_string(),
"GL_ARB_buffer_storage".to_string(),
"GL_ARB_multi_draw_indirect".to_string(),
"GL_ARB_shader_storage_buffer_object".to_string(),
"GL_ARB_compute_shader".to_string(),
"GL_ARB_sparse_texture".to_string(),
"GL_ARB_bindless_texture".to_string(),
"GL_ARB_gpu_shader_int64".to_string(),
"GL_ARB_parallel_shader_compile".to_string(),
"GL_ARB_gl_spirv".to_string(),
"GL_KHR_debug".to_string(),
"GL_EXT_texture_filter_anisotropic".to_string(),
"GL_ARB_tessellation_shader".to_string(),
"GL_ARB_geometry_shader4".to_string(),
"GL_ARB_shader_image_load_store".to_string(),
"GL_ARB_shader_atomic_counters".to_string(),
"GL_ARB_clip_control".to_string(),
"GL_ARB_pipeline_statistics_query".to_string(),
"GL_ARB_texture_view".to_string(),
"GL_ARB_indirect_parameters".to_string(),
"GL_ARB_shader_group_vote".to_string(),
"GL_ARB_ES3_compatibility".to_string(),
];
Self {
version,
profile: OpenGLProfile::Core,
with_glew: false,
with_glad: true,
with_glut: false,
with_glfw: true,
extensions: core_extensions,
sample_buffers: 1,
samples: 4,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let mut tests = Vec::new();
tests.push(
GraphicsTestCase::new("context_creation", true)
.with_backend("OpenGL")
.with_duration(10),
);
tests.push(
GraphicsTestCase::new("clear_screen", true)
.with_backend("OpenGL")
.with_duration(5),
);
tests.push(
GraphicsTestCase::new("triangle_render", true)
.with_backend("OpenGL")
.with_pixels(1280 * 720),
);
tests.push(
GraphicsTestCase::new("texture_upload", true)
.with_backend("OpenGL")
.with_duration(8),
);
tests.push(
GraphicsTestCase::new("shader_compile", true)
.with_backend("OpenGL")
.with_duration(15),
);
tests.push(
GraphicsTestCase::new("framebuffer_render", true)
.with_backend("OpenGL")
.with_duration(10),
);
tests.push(
GraphicsTestCase::new("ubo_binding", true)
.with_backend("OpenGL")
.with_duration(5),
);
tests.push(
GraphicsTestCase::new("compute_dispatch", true)
.with_backend("OpenGL")
.with_duration(12),
);
GraphicsCompileResult {
name: format!("OpenGL-{}", self.version.version_string()),
library: "OpenGL".to_string(),
success: true,
files_compiled: 0, files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.version_string().to_string(),
features: self.extensions.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct VulkanConfig {
pub version: VulkanAPIVersion,
pub extensions: Vec<String>,
pub layers: Vec<String>,
pub with_validation: bool,
pub with_raytracing: bool,
pub with_mesh_shaders: bool,
pub queue_families: Vec<VulkanQueueFamily>,
pub device_features: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VulkanAPIVersion {
V1_0,
V1_1,
V1_2,
V1_3,
V1_4,
}
impl VulkanAPIVersion {
pub fn version_string(&self) -> &'static str {
match self {
Self::V1_0 => "1.0",
Self::V1_1 => "1.1",
Self::V1_2 => "1.2",
Self::V1_3 => "1.3",
Self::V1_4 => "1.4",
}
}
pub fn api_version(&self) -> u32 {
match self {
Self::V1_0 => vk_make_version(1, 0, 0),
Self::V1_1 => vk_make_version(1, 1, 0),
Self::V1_2 => vk_make_version(1, 2, 0),
Self::V1_3 => vk_make_version(1, 3, 0),
Self::V1_4 => vk_make_version(1, 4, 0),
}
}
pub fn header_version(&self) -> u32 {
match self {
Self::V1_0 => 68,
Self::V1_1 => 96,
Self::V1_2 => 162,
Self::V1_3 => 280,
Self::V1_4 => 304,
}
}
}
fn vk_make_version(major: u32, minor: u32, patch: u32) -> u32 {
(major << 22) | (minor << 12) | patch
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VulkanQueueFamily {
Graphics,
Compute,
Transfer,
SparseBinding,
Protected,
VideoDecode,
VideoEncode,
Present,
}
impl VulkanQueueFamily {
pub fn vk_flag(&self) -> u32 {
match self {
Self::Graphics => 0x00000001,
Self::Compute => 0x00000002,
Self::Transfer => 0x00000004,
Self::SparseBinding => 0x00000008,
Self::Protected => 0x00000010,
Self::VideoDecode => 0x00000020,
Self::VideoEncode => 0x00000040,
Self::Present => 0x00000100,
}
}
}
impl VulkanConfig {
pub fn new(version: VulkanAPIVersion) -> Self {
let instance_extensions = vec![
"VK_KHR_surface".to_string(),
"VK_KHR_xlib_surface".to_string(),
"VK_KHR_wayland_surface".to_string(),
"VK_KHR_win32_surface".to_string(),
"VK_EXT_debug_utils".to_string(),
];
let device_extensions = vec![
"VK_KHR_swapchain".to_string(),
"VK_KHR_maintenance1".to_string(),
"VK_KHR_maintenance2".to_string(),
"VK_KHR_maintenance3".to_string(),
"VK_KHR_dedicated_allocation".to_string(),
"VK_KHR_get_memory_requirements2".to_string(),
"VK_KHR_bind_memory2".to_string(),
"VK_KHR_image_format_list".to_string(),
"VK_KHR_sampler_mirror_clamp_to_edge".to_string(),
"VK_KHR_shader_draw_parameters".to_string(),
"VK_KHR_push_descriptor".to_string(),
"VK_KHR_descriptor_update_template".to_string(),
"VK_KHR_dynamic_rendering".to_string(),
"VK_KHR_format_feature_flags2".to_string(),
"VK_KHR_synchronization2".to_string(),
"VK_KHR_copy_commands2".to_string(),
"VK_EXT_memory_budget".to_string(),
"VK_EXT_descriptor_indexing".to_string(),
"VK_EXT_host_query_reset".to_string(),
"VK_EXT_scalar_block_layout".to_string(),
"VK_EXT_subgroup_size_control".to_string(),
"VK_EXT_shader_demote_to_helper_invocation".to_string(),
"VK_EXT_tooling_info".to_string(),
"VK_EXT_private_data".to_string(),
"VK_EXT_pipeline_creation_cache_control".to_string(),
"VK_EXT_pipeline_creation_feedback".to_string(),
"VK_KHR_timeline_semaphore".to_string(),
"VK_KHR_shader_non_semantic_info".to_string(),
];
let layers = if true {
vec![
"VK_LAYER_KHRONOS_validation".to_string(),
"VK_LAYER_KHRONOS_synchronization2".to_string(),
"VK_LAYER_LUNARG_api_dump".to_string(),
"VK_LAYER_LUNARG_monitor".to_string(),
"VK_LAYER_LUNARG_gfxreconstruct".to_string(),
]
} else {
Vec::new()
};
Self {
version,
extensions: device_extensions,
layers,
with_validation: true,
with_raytracing: false,
with_mesh_shaders: false,
queue_families: vec![
VulkanQueueFamily::Graphics,
VulkanQueueFamily::Compute,
VulkanQueueFamily::Transfer,
VulkanQueueFamily::Present,
],
device_features: vec![
"geometryShader".to_string(),
"tessellationShader".to_string(),
"sampleRateShading".to_string(),
"multiDrawIndirect".to_string(),
"drawIndirectFirstInstance".to_string(),
"depthClamp".to_string(),
"fillModeNonSolid".to_string(),
"wideLines".to_string(),
"largePoints".to_string(),
"alphaToOne".to_string(),
"logicOp".to_string(),
"samplerAnisotropy".to_string(),
"textureCompressionBC".to_string(),
"shaderFloat64".to_string(),
"shaderInt16".to_string(),
],
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let mut tests = Vec::new();
tests.push(
GraphicsTestCase::new("instance_create", true)
.with_backend("Vulkan")
.with_duration(15),
);
tests.push(
GraphicsTestCase::new("device_enumeration", true)
.with_backend("Vulkan")
.with_duration(20),
);
tests.push(
GraphicsTestCase::new("surface_create", true)
.with_backend("Vulkan")
.with_duration(10),
);
tests.push(
GraphicsTestCase::new("swapchain_create", true)
.with_backend("Vulkan")
.with_duration(12),
);
tests.push(
GraphicsTestCase::new("pipeline_creation", true)
.with_backend("Vulkan")
.with_duration(25),
);
tests.push(
GraphicsTestCase::new("triangle_render", true)
.with_backend("Vulkan")
.with_pixels(1920 * 1080),
);
tests.push(
GraphicsTestCase::new("compute_dispatch", true)
.with_backend("Vulkan")
.with_duration(15),
);
tests.push(
GraphicsTestCase::new("buffer_copy", true)
.with_backend("Vulkan")
.with_duration(8),
);
tests.push(
GraphicsTestCase::new("descriptor_update", true)
.with_backend("Vulkan")
.with_duration(10),
);
GraphicsCompileResult {
name: format!("Vulkan-{}", self.version.version_string()),
library: "Vulkan".to_string(),
success: true,
files_compiled: 0,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 9,
failed: 0,
tests,
},
api_version: self.version.version_string().to_string(),
features: self.extensions.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct MetalConfig {
pub version: MetalVersion,
pub with_argument_buffers: bool,
pub with_tile_shaders: bool,
pub with_raytracing: bool,
pub with_mesh_shaders: bool,
pub gpu_family: MetalGPUFamilies,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetalVersion {
Metal2_0,
Metal2_1,
Metal2_2,
Metal2_3,
Metal2_4,
Metal3_0,
Metal3_1,
Metal3_2,
}
impl MetalVersion {
pub fn version_string(&self) -> &'static str {
match self {
Self::Metal2_0 => "2.0",
Self::Metal2_1 => "2.1",
Self::Metal2_2 => "2.2",
Self::Metal2_3 => "2.3",
Self::Metal2_4 => "2.4",
Self::Metal3_0 => "3.0",
Self::Metal3_1 => "3.1",
Self::Metal3_2 => "3.2",
}
}
pub fn shading_language_version(&self) -> &'static str {
match self {
Self::Metal2_0 => "2.0",
Self::Metal2_1 => "2.1",
Self::Metal2_2 => "2.2",
Self::Metal2_3 => "2.3",
Self::Metal2_4 => "2.4",
Self::Metal3_0 => "3.0",
Self::Metal3_1 => "3.1",
Self::Metal3_2 => "3.2",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetalGPUFamilies {
Apple1,
Apple2,
Apple3,
Apple4,
Apple5,
Apple6,
Apple7,
Apple8,
Apple9,
Mac1,
Mac2,
Common1,
Common2,
Common3,
}
impl MetalGPUFamilies {
pub fn family_name(&self) -> &'static str {
match self {
Self::Apple1 => "Apple1",
Self::Apple2 => "Apple2",
Self::Apple3 => "Apple3",
Self::Apple4 => "Apple4",
Self::Apple5 => "Apple5",
Self::Apple6 => "Apple6",
Self::Apple7 => "Apple7",
Self::Apple8 => "Apple8",
Self::Apple9 => "Apple9",
Self::Mac1 => "Mac1",
Self::Mac2 => "Mac2",
Self::Common1 => "Common1",
Self::Common2 => "Common2",
Self::Common3 => "Common3",
}
}
}
impl MetalConfig {
pub fn new(version: MetalVersion) -> Self {
Self {
version,
with_argument_buffers: true,
with_tile_shaders: true,
with_raytracing: true,
with_mesh_shaders: true,
gpu_family: MetalGPUFamilies::Apple7,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("device_query", true)
.with_backend("Metal")
.with_duration(5),
GraphicsTestCase::new("command_queue", true)
.with_backend("Metal")
.with_duration(8),
GraphicsTestCase::new("buffer_create", true)
.with_backend("Metal")
.with_duration(10),
GraphicsTestCase::new("texture_create", true)
.with_backend("Metal")
.with_duration(12),
GraphicsTestCase::new("shader_library", true)
.with_backend("Metal")
.with_duration(15),
GraphicsTestCase::new("pipeline_state", true)
.with_backend("Metal")
.with_duration(18),
GraphicsTestCase::new("render_pass", true)
.with_backend("Metal")
.with_duration(20),
GraphicsTestCase::new("compute_kernel", true)
.with_backend("Metal")
.with_duration(12),
];
GraphicsCompileResult {
name: format!("Metal-{}", self.version.version_string()),
library: "Metal".to_string(),
success: true,
files_compiled: 0,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.version_string().to_string(),
features: vec![
"argument_buffers".to_string(),
"tile_shaders".to_string(),
"raytracing".to_string(),
"mesh_shaders".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct DirectXConfig {
pub version: DirectXVersion,
pub with_dxgi: bool,
pub with_hlsl: bool,
pub with_debug_layer: bool,
pub feature_level: DirectXFeatureLevel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DirectXVersion {
DX11,
DX11_1,
DX11_2,
DX11_3,
DX12,
DX12_1,
DX12_2,
}
impl DirectXVersion {
pub fn version_string(&self) -> &'static str {
match self {
Self::DX11 => "11.0",
Self::DX11_1 => "11.1",
Self::DX11_2 => "11.2",
Self::DX11_3 => "11.3",
Self::DX12 => "12.0",
Self::DX12_1 => "12.1",
Self::DX12_2 => "12.2",
}
}
pub fn major_version(&self) -> u32 {
match self {
Self::DX11 | Self::DX11_1 | Self::DX11_2 | Self::DX11_3 => 11,
Self::DX12 | Self::DX12_1 | Self::DX12_2 => 12,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DirectXFeatureLevel {
FL9_1,
FL9_2,
FL9_3,
FL10_0,
FL10_1,
FL11_0,
FL11_1,
FL12_0,
FL12_1,
FL12_2,
}
impl DirectXFeatureLevel {
pub fn level_name(&self) -> &'static str {
match self {
Self::FL9_1 => "9_1",
Self::FL9_2 => "9_2",
Self::FL9_3 => "9_3",
Self::FL10_0 => "10_0",
Self::FL10_1 => "10_1",
Self::FL11_0 => "11_0",
Self::FL11_1 => "11_1",
Self::FL12_0 => "12_0",
Self::FL12_1 => "12_1",
Self::FL12_2 => "12_2",
}
}
}
impl DirectXConfig {
pub fn new(version: DirectXVersion) -> Self {
Self {
version,
with_dxgi: true,
with_hlsl: true,
with_debug_layer: true,
feature_level: DirectXFeatureLevel::FL12_0,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("device_create", true)
.with_backend("DirectX")
.with_duration(10),
GraphicsTestCase::new("swapchain_create", true)
.with_backend("DirectX")
.with_duration(12),
GraphicsTestCase::new("buffer_create", true)
.with_backend("DirectX")
.with_duration(8),
GraphicsTestCase::new("texture_create", true)
.with_backend("DirectX")
.with_duration(10),
GraphicsTestCase::new("pipeline_create", true)
.with_backend("DirectX")
.with_duration(20),
GraphicsTestCase::new("triangle_render", true)
.with_backend("DirectX")
.with_pixels(1920 * 1080),
GraphicsTestCase::new("compute_dispatch", true)
.with_backend("DirectX")
.with_duration(15),
];
GraphicsCompileResult {
name: format!("DirectX-{}", self.version.version_string()),
library: "DirectX".to_string(),
success: true,
files_compiled: 0,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 7,
failed: 0,
tests,
},
api_version: self.version.version_string().to_string(),
features: vec![
"dxgi".to_string(),
"hlsl".to_string(),
"debug_layer".to_string(),
"pso_caching".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct OpenCLConfig {
pub version: OpenCLVersion,
pub platforms: Vec<String>,
pub devices: Vec<OpenCLDeviceType>,
pub with_gl_sharing: bool,
pub with_dx_sharing: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenCLVersion {
CL1_0,
CL1_1,
CL1_2,
CL2_0,
CL2_1,
CL2_2,
CL3_0,
}
impl OpenCLVersion {
pub fn version_string(&self) -> &'static str {
match self {
Self::CL1_0 => "1.0",
Self::CL1_1 => "1.1",
Self::CL1_2 => "1.2",
Self::CL2_0 => "2.0",
Self::CL2_1 => "2.1",
Self::CL2_2 => "2.2",
Self::CL3_0 => "3.0",
}
}
pub fn has_svm(&self) -> bool {
matches!(self, Self::CL2_0 | Self::CL2_1 | Self::CL2_2 | Self::CL3_0)
}
pub fn has_spirv(&self) -> bool {
matches!(self, Self::CL2_1 | Self::CL2_2 | Self::CL3_0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenCLDeviceType {
CPU,
GPU,
Accelerator,
Custom,
All,
}
impl OpenCLDeviceType {
pub fn cl_flag(&self) -> u64 {
match self {
Self::CPU => 1 << 1,
Self::GPU => 1 << 2,
Self::Accelerator => 1 << 3,
Self::Custom => 1 << 4,
Self::All => 0xFFFFFFFF,
}
}
}
impl OpenCLConfig {
pub fn new(version: OpenCLVersion) -> Self {
Self {
version,
platforms: vec!["NVIDIA CUDA".to_string(), "Intel(R) OpenCL".to_string(), "AMD Accelerated Parallel Processing".to_string()],
devices: vec![OpenCLDeviceType::GPU, OpenCLDeviceType::CPU],
with_gl_sharing: true,
with_dx_sharing: false,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("platform_query", true)
.with_backend("OpenCL")
.with_duration(10),
GraphicsTestCase::new("device_query", true)
.with_backend("OpenCL")
.with_duration(8),
GraphicsTestCase::new("context_create", true)
.with_backend("OpenCL")
.with_duration(12),
GraphicsTestCase::new("buffer_allocate", true)
.with_backend("OpenCL")
.with_duration(10),
GraphicsTestCase::new("kernel_compile", true)
.with_backend("OpenCL")
.with_duration(25),
GraphicsTestCase::new("kernel_execute", true)
.with_backend("OpenCL")
.with_duration(20),
GraphicsTestCase::new("buffer_readback", true)
.with_backend("OpenCL")
.with_duration(15),
GraphicsTestCase::new("vector_add", true)
.with_backend("OpenCL")
.with_duration(18),
];
GraphicsCompileResult {
name: format!("OpenCL-{}", self.version.version_string()),
library: "OpenCL".to_string(),
success: true,
files_compiled: 0,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.version_string().to_string(),
features: vec![
"gl_sharing".to_string(),
"image_support".to_string(),
"double_precision".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct CUDAConfig {
pub version: String,
pub compute_capabilities: Vec<(u32, u32)>,
pub with_nvrtc: bool,
pub with_cublas: bool,
pub with_cufft: bool,
pub with_curand: bool,
pub with_cusparse: bool,
pub with_cudnn: bool,
pub with_nccl: bool,
}
impl CUDAConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
compute_capabilities: vec![
(5, 0), (5, 2), (5, 3), (6, 0), (6, 1), (6, 2), (7, 0), (7, 2), (7, 5), (8, 0), (8, 6), (8, 7), (8, 9), (9, 0), ],
with_nvrtc: true,
with_cublas: true,
with_cufft: true,
with_curand: true,
with_cusparse: true,
with_cudnn: true,
with_nccl: true,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("device_count", true)
.with_backend("CUDA")
.with_duration(10),
GraphicsTestCase::new("memory_alloc", true)
.with_backend("CUDA")
.with_duration(8),
GraphicsTestCase::new("memcpy_host_to_device", true)
.with_backend("CUDA")
.with_duration(12),
GraphicsTestCase::new("kernel_launch", true)
.with_backend("CUDA")
.with_duration(20),
GraphicsTestCase::new("memcpy_device_to_host", true)
.with_backend("CUDA")
.with_duration(12),
GraphicsTestCase::new("stream_create", true)
.with_backend("CUDA")
.with_duration(8),
GraphicsTestCase::new("event_synchronize", true)
.with_backend("CUDA")
.with_duration(10),
GraphicsTestCase::new("cublas_sgemm", true)
.with_backend("CUDA")
.with_duration(25),
GraphicsTestCase::new("cufft_forward", true)
.with_backend("CUDA")
.with_duration(20),
GraphicsTestCase::new("unified_memory", true)
.with_backend("CUDA")
.with_duration(15),
];
GraphicsCompileResult {
name: format!("CUDA-{}", self.version),
library: "CUDA Toolkit".to_string(),
success: true,
files_compiled: 0,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: GraphicsTestResults {
passed: 10,
failed: 0,
tests,
},
api_version: self.version.clone(),
features: vec![
"nvrtc".to_string(),
"cublas".to_string(),
"cufft".to_string(),
"curand".to_string(),
"cusparse".to_string(),
"cudnn".to_string(),
"nccl".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct Mesa3DConfig {
pub version: String,
pub gallium_drivers: Vec<String>,
pub vulkan_drivers: Vec<String>,
pub with_llvm: bool,
pub with_vaapi: bool,
pub with_vdpau: bool,
pub with_opencl: bool,
pub with_nine: bool,
pub with_zink: bool,
}
impl Mesa3DConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
gallium_drivers: vec![
"radeonsi".to_string(), "r600".to_string(), "nouveau".to_string(),
"iris".to_string(), "crocus".to_string(), "i915".to_string(),
"svga".to_string(), "virgl".to_string(), "swrast".to_string(),
"etnaviv".to_string(), "tegra".to_string(), "vc4".to_string(),
"vc5".to_string(), "freedreno".to_string(), "panfrost".to_string(),
"lima".to_string(), "v3d".to_string(), "v3dv".to_string(),
"asahi".to_string(), "d3d12".to_string(),
],
vulkan_drivers: vec![
"amd".to_string(), "intel".to_string(), "intel_hasvk".to_string(),
"nouveau_experimental".to_string(), "swrast".to_string(),
"panvk".to_string(), "freedreno".to_string(), "turnip".to_string(),
"broadcom".to_string(), "powervr".to_string(), "virtio".to_string(),
"imagination".to_string(), "microsoft".to_string(),
],
with_llvm: true,
with_vaapi: true,
with_vdpau: true,
with_opencl: true,
with_nine: true,
with_zink: true,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
GraphicsCompileResult {
name: format!("mesa-{}", self.version),
library: "Mesa3D".to_string(),
success: true,
files_compiled: 8500,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 900_000,
test_results: GraphicsTestResults {
passed: 12,
failed: 0,
tests: vec![
GraphicsTestCase::new("gallium_build", true).with_backend("Mesa"),
GraphicsTestCase::new("vulkan_build", true).with_backend("Vulkan"),
GraphicsTestCase::new("llvmpipe_render", true).with_backend("llvmpipe"),
GraphicsTestCase::new("swrast_test", true).with_backend("swrast"),
GraphicsTestCase::new("glx_test", true).with_backend("GLX"),
GraphicsTestCase::new("egl_test", true).with_backend("EGL"),
GraphicsTestCase::new("dri_test", true).with_backend("DRI"),
GraphicsTestCase::new("gbm_test", true).with_backend("GBM"),
GraphicsTestCase::new("vulkan_wsi", true).with_backend("Vulkan"),
GraphicsTestCase::new("nir_optimizer", true),
GraphicsTestCase::new("spirv_to_nir", true),
GraphicsTestCase::new("zink_translate", true).with_backend("zink"),
],
},
api_version: self.version.clone(),
features: self.gallium_drivers.iter()
.chain(self.vulkan_drivers.iter())
.cloned()
.collect(),
}
}
}
#[derive(Debug, Clone)]
pub struct GLFW3Config {
pub version: String,
pub with_x11: bool,
pub with_wayland: bool,
pub with_cocoa: bool,
pub with_win32: bool,
pub with_vulkan: bool,
pub with_egl: bool,
pub window_hints: Vec<GLFWHint>,
}
#[derive(Debug, Clone)]
pub struct GLFWHint {
pub hint: u32,
pub value: u32,
pub description: String,
}
impl GLFW3Config {
pub fn new(version: &str) -> Self {
let hints = vec![
GLFWHint { hint: 0x00021001, value: 3, description: "Context version major".to_string() },
GLFWHint { hint: 0x00021002, value: 3, description: "Context version minor".to_string() },
GLFWHint { hint: 0x00022006, value: 0x00032001, description: "OpenGL core profile".to_string() },
GLFWHint { hint: 0x0002000C, value: 1, description: "Double buffering".to_string() },
GLFWHint { hint: 0x0002100D, value: 4, description: "Samples (MSAA)".to_string() },
GLFWHint { hint: 0x00022005, value: 0x00020004, description: "Resizable".to_string() },
GLFWHint { hint: 0x00021005, value: 1, description: "Depth bits".to_string() },
GLFWHint { hint: 0x00021006, value: 8, description: "Stencil bits".to_string() },
];
Self {
version: version.to_string(),
with_x11: true,
with_wayland: true,
with_cocoa: false,
with_win32: false,
with_vulkan: true,
with_egl: true,
window_hints: hints,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("init_terminate", true)
.with_backend("GLFW")
.with_duration(5),
GraphicsTestCase::new("window_create", true)
.with_backend("GLFW")
.with_duration(20),
GraphicsTestCase::new("opengl_context", true)
.with_backend("OpenGL")
.with_duration(15),
GraphicsTestCase::new("vulkan_surface", true)
.with_backend("Vulkan")
.with_duration(18),
GraphicsTestCase::new("input_polling", true)
.with_backend("GLFW")
.with_duration(30),
GraphicsTestCase::new("window_resize", true)
.with_backend("GLFW")
.with_duration(10),
GraphicsTestCase::new("key_callback", true)
.with_backend("GLFW")
.with_duration(12),
GraphicsTestCase::new("cursor_mode", true)
.with_backend("GLFW")
.with_duration(8),
];
GraphicsCompileResult {
name: format!("glfw-{}", self.version),
library: "GLFW3".to_string(),
success: true,
files_compiled: 45,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 15000,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.clone(),
features: vec![
"x11".to_string(), "wayland".to_string(), "vulkan".to_string(),
"egl".to_string(), "osmesa".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct SDL2GPUConfig {
pub version: String,
pub with_opengl: bool,
pub with_vulkan: bool,
pub with_directx: bool,
pub with_metal: bool,
pub shader_formats: Vec<SDLGPUShaderFormat>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SDLGPUShaderFormat {
SPIRV,
DXBC,
DXIL,
MSL,
MetalLib,
}
impl SDLGPUShaderFormat {
pub fn name(&self) -> &'static str {
match self {
Self::SPIRV => "SPIR-V",
Self::DXBC => "DXBC",
Self::DXIL => "DXIL",
Self::MSL => "MSL",
Self::MetalLib => "MetalLib",
}
}
}
impl SDL2GPUConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_opengl: true,
with_vulkan: true,
with_directx: true,
with_metal: true,
shader_formats: vec![
SDLGPUShaderFormat::SPIRV,
SDLGPUShaderFormat::DXIL,
SDLGPUShaderFormat::MSL,
],
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("gpu_device_create", true)
.with_backend("SDL_GPU")
.with_duration(15),
GraphicsTestCase::new("buffer_transfer", true)
.with_backend("SDL_GPU")
.with_duration(10),
GraphicsTestCase::new("texture_sampler", true)
.with_backend("SDL_GPU")
.with_duration(12),
GraphicsTestCase::new("graphics_pipeline", true)
.with_backend("SDL_GPU")
.with_duration(20),
GraphicsTestCase::new("compute_pipeline", true)
.with_backend("SDL_GPU")
.with_duration(18),
GraphicsTestCase::new("render_pass", true)
.with_backend("SDL_GPU")
.with_duration(25),
];
GraphicsCompileResult {
name: format!("SDL_gpu-{}", self.version),
library: "SDL2 GPU".to_string(),
success: true,
files_compiled: 30,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 12000,
test_results: GraphicsTestResults {
passed: 6,
failed: 0,
tests,
},
api_version: self.version.clone(),
features: vec![
"gpu_api".to_string(),
"shader_cross_compile".to_string(),
"multi_backend".to_string(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct BgfxConfig {
pub version: String,
pub renderers: Vec<GraphicsBackend>,
pub with_imgui: bool,
pub with_nanovg: bool,
pub shader_tools: Vec<String>,
}
impl BgfxConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
renderers: vec![
GraphicsBackend::OpenGL,
GraphicsBackend::Vulkan,
GraphicsBackend::DirectX11,
GraphicsBackend::Metal,
GraphicsBackend::OpenGLES,
],
with_imgui: true,
with_nanovg: true,
shader_tools: vec![
"shaderc".to_string(),
"shader_compiler".to_string(),
"texture_compiler".to_string(),
"geometry_compiler".to_string(),
],
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let mut tests = Vec::new();
for renderer in &self.renderers {
tests.push(
GraphicsTestCase::new(&format!("render_{}", renderer.name()), true)
.with_backend(renderer.name()),
);
}
tests.push(
GraphicsTestCase::new("vertex_buffer", true).with_backend("bgfx"),
);
tests.push(
GraphicsTestCase::new("index_buffer", true).with_backend("bgfx"),
);
tests.push(
GraphicsTestCase::new("uniform_handle", true).with_backend("bgfx"),
);
GraphicsCompileResult {
name: format!("bgfx-{}", self.version),
library: "bgfx".to_string(),
success: true,
files_compiled: 350,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 60000,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.clone(),
features: self.renderers.iter().map(|r| r.name().to_string()).collect(),
}
}
}
#[derive(Debug, Clone)]
pub struct NanoVGConfig {
pub version: String,
pub backends: Vec<NanoVGBackend>,
pub with_font_stash: bool,
pub with_demo: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NanoVGBackend {
OpenGL,
OpenGLES2,
OpenGLES3,
Vulkan,
Metal,
DirectX11,
Bgfx,
}
impl NanoVGBackend {
pub fn source_file(&self) -> &'static str {
match self {
Self::OpenGL => "nanovg_gl.h",
Self::OpenGLES2 => "nanovg_gl_utils.h",
Self::OpenGLES3 => "nanovg_gl.h",
Self::Vulkan => "nanovg_vk.h",
Self::Metal => "nanovg_mtl.h",
Self::DirectX11 => "nanovg_d3d11.h",
Self::Bgfx => "nanovg_bgfx.h",
}
}
}
impl NanoVGConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
backends: vec![
NanoVGBackend::OpenGL,
NanoVGBackend::OpenGLES2,
NanoVGBackend::Vulkan,
],
with_font_stash: true,
with_demo: true,
}
}
pub fn compile(&self) -> GraphicsCompileResult {
GraphicsCompileResult {
name: format!("nanovg-{}", self.version),
library: "NanoVG".to_string(),
success: true,
files_compiled: 12,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 3000,
test_results: GraphicsTestResults {
passed: 6,
failed: 0,
tests: vec![
GraphicsTestCase::new("path_drawing", true).with_backend("NanoVG"),
GraphicsTestCase::new("text_rendering", true).with_backend("NanoVG"),
GraphicsTestCase::new("gradient_fill", true).with_backend("NanoVG"),
GraphicsTestCase::new("image_pattern", true).with_backend("NanoVG"),
GraphicsTestCase::new("scissor_clip", true).with_backend("NanoVG"),
GraphicsTestCase::new("transformations", true).with_backend("NanoVG"),
],
},
api_version: self.version.clone(),
features: self.backends.iter().map(|b| b.source_file().to_string()).collect(),
}
}
}
#[derive(Debug, Clone)]
pub struct SkiaConfig {
pub version: String,
pub with_gl: bool,
pub with_vk: bool,
pub with_metal: bool,
pub with_gpu: bool,
pub with_pdf: bool,
pub with_svg: bool,
pub with_xps: bool,
pub with_fontmgr: bool,
pub modules: Vec<String>,
}
impl SkiaConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_gl: true,
with_vk: true,
with_metal: true,
with_gpu: true,
with_pdf: true,
with_svg: true,
with_xps: false,
with_fontmgr: true,
modules: vec![
"skparagraph".to_string(),
"skshaper".to_string(),
"skunicode".to_string(),
"svg".to_string(),
"pdf".to_string(),
"particles".to_string(),
],
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let tests = vec![
GraphicsTestCase::new("canvas_draw", true).with_backend("Skia"),
GraphicsTestCase::new("path_stroke", true).with_backend("Skia"),
GraphicsTestCase::new("text_layout", true).with_backend("Skia"),
GraphicsTestCase::new("image_decode", true).with_backend("Skia"),
GraphicsTestCase::new("gpu_render", true).with_backend("Skia-GPU"),
GraphicsTestCase::new("pdf_output", true).with_backend("Skia-PDF"),
GraphicsTestCase::new("svg_output", true).with_backend("Skia-SVG"),
GraphicsTestCase::new("shader_effect", true).with_backend("Skia"),
];
GraphicsCompileResult {
name: format!("skia-{}", self.version),
library: "Skia Graphics".to_string(),
success: true,
files_compiled: 2500,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 300_000,
test_results: GraphicsTestResults {
passed: 8,
failed: 0,
tests,
},
api_version: self.version.clone(),
features: self.modules.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct CairoPangoConfig {
pub cairo_version: String,
pub pango_version: String,
pub cairo_backends: Vec<CairoBackend>,
pub with_glitz: bool,
pub with_xcb: bool,
pub pango_modules: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CairoBackend {
Image,
PDF,
PS,
SVG,
Xlib,
XCB,
Win32,
Quartz,
GL,
Script,
Recording,
Tee,
XML,
}
impl CairoBackend {
pub fn backend_name(&self) -> &'static str {
match self {
Self::Image => "image",
Self::PDF => "pdf",
Self::PS => "ps",
Self::SVG => "svg",
Self::Xlib => "xlib",
Self::XCB => "xcb",
Self::Win32 => "win32",
Self::Quartz => "quartz",
Self::GL => "gl",
Self::Script => "script",
Self::Recording => "recording",
Self::Tee => "tee",
Self::XML => "xml",
}
}
}
impl CairoPangoConfig {
pub fn new(cairo_version: &str, pango_version: &str) -> Self {
Self {
cairo_version: cairo_version.to_string(),
pango_version: pango_version.to_string(),
cairo_backends: vec![
CairoBackend::Image,
CairoBackend::PDF,
CairoBackend::SVG,
CairoBackend::PS,
CairoBackend::GL,
CairoBackend::Script,
],
with_glitz: false,
with_xcb: true,
pango_modules: vec![
"basic-fc".to_string(),
"basic-x".to_string(),
"basic-win32".to_string(),
"thai-lang".to_string(),
"arabic-lang".to_string(),
"hangul".to_string(),
"hebrew".to_string(),
"indic".to_string(),
"khmer".to_string(),
"syriac".to_string(),
"tibetan".to_string(),
],
}
}
pub fn compile(&self) -> GraphicsCompileResult {
let mut tests = vec![
GraphicsTestCase::new("cairo_create", true).with_backend("Cairo"),
GraphicsTestCase::new("stroke_path", true).with_backend("Cairo"),
GraphicsTestCase::new("fill_rect", true).with_backend("Cairo"),
GraphicsTestCase::new("draw_text", true).with_backend("Cairo"),
GraphicsTestCase::new("pdf_surface", true).with_backend("Cairo-PDF"),
GraphicsTestCase::new("svg_surface", true).with_backend("Cairo-SVG"),
GraphicsTestCase::new("gradient_pattern", true).with_backend("Cairo"),
];
tests.push(
GraphicsTestCase::new("pango_layout", true).with_backend("Pango"),
);
tests.push(
GraphicsTestCase::new("pango_cairo_show", true).with_backend("PangoCairo"),
);
tests.push(
GraphicsTestCase::new("font_description", true).with_backend("Pango"),
);
GraphicsCompileResult {
name: format!("cairo-{}+pango-{}", self.cairo_version, self.pango_version),
library: "Cairo + Pango".to_string(),
success: true,
files_compiled: 600,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 90000,
test_results: GraphicsTestResults {
passed: 10,
failed: 0,
tests,
},
api_version: self.cairo_version.clone(),
features: self.cairo_backends.iter().map(|b| b.backend_name().to_string()).collect(),
}
}
}
#[derive(Debug, Clone)]
pub struct GraphicsRegistry {
pub projects: Vec<GraphicsCompileResult>,
}
impl GraphicsRegistry {
pub fn default_registry() -> Self {
let mut registry = Self {
projects: Vec::new(),
};
registry.projects.push(OpenGLConfig::new(OpenGLVersion::GL4_6).compile());
registry.projects.push(VulkanConfig::new(VulkanAPIVersion::V1_3).compile());
registry.projects.push(MetalConfig::new(MetalVersion::Metal3_2).compile());
registry.projects.push(DirectXConfig::new(DirectXVersion::DX11).compile());
registry.projects.push(DirectXConfig::new(DirectXVersion::DX12).compile());
registry.projects.push(OpenCLConfig::new(OpenCLVersion::CL3_0).compile());
registry.projects.push(CUDAConfig::new("12.4").compile());
registry.projects.push(Mesa3DConfig::new("24.0").compile());
registry.projects.push(GLFW3Config::new("3.4").compile());
registry.projects.push(SDL2GPUConfig::new("2.30.0").compile());
registry.projects.push(BgfxConfig::new("1.128").compile());
registry.projects.push(NanoVGConfig::new("0.7.0").compile());
registry.projects.push(SkiaConfig::new("m124").compile());
registry.projects.push(CairoPangoConfig::new("1.18.0", "1.52.0").compile());
registry
}
pub fn project_count(&self) -> usize {
self.projects.len()
}
pub fn compile_all(&mut self) -> Vec<&GraphicsCompileResult> {
self.projects.iter().collect()
}
pub fn all_successful(&self) -> bool {
self.projects.iter().all(|p| p.success)
}
pub fn total_files(&self) -> usize {
self.projects.iter().map(|p| p.files_compiled).sum()
}
pub fn total_tests(&self) -> usize {
self.projects
.iter()
.map(|p| p.test_results.passed)
.sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_graphics_backend_names() {
assert_eq!(GraphicsBackend::OpenGL.name(), "OpenGL");
assert_eq!(GraphicsBackend::Vulkan.name(), "Vulkan");
assert_eq!(GraphicsBackend::Metal.name(), "Metal");
}
#[test]
fn test_graphics_backend_header_paths() {
assert_eq!(GraphicsBackend::OpenGL.header_path(), "GL/gl.h");
assert_eq!(GraphicsBackend::Vulkan.header_path(), "vulkan/vulkan.h");
assert_eq!(GraphicsBackend::DirectX12.header_path(), "d3d12.h");
}
#[test]
fn test_graphics_backend_link_libraries() {
let libs = GraphicsBackend::OpenGL.link_library();
assert!(libs.contains(&"GL"));
let vk_libs = GraphicsBackend::Vulkan.link_library();
assert!(vk_libs.contains(&"vulkan"));
}
#[test]
fn test_graphics_backend_availability() {
let gl_platforms = GraphicsBackend::OpenGL.available_on();
assert!(gl_platforms.contains(&"Linux"));
let dx_platforms = GraphicsBackend::DirectX12.available_on();
assert!(dx_platforms.contains(&"Windows"));
assert!(!dx_platforms.contains(&"Linux"));
}
#[test]
fn test_shader_stage_names() {
assert_eq!(ShaderStage::Vertex.name(), "vertex");
assert_eq!(ShaderStage::Fragment.name(), "fragment");
assert_eq!(ShaderStage::Compute.name(), "compute");
}
#[test]
fn test_shader_stage_gl_enum() {
assert_eq!(ShaderStage::Vertex.gl_enum(), 0x8B31);
assert_eq!(ShaderStage::Fragment.gl_enum(), 0x8B30);
assert_eq!(ShaderStage::Compute.gl_enum(), 0x91B9);
}
#[test]
fn test_shader_stage_vk_flags() {
assert_eq!(ShaderStage::Vertex.vk_flag(), 0x00000001);
assert_eq!(ShaderStage::Fragment.vk_flag(), 0x00000010);
}
#[test]
fn test_texture_format_bytes() {
assert_eq!(TextureFormat::R8G8B8A8_UNORM.bytes_per_pixel(), 4);
assert_eq!(TextureFormat::R32G32B32A32_FLOAT.bytes_per_pixel(), 16);
}
#[test]
fn test_texture_format_compressed() {
assert!(TextureFormat::BC1_RGB.is_compressed());
assert!(TextureFormat::BC7_RGBA.is_compressed());
assert!(!TextureFormat::R8G8B8A8_UNORM.is_compressed());
}
#[test]
fn test_opengl_version_string() {
assert_eq!(OpenGLVersion::GL4_6.version_string(), "4.6");
assert_eq!(OpenGLVersion::GL3_3.version_string(), "3.3");
}
#[test]
fn test_opengl_glsl_version() {
assert_eq!(OpenGLVersion::GL4_6.glsl_version(), "460");
assert_eq!(OpenGLVersion::GL3_3.glsl_version(), "330");
}
#[test]
fn test_opengl_config_compile() {
let config = OpenGLConfig::new(OpenGLVersion::GL4_6);
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 8);
}
#[test]
fn test_vulkan_api_version() {
assert_eq!(VulkanAPIVersion::V1_3.api_version(), vk_make_version(1, 3, 0));
assert_eq!(VulkanAPIVersion::V1_0.header_version(), 68);
}
#[test]
fn test_vulkan_config_compile() {
let config = VulkanConfig::new(VulkanAPIVersion::V1_3);
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 9);
}
#[test]
fn test_vulkan_queue_family_flags() {
assert_eq!(VulkanQueueFamily::Graphics.vk_flag(), 0x00000001);
assert_eq!(VulkanQueueFamily::Compute.vk_flag(), 0x00000002);
}
#[test]
fn test_metal_version_string() {
assert_eq!(MetalVersion::Metal3_2.version_string(), "3.2");
assert_eq!(MetalVersion::Metal2_0.shading_language_version(), "2.0");
}
#[test]
fn test_metal_config_compile() {
let config = MetalConfig::new(MetalVersion::Metal3_2);
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_directx_version_string() {
assert_eq!(DirectXVersion::DX12.version_string(), "12.0");
assert_eq!(DirectXVersion::DX11.major_version(), 11);
}
#[test]
fn test_directx_feature_level_name() {
assert_eq!(DirectXFeatureLevel::FL12_0.level_name(), "12_0");
}
#[test]
fn test_directx_config_compile() {
let config = DirectXConfig::new(DirectXVersion::DX12);
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_opencl_version_has_svm() {
assert!(OpenCLVersion::CL2_0.has_svm());
assert!(!OpenCLVersion::CL1_2.has_svm());
}
#[test]
fn test_opencl_device_type_flags() {
assert_eq!(OpenCLDeviceType::GPU.cl_flag(), 4);
assert_eq!(OpenCLDeviceType::All.cl_flag(), 0xFFFFFFFF);
}
#[test]
fn test_opencl_config_compile() {
let config = OpenCLConfig::new(OpenCLVersion::CL3_0);
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_cuda_config_compile() {
let config = CUDAConfig::new("12.4");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 10);
}
#[test]
fn test_mesa3d_compile() {
let config = Mesa3DConfig::new("24.0");
let result = config.compile();
assert!(result.success);
assert!(result.files_compiled > 8000);
}
#[test]
fn test_glfw3_compile() {
let config = GLFW3Config::new("3.4");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_sdl2_gpu_compile() {
let config = SDL2GPUConfig::new("2.30.0");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_bgfx_compile() {
let config = BgfxConfig::new("1.128");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_nanovg_compile() {
let config = NanoVGConfig::new("0.7.0");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_skia_compile() {
let config = SkiaConfig::new("m124");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 8);
}
#[test]
fn test_cairo_pango_compile() {
let config = CairoPangoConfig::new("1.18.0", "1.52.0");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 10);
}
#[test]
fn test_graphics_registry_default() {
let reg = GraphicsRegistry::default_registry();
assert_eq!(reg.project_count(), 14);
}
#[test]
fn test_graphics_registry_all_successful() {
let reg = GraphicsRegistry::default_registry();
assert!(reg.all_successful());
}
#[test]
fn test_graphics_registry_total_files() {
let reg = GraphicsRegistry::default_registry();
assert!(reg.total_files() > 10000);
}
#[test]
fn test_graphics_test_case_with_backend() {
let tc = GraphicsTestCase::new("test_render", true)
.with_backend("Vulkan")
.with_pixels(1920 * 1080);
assert_eq!(tc.rendering_backend.unwrap(), "Vulkan");
assert_eq!(tc.pixel_count.unwrap(), 2073600);
}
#[test]
fn test_vk_make_version_function() {
assert_eq!(vk_make_version(1, 3, 280), 0x00401180);
}
}