1use crate::{
2 get_error,
3 gpu::{
4 BufferBuilder, ColorTargetInfo, CommandBuffer, CopyPass, DepthStencilTargetInfo,
5 GraphicsPipelineBuilder, RenderPass, Sampler, SamplerCreateInfo, ShaderBuilder,
6 ShaderFormat, Texture, TextureCreateInfo, TextureFormat, TransferBufferBuilder,
7 },
8 sys, Error,
9};
10use std::sync::{Arc, Weak};
11use sys::gpu::{
12 SDL_BeginGPUComputePass, SDL_BeginGPUCopyPass, SDL_BeginGPURenderPass, SDL_CreateGPUDevice,
13 SDL_CreateGPUSampler, SDL_CreateGPUTexture, SDL_DestroyGPUDevice, SDL_GPUColorTargetInfo,
14 SDL_GPUDepthStencilTargetInfo, SDL_GPUDevice, SDL_GPUViewport,
15 SDL_GetGPUSwapchainTextureFormat, SDL_SetGPUViewport,
16};
17
18use super::{
19 pipeline::{StorageBufferReadWriteBinding, StorageTextureReadWriteBinding},
20 ComputePass, ComputePipelineBuilder,
21};
22
23pub(super) struct DeviceContainer(*mut SDL_GPUDevice);
25impl DeviceContainer {
26 pub(super) fn raw(&self) -> *mut SDL_GPUDevice {
27 self.0
28 }
29}
30impl Drop for DeviceContainer {
31 #[doc(alias = "SDL_DestroyGPUDevice")]
32 fn drop(&mut self) {
33 unsafe { SDL_DestroyGPUDevice(self.0) }
34 }
35}
36
37pub(super) type WeakDevice = Weak<DeviceContainer>;
38
39#[derive(Clone)]
40pub struct Device {
41 inner: Arc<DeviceContainer>,
42}
43impl Device {
44 #[inline]
45 pub fn raw(&self) -> *mut SDL_GPUDevice {
46 self.inner.0
47 }
48
49 pub(super) fn weak(&self) -> WeakDevice {
50 Arc::downgrade(&self.inner)
51 }
52
53 #[doc(alias = "SDL_CreateGPUDevice")]
54 pub fn new(flags: ShaderFormat, debug_mode: bool) -> Result<Self, Error> {
55 let raw_device = unsafe { SDL_CreateGPUDevice(flags as u32, debug_mode, std::ptr::null()) };
56 if raw_device.is_null() {
57 Err(get_error())
58 } else {
59 Ok(Self {
60 inner: Arc::new(DeviceContainer(raw_device)),
61 })
62 }
63 }
64
65 #[doc(alias = "SDL_ClaimWindowForGPUDevice")]
66 pub fn with_window(self, w: &crate::video::Window) -> Result<Self, Error> {
67 let p = unsafe { sys::gpu::SDL_ClaimWindowForGPUDevice(self.inner.0, w.raw()) };
68 if p {
69 Ok(self)
70 } else {
71 Err(get_error())
72 }
73 }
74
75 #[doc(alias = "SDL_AcquireGPUCommandBuffer")]
76 pub fn acquire_command_buffer(&self) -> Result<CommandBuffer, Error> {
77 let raw_buffer = unsafe { sys::gpu::SDL_AcquireGPUCommandBuffer(self.inner.0) };
78 if raw_buffer.is_null() {
79 Err(get_error())
80 } else {
81 Ok(CommandBuffer::new(raw_buffer))
82 }
83 }
84
85 pub fn create_shader(&self) -> ShaderBuilder {
86 ShaderBuilder::new(self)
87 }
88
89 #[doc(alias = "SDL_CreateGPUBuffer")]
90 pub fn create_buffer(&self) -> BufferBuilder {
91 BufferBuilder::new(self)
92 }
93
94 #[doc(alias = "SDL_CreateGPUTransferBuffer")]
95 pub fn create_transfer_buffer(&self) -> TransferBufferBuilder {
96 TransferBufferBuilder::new(self)
97 }
98
99 #[doc(alias = "SDL_CreateGPUSampler")]
100 pub fn create_sampler(&self, create_info: SamplerCreateInfo) -> Result<Sampler, Error> {
101 let raw_sampler = unsafe { SDL_CreateGPUSampler(self.raw(), &create_info.inner) };
102 if raw_sampler.is_null() {
103 Err(get_error())
104 } else {
105 Ok(Sampler::new(self, raw_sampler))
106 }
107 }
108
109 #[doc(alias = "SDL_CreateGPUTexture")]
110 pub fn create_texture(
111 &self,
112 create_info: TextureCreateInfo,
113 ) -> Result<Texture<'static>, Error> {
114 let raw_texture = unsafe { SDL_CreateGPUTexture(self.raw(), &create_info.inner) };
115 if raw_texture.is_null() {
116 Err(get_error())
117 } else {
118 Ok(Texture::new(
119 self,
120 raw_texture,
121 create_info.inner.width,
122 create_info.inner.height,
123 ))
124 }
125 }
126
127 #[doc(alias = "SDL_SetGPUViewport")]
128 pub fn set_viewport(&self, render_pass: &RenderPass, viewport: SDL_GPUViewport) {
129 unsafe { SDL_SetGPUViewport(render_pass.inner, &viewport) }
130 }
131
132 pub fn get_swapchain_texture_format(&self, w: &crate::video::Window) -> TextureFormat {
133 unsafe { std::mem::transmute(SDL_GetGPUSwapchainTextureFormat(self.inner.0, w.raw()).0) }
134 }
135
136 #[doc(alias = "SDL_BeginGPURenderPass")]
138 pub fn begin_render_pass(
139 &self,
140 command_buffer: &CommandBuffer,
141 color_info: &[ColorTargetInfo],
142 depth_stencil_target: Option<&DepthStencilTargetInfo>,
143 ) -> Result<RenderPass, Error> {
144 let p = unsafe {
145 SDL_BeginGPURenderPass(
146 command_buffer.inner,
147 color_info.as_ptr() as *const SDL_GPUColorTargetInfo, color_info.len() as u32,
149 if let Some(p) = depth_stencil_target {
150 p as *const _ as *const SDL_GPUDepthStencilTargetInfo } else {
152 std::ptr::null()
153 },
154 )
155 };
156 if !p.is_null() {
157 Ok(RenderPass { inner: p })
158 } else {
159 Err(get_error())
160 }
161 }
162
163 #[doc(alias = "SDL_EndGPURenderPass")]
164 pub fn end_render_pass(&self, pass: RenderPass) {
165 unsafe {
166 sys::gpu::SDL_EndGPURenderPass(pass.inner);
167 }
168 }
169
170 #[doc(alias = "SDL_BeginGPUCopyPass")]
171 pub fn begin_copy_pass(&self, command_buffer: &CommandBuffer) -> Result<CopyPass, Error> {
172 let p = unsafe { SDL_BeginGPUCopyPass(command_buffer.inner) };
173 if !p.is_null() {
174 Ok(CopyPass { inner: p })
175 } else {
176 Err(get_error())
177 }
178 }
179 #[doc(alias = "SDL_EndGPUCopyPass")]
180 pub fn end_copy_pass(&self, pass: CopyPass) {
181 unsafe {
182 sys::gpu::SDL_EndGPUCopyPass(pass.inner);
183 }
184 }
185
186 #[doc(alias = "SDL_BeginGPUComputePass")]
187 pub fn begin_compute_pass(
188 &self,
189 command_buffer: &CommandBuffer,
190 storage_texture_bindings: &[StorageTextureReadWriteBinding],
191 storage_buffer_bindings: &[StorageBufferReadWriteBinding],
192 ) -> Result<ComputePass, Error> {
193 let p = unsafe {
194 SDL_BeginGPUComputePass(
195 command_buffer.inner,
196 storage_texture_bindings.as_ptr().cast(),
197 storage_buffer_bindings.len() as u32,
198 storage_buffer_bindings.as_ptr().cast(),
199 storage_buffer_bindings.len() as u32,
200 )
201 };
202 if !p.is_null() {
203 Ok(ComputePass { inner: p })
204 } else {
205 Err(get_error())
206 }
207 }
208 #[doc(alias = "SDL_EndGPUComputePass")]
209 pub fn end_compute_pass(&self, pass: ComputePass) {
210 unsafe {
211 sys::gpu::SDL_EndGPUComputePass(pass.inner);
212 }
213 }
214
215 pub fn create_graphics_pipeline<'a>(&'a self) -> GraphicsPipelineBuilder<'a> {
216 GraphicsPipelineBuilder::new(self)
217 }
218
219 pub fn create_compute_pipeline<'a>(&'a self) -> ComputePipelineBuilder<'a> {
220 ComputePipelineBuilder::new(self)
221 }
222
223 #[doc(alias = "SDL_GetGPUShaderFormats")]
224 pub fn get_shader_formats(&self) -> ShaderFormat {
225 unsafe { std::mem::transmute(sys::gpu::SDL_GetGPUShaderFormats(self.raw())) }
226 }
227
228 #[cfg(target_vendor = "uwp")]
230 #[doc(alias = "SDL_GDKSuspendGPU")]
231 pub fn gdk_suspend(&self) {
232 unsafe {
233 sys::gpu::SDL_GDKSuspendGPU(self.inner);
234 }
235 }
236
237 #[cfg(target_vendor = "uwp")]
238 #[doc(alias = "SDL_GDKResumeGPU")]
239 pub fn gdk_resume(&self) {
240 unsafe {
241 sys::gpu::SDL_GDKResumeGPU(self.inner);
242 }
243 }
244}