1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! Defining information structures of a renderer.

use std::ffi::CStr;
use std::mem::MaybeUninit;

use crate::color::pixel::kind::PixelFormatKind;
use crate::geo::Size;
use crate::{bind, EnumInt, Sdl};

use super::Renderer;

/// A kind of renderer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RendererKind {
    /// Software renderer, normally slow.
    Software,
    /// GPU accelerated renderer, normally fast.
    Accelerated,
}

/// An information of a renderer.
#[derive(Debug, Clone)]
pub struct RendererInfo {
    /// The name of the renderer.
    pub name: String,
    /// The kind of the renderer.
    pub kind: RendererKind,
    /// Whether vertical sync is enabled.
    pub is_v_sync: bool,
    /// Whether texture is supported.
    pub supported_texture: bool,
    /// The list of supported format kinds.
    pub supported_formats: Vec<PixelFormatKind>,
    /// The max size of texture.
    pub max_texture_size: Size,
}

impl From<bind::SDL_RendererInfo> for RendererInfo {
    #[allow(clippy::unnecessary_cast)]
    fn from(info: bind::SDL_RendererInfo) -> Self {
        let kind = if info.flags & bind::SDL_RENDERER_SOFTWARE as u32 == 0 {
            RendererKind::Accelerated
        } else {
            RendererKind::Software
        };
        let supported_formats = info
            .texture_formats
            .iter()
            .take(info.num_texture_formats as usize)
            .map(|&raw| raw as EnumInt)
            .map(PixelFormatKind::from_raw)
            .collect();
        Self {
            name: unsafe { CStr::from_ptr(info.name) }
                .to_str()
                .unwrap_or_default()
                .into(),
            kind,
            is_v_sync: info.flags & bind::SDL_RENDERER_PRESENTVSYNC as u32 != 0,
            supported_texture: info.flags & bind::SDL_RENDERER_TARGETTEXTURE as u32 != 0,
            supported_formats,
            max_texture_size: Size {
                width: info.max_texture_width as u32,
                height: info.max_texture_height as u32,
            },
        }
    }
}

/// An extension for [`Renderer`] to get [`RendererInfo`].
pub trait RendererInfoExt {
    /// Returns the information of the renderer.
    fn renderer_info(&self) -> RendererInfo;
}

impl<'window> RendererInfoExt for Renderer<'window> {
    fn renderer_info(&self) -> RendererInfo {
        let mut info_raw = MaybeUninit::uninit();
        let ret = unsafe { bind::SDL_GetRendererInfo(self.as_ptr(), info_raw.as_mut_ptr()) };
        if ret != 0 {
            Sdl::error_then_panic("Getting renderer info");
        }
        unsafe { info_raw.assume_init() }.into()
    }
}