1use crate::{
2 get_error,
3 gpu::{
4 BufferBuilder, ColorTargetInfo, CommandBuffer, CopyPass, DepthStencilTargetInfo,
5 GraphicsPipelineBuilder, PresentMode, RenderPass, Sampler, SamplerCreateInfo,
6 ShaderBuilder, ShaderFormat, SwapchainComposition, Texture, TextureCreateInfo,
7 TextureFormat, TransferBufferBuilder,
8 },
9 sys,
10 video::Window,
11 Error,
12};
13use std::sync::{Arc, Weak};
14use sys::gpu::{
15 SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, SDL_BeginGPURenderPass, SDL_CreateGPUDevice,
16 SDL_CreateGPUSampler, SDL_CreateGPUTexture, SDL_DestroyGPUDevice, SDL_GPUColorTargetInfo,
17 SDL_GPUDepthStencilTargetInfo, SDL_GPUDevice, SDL_GPUViewport,
18 SDL_GetGPUSwapchainTextureFormat, SDL_SetGPUViewport,
19};
20
21use super::{
22 pass::Fence,
23 pipeline::{StorageBufferReadWriteBinding, StorageTextureReadWriteBinding},
24 ComputePass, ComputePipelineBuilder,
25};
26
27pub struct Viewport {
28 inner: SDL_GPUViewport,
29}
30impl Viewport {
31 #[doc(alias = "SDL_GPUViewport")]
32 pub fn new(x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32) -> Self {
33 Self {
34 inner: SDL_GPUViewport {
35 x,
36 y,
37 w,
38 h,
39 min_depth,
40 max_depth,
41 },
42 }
43 }
44
45 #[inline]
46 pub fn raw(&self) -> *const SDL_GPUViewport {
47 &self.inner
48 }
49}
50
51pub(super) struct DeviceContainer(*mut SDL_GPUDevice);
53impl DeviceContainer {
54 pub(super) fn raw(&self) -> *mut SDL_GPUDevice {
55 self.0
56 }
57}
58impl Drop for DeviceContainer {
59 #[doc(alias = "SDL_DestroyGPUDevice")]
60 fn drop(&mut self) {
61 unsafe { SDL_DestroyGPUDevice(self.0) }
62 }
63}
64
65pub(super) type WeakDevice = Weak<DeviceContainer>;
66
67#[derive(Clone)]
68pub struct Device {
69 inner: Arc<DeviceContainer>,
70 subsystem: Option<crate::VideoSubsystem>,
73}
74impl Device {
75 #[inline]
76 pub fn raw(&self) -> *mut SDL_GPUDevice {
77 self.inner.0
78 }
79
80 pub(super) fn weak(&self) -> WeakDevice {
81 Arc::downgrade(&self.inner)
82 }
83
84 #[doc(alias = "SDL_CreateGPUDevice")]
85 pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result<Self, Error> {
86 let raw_device = unsafe { SDL_CreateGPUDevice(flags.0, debug_mode, std::ptr::null()) };
87 if raw_device.is_null() {
88 Err(get_error())
89 } else {
90 Ok(Self {
91 inner: Arc::new(DeviceContainer(raw_device)),
92 subsystem: None,
93 })
94 }
95 }
96
97 #[doc(alias = "SDL_ClaimWindowForGPUDevice")]
98 pub fn with_window(mut self, window: &crate::video::Window) -> Result<Self, Error> {
99 self.subsystem = Some(window.subsystem().clone());
100
101 let p = unsafe { sys::gpu::SDL_ClaimWindowForGPUDevice(self.inner.0, window.raw()) };
102 if p {
103 Ok(self)
104 } else {
105 Err(get_error())
106 }
107 }
108
109 #[doc(alias = "SDL_AcquireGPUCommandBuffer")]
110 pub fn acquire_command_buffer(&self) -> Result<CommandBuffer, Error> {
111 let raw_buffer = unsafe { sys::gpu::SDL_AcquireGPUCommandBuffer(self.inner.0) };
112 if raw_buffer.is_null() {
113 Err(get_error())
114 } else {
115 Ok(CommandBuffer::new(raw_buffer))
116 }
117 }
118
119 pub fn create_shader(&self) -> ShaderBuilder<'_> {
120 ShaderBuilder::new(self)
121 }
122
123 #[doc(alias = "SDL_CreateGPUBuffer")]
124 pub fn create_buffer(&self) -> BufferBuilder<'_> {
125 BufferBuilder::new(self)
126 }
127
128 #[doc(alias = "SDL_CreateGPUTransferBuffer")]
129 pub fn create_transfer_buffer(&self) -> TransferBufferBuilder<'_> {
130 TransferBufferBuilder::new(self)
131 }
132
133 #[doc(alias = "SDL_CreateGPUSampler")]
134 pub fn create_sampler(&self, create_info: SamplerCreateInfo) -> Result<Sampler, Error> {
135 let raw_sampler = unsafe { SDL_CreateGPUSampler(self.raw(), &create_info.inner) };
136 if raw_sampler.is_null() {
137 Err(get_error())
138 } else {
139 Ok(Sampler::new(self, raw_sampler))
140 }
141 }
142
143 #[doc(alias = "SDL_CreateGPUTexture")]
144 pub fn create_texture(
145 &self,
146 create_info: TextureCreateInfo,
147 ) -> Result<Texture<'static>, Error> {
148 let raw_texture = unsafe { SDL_CreateGPUTexture(self.raw(), &create_info.inner) };
149 if raw_texture.is_null() {
150 Err(get_error())
151 } else {
152 Ok(Texture::new(
153 self,
154 raw_texture,
155 create_info.inner.width,
156 create_info.inner.height,
157 ))
158 }
159 }
160
161 #[doc(alias = "SDL_SetGPUViewport")]
162 pub fn set_viewport(&self, render_pass: &RenderPass, viewport: Viewport) {
163 unsafe { SDL_SetGPUViewport(render_pass.inner, viewport.raw()) }
164 }
165
166 pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat {
167 unsafe { std::mem::transmute(SDL_GetGPUSwapchainTextureFormat(self.inner.0, w.raw()).0) }
168 }
169
170 #[doc(alias = "SDL_BeginGPURenderPass")]
172 pub fn begin_render_pass(
173 &self,
174 command_buffer: &CommandBuffer,
175 color_info: &[ColorTargetInfo],
176 depth_stencil_target: Option<&DepthStencilTargetInfo>,
177 ) -> Result<RenderPass, Error> {
178 let p = unsafe {
179 SDL_BeginGPURenderPass(
180 command_buffer.inner,
181 color_info.as_ptr() as *const SDL_GPUColorTargetInfo, color_info.len() as u32,
183 if let Some(p) = depth_stencil_target {
184 p as *const _ as *const SDL_GPUDepthStencilTargetInfo } else {
186 std::ptr::null()
187 },
188 )
189 };
190 if !p.is_null() {
191 Ok(RenderPass { inner: p })
192 } else {
193 Err(get_error())
194 }
195 }
196
197 #[doc(alias = "SDL_EndGPURenderPass")]
198 pub fn end_render_pass(&self, pass: RenderPass) {
199 unsafe {
200 sys::gpu::SDL_EndGPURenderPass(pass.inner);
201 }
202 }
203
204 #[doc(alias = "SDL_BeginGPUCopyPass")]
205 pub fn begin_copy_pass(&self, command_buffer: &CommandBuffer) -> Result<CopyPass, Error> {
206 let p = unsafe { SDL_BeginGPUCopyPass(command_buffer.inner) };
207 if !p.is_null() {
208 Ok(CopyPass { inner: p })
209 } else {
210 Err(get_error())
211 }
212 }
213 #[doc(alias = "SDL_EndGPUCopyPass")]
214 pub fn end_copy_pass(&self, pass: CopyPass) {
215 unsafe {
216 sys::gpu::SDL_EndGPUCopyPass(pass.inner);
217 }
218 }
219
220 #[doc(alias = "SDL_BeginGPUComputePass")]
221 pub fn begin_compute_pass(
222 &self,
223 command_buffer: &CommandBuffer,
224 storage_texture_bindings: &[StorageTextureReadWriteBinding],
225 storage_buffer_bindings: &[StorageBufferReadWriteBinding],
226 ) -> Result<ComputePass, Error> {
227 let p = unsafe {
228 SDL_BeginGPUComputePass(
229 command_buffer.inner,
230 storage_texture_bindings.as_ptr().cast(),
231 storage_texture_bindings.len() as u32,
232 storage_buffer_bindings.as_ptr().cast(),
233 storage_buffer_bindings.len() as u32,
234 )
235 };
236 if !p.is_null() {
237 Ok(ComputePass { inner: p })
238 } else {
239 Err(get_error())
240 }
241 }
242 #[doc(alias = "SDL_EndGPUComputePass")]
243 pub fn end_compute_pass(&self, pass: ComputePass) {
244 unsafe {
245 sys::gpu::SDL_EndGPUComputePass(pass.inner);
246 }
247 }
248
249 pub fn create_graphics_pipeline<'a>(&'a self) -> GraphicsPipelineBuilder<'a> {
250 GraphicsPipelineBuilder::new(self)
251 }
252
253 pub fn create_compute_pipeline<'a>(&'a self) -> ComputePipelineBuilder<'a> {
254 ComputePipelineBuilder::new(self)
255 }
256
257 #[doc(alias = "SDL_WaitForGPUFences")]
258 pub fn wait_fences(&self, wait_all: bool, fences: &[Fence]) -> Result<(), Error> {
259 let fences: Vec<_> = fences.iter().map(|x| x.raw()).collect();
260 unsafe {
261 if !sys::gpu::SDL_WaitForGPUFences(
262 self.raw(),
263 wait_all,
264 fences.as_ptr(),
265 fences.len() as u32,
266 ) {
267 Err(get_error())
268 } else {
269 Ok(())
270 }
271 }
272 }
273
274 #[doc(alias = "SDL_GetGPUShaderFormats")]
275 pub fn get_shader_formats(&self) -> ShaderFormat {
276 unsafe { std::mem::transmute(sys::gpu::SDL_GetGPUShaderFormats(self.raw())) }
277 }
278
279 #[doc(alias = "SDL_SetGPUSwapchainParameters")]
280 pub fn set_swapchain_parameters(
281 &self,
282 window: &Window,
283 present_mode: PresentMode,
284 swapchain_composition: SwapchainComposition,
285 ) -> Result<(), Error> {
286 let raw_device_ptr = self.raw();
287 let raw_window_ptr = window.raw();
288
289 let c_present_mode = sys::gpu::SDL_GPUPresentMode(present_mode as i32);
290 let c_swapchain_composition =
291 sys::gpu::SDL_GPUSwapchainComposition(swapchain_composition as i32);
292
293 let success = unsafe {
294 sys::gpu::SDL_SetGPUSwapchainParameters(
295 raw_device_ptr,
296 raw_window_ptr,
297 c_swapchain_composition,
298 c_present_mode,
299 )
300 };
301
302 if success {
303 Ok(())
304 } else {
305 Err(get_error())
306 }
307 }
308
309 #[cfg(target_vendor = "uwp")]
311 #[doc(alias = "SDL_GDKSuspendGPU")]
312 pub fn gdk_suspend(&self) {
313 unsafe {
314 sys::gpu::SDL_GDKSuspendGPU(self.inner);
315 }
316 }
317
318 #[cfg(target_vendor = "uwp")]
319 #[doc(alias = "SDL_GDKResumeGPU")]
320 pub fn gdk_resume(&self) {
321 unsafe {
322 sys::gpu::SDL_GDKResumeGPU(self.inner);
323 }
324 }
325}