libretro_core/
hw_render.rs1#[cfg(test)]
8use crate::HwContextType;
9use crate::HwRenderConfig;
10use crate::raw;
11use std::ffi::c_void;
12
13pub const OPENGL_COMPATIBILITY_HW_RENDER_LABEL: &str = "OpenGL/GLESv2/GLES2 candidate";
14pub const OPENGL_MODERN_PREFERRED_HW_RENDER_LABEL: &str = "modern-preferred OpenGL/GLES candidate";
15
16pub fn opengl_modern_preferred_hw_render_candidates() -> [HwRenderConfig; 5] {
17 [
18 HwRenderConfig::opengl().with_bottom_left_origin(true),
22 HwRenderConfig::opengles_version(2, 0)
25 .with_depth(true)
26 .with_bottom_left_origin(true),
27 HwRenderConfig::opengles2()
28 .with_depth(true)
29 .with_bottom_left_origin(true),
30 HwRenderConfig::opengl_core(3, 3).with_bottom_left_origin(true),
33 HwRenderConfig::opengles3().with_bottom_left_origin(true),
34 ]
35}
36
37pub fn opengl_compatibility_hw_render_candidates() -> [HwRenderConfig; 3] {
38 [
39 HwRenderConfig::opengl()
43 .with_depth(true)
44 .with_bottom_left_origin(true),
45 HwRenderConfig::opengles_version(2, 0)
48 .with_depth(true)
49 .with_bottom_left_origin(true),
50 HwRenderConfig::opengles2()
51 .with_depth(true)
52 .with_bottom_left_origin(true),
53 ]
54}
55
56#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
57pub enum HwRenderInterfaceType {
58 Vulkan,
59 D3d9,
60 D3d10,
61 D3d11,
62 D3d12,
63 GskitPs2,
64 Unknown(i32),
65}
66
67impl HwRenderInterfaceType {
68 pub(crate) fn from_raw(raw: i32) -> Self {
69 match raw {
70 value if value == raw::retro_hw_render_interface_type::Vulkan as i32 => Self::Vulkan,
71 value if value == raw::retro_hw_render_interface_type::D3d9 as i32 => Self::D3d9,
72 value if value == raw::retro_hw_render_interface_type::D3d10 as i32 => Self::D3d10,
73 value if value == raw::retro_hw_render_interface_type::D3d11 as i32 => Self::D3d11,
74 value if value == raw::retro_hw_render_interface_type::D3d12 as i32 => Self::D3d12,
75 value if value == raw::retro_hw_render_interface_type::GskitPs2 as i32 => {
76 Self::GskitPs2
77 }
78 value => Self::Unknown(value),
79 }
80 }
81
82 #[cfg(test)]
83 pub(crate) fn as_raw(self) -> i32 {
84 match self {
85 Self::Vulkan => raw::retro_hw_render_interface_type::Vulkan as i32,
86 Self::D3d9 => raw::retro_hw_render_interface_type::D3d9 as i32,
87 Self::D3d10 => raw::retro_hw_render_interface_type::D3d10 as i32,
88 Self::D3d11 => raw::retro_hw_render_interface_type::D3d11 as i32,
89 Self::D3d12 => raw::retro_hw_render_interface_type::D3d12 as i32,
90 Self::GskitPs2 => raw::retro_hw_render_interface_type::GskitPs2 as i32,
91 Self::Unknown(value) => value,
92 }
93 }
94}
95
96#[derive(Clone, Copy, Debug)]
97pub struct HwRenderInterface<'a> {
98 raw: &'a raw::retro_hw_render_interface,
99}
100
101impl<'a> HwRenderInterface<'a> {
102 pub(crate) fn from_raw(raw: &'a raw::retro_hw_render_interface) -> Self {
103 Self { raw }
104 }
105
106 pub fn interface_type(self) -> HwRenderInterfaceType {
107 HwRenderInterfaceType::from_raw(self.raw.interface_type)
108 }
109
110 pub fn interface_version(self) -> u32 {
111 self.raw.interface_version
112 }
113
114 pub fn as_base_ptr(self) -> *const c_void {
115 (self.raw as *const raw::retro_hw_render_interface).cast::<c_void>()
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
120pub enum HwRenderContextNegotiationInterfaceType {
121 Vulkan,
122 Unknown(i32),
123}
124
125impl HwRenderContextNegotiationInterfaceType {
126 #[cfg(test)]
127 pub(crate) fn from_raw(raw: i32) -> Self {
128 match raw {
129 value
130 if value
131 == raw::retro_hw_render_context_negotiation_interface_type::Vulkan as i32 =>
132 {
133 Self::Vulkan
134 }
135 value => Self::Unknown(value),
136 }
137 }
138
139 pub(crate) fn as_raw(self) -> i32 {
140 match self {
141 Self::Vulkan => raw::retro_hw_render_context_negotiation_interface_type::Vulkan as i32,
142 Self::Unknown(value) => value,
143 }
144 }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148pub struct HwRenderContextNegotiationInterface {
149 interface_type: HwRenderContextNegotiationInterfaceType,
150 interface_version: u32,
151}
152
153impl HwRenderContextNegotiationInterface {
154 pub fn new(
155 interface_type: HwRenderContextNegotiationInterfaceType,
156 interface_version: u32,
157 ) -> Self {
158 Self {
159 interface_type,
160 interface_version,
161 }
162 }
163
164 pub fn vulkan(interface_version: u32) -> Self {
165 Self::new(
166 HwRenderContextNegotiationInterfaceType::Vulkan,
167 interface_version,
168 )
169 }
170
171 pub fn interface_type(self) -> HwRenderContextNegotiationInterfaceType {
172 self.interface_type
173 }
174
175 pub fn interface_version(self) -> u32 {
176 self.interface_version
177 }
178
179 #[cfg(test)]
180 pub(crate) fn from_raw(raw: raw::retro_hw_render_context_negotiation_interface) -> Self {
181 Self {
182 interface_type: HwRenderContextNegotiationInterfaceType::from_raw(raw.interface_type),
183 interface_version: raw.interface_version,
184 }
185 }
186
187 pub(crate) fn as_raw(self) -> raw::retro_hw_render_context_negotiation_interface {
188 raw::retro_hw_render_context_negotiation_interface {
189 interface_type: self.interface_type.as_raw(),
190 interface_version: self.interface_version,
191 }
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn modern_preferred_candidates_keep_tolerant_paths_before_strict_modern_requests() {
201 let candidates = opengl_modern_preferred_hw_render_candidates();
202
203 assert_eq!(candidates[0].context_type, HwContextType::OpenGl);
204 assert!(candidates[0].bottom_left_origin);
205 assert_eq!(candidates[1].context_type, HwContextType::OpenGlEsVersion);
206 assert_eq!(candidates[1].version_major, 2);
207 assert_eq!(candidates[1].version_minor, 0);
208 assert!(candidates[1].depth);
209 assert!(candidates[1].bottom_left_origin);
210 assert_eq!(candidates[2].context_type, HwContextType::OpenGlEs2);
211 assert!(candidates[2].depth);
212 assert!(candidates[2].bottom_left_origin);
213 assert_eq!(candidates[3].context_type, HwContextType::OpenGlCore);
214 assert_eq!(candidates[3].version_major, 3);
215 assert_eq!(candidates[3].version_minor, 3);
216 assert!(candidates[3].bottom_left_origin);
217 assert_eq!(candidates[4].context_type, HwContextType::OpenGlEs3);
218 assert!(candidates[4].bottom_left_origin);
219 }
220
221 #[test]
222 fn compatibility_candidates_prefer_visible_request_forms_before_legacy_gles2() {
223 let candidates = opengl_compatibility_hw_render_candidates();
224
225 assert_eq!(candidates[0].context_type, HwContextType::OpenGl);
226 assert!(candidates[0].depth);
227 assert!(candidates[0].bottom_left_origin);
228 assert_eq!(candidates[1].context_type, HwContextType::OpenGlEsVersion);
229 assert_eq!(candidates[1].version_major, 2);
230 assert_eq!(candidates[1].version_minor, 0);
231 assert!(candidates[1].depth);
232 assert!(candidates[1].bottom_left_origin);
233 assert_eq!(candidates[2].context_type, HwContextType::OpenGlEs2);
234 assert!(candidates[2].depth);
235 assert!(candidates[2].bottom_left_origin);
236 }
237
238 #[test]
239 fn hw_render_interface_types_preserve_unknown_values() {
240 assert_eq!(
241 HwRenderInterfaceType::from_raw(raw::retro_hw_render_interface_type::D3d11 as i32),
242 HwRenderInterfaceType::D3d11
243 );
244 assert_eq!(HwRenderInterfaceType::Unknown(99).as_raw(), 99);
245 }
246
247 #[test]
248 fn hw_render_context_negotiation_interface_preserves_type_and_version() {
249 let interface = HwRenderContextNegotiationInterface::vulkan(2);
250 let raw = interface.as_raw();
251
252 assert_eq!(
253 raw.interface_type,
254 raw::retro_hw_render_context_negotiation_interface_type::Vulkan as i32
255 );
256 assert_eq!(raw.interface_version, 2);
257 assert_eq!(
258 HwRenderContextNegotiationInterface::from_raw(raw),
259 interface
260 );
261 }
262}