1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "SDL_internal.h" |
22 | #include "SDL_sysgpu.h" |
23 | |
24 | // FIXME: This could probably use SDL_ObjectValid |
25 | #define CHECK_DEVICE_MAGIC(device, retval) \ |
26 | if (device == NULL) { \ |
27 | SDL_SetError("Invalid GPU device"); \ |
28 | return retval; \ |
29 | } |
30 | |
31 | #define CHECK_COMMAND_BUFFER \ |
32 | if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ |
33 | SDL_assert_release(!"Command buffer already submitted!"); \ |
34 | return; \ |
35 | } |
36 | |
37 | #define CHECK_COMMAND_BUFFER_RETURN_FALSE \ |
38 | if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ |
39 | SDL_assert_release(!"Command buffer already submitted!"); \ |
40 | return false; \ |
41 | } |
42 | |
43 | #define CHECK_COMMAND_BUFFER_RETURN_NULL \ |
44 | if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ |
45 | SDL_assert_release(!"Command buffer already submitted!"); \ |
46 | return NULL; \ |
47 | } |
48 | |
49 | #define CHECK_ANY_PASS_IN_PROGRESS(msg, retval) \ |
50 | if ( \ |
51 | ((CommandBufferCommonHeader *)command_buffer)->render_pass.in_progress || \ |
52 | ((CommandBufferCommonHeader *)command_buffer)->compute_pass.in_progress || \ |
53 | ((CommandBufferCommonHeader *)command_buffer)->copy_pass.in_progress) { \ |
54 | SDL_assert_release(!msg); \ |
55 | return retval; \ |
56 | } |
57 | |
58 | #define CHECK_RENDERPASS \ |
59 | if (!((Pass *)render_pass)->in_progress) { \ |
60 | SDL_assert_release(!"Render pass not in progress!"); \ |
61 | return; \ |
62 | } |
63 | |
64 | #define CHECK_GRAPHICS_PIPELINE_BOUND \ |
65 | if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \ |
66 | SDL_assert_release(!"Graphics pipeline not bound!"); \ |
67 | return; \ |
68 | } |
69 | |
70 | #define CHECK_COMPUTEPASS \ |
71 | if (!((Pass *)compute_pass)->in_progress) { \ |
72 | SDL_assert_release(!"Compute pass not in progress!"); \ |
73 | return; \ |
74 | } |
75 | |
76 | #define CHECK_COMPUTE_PIPELINE_BOUND \ |
77 | if (!((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->compute_pipeline_bound) { \ |
78 | SDL_assert_release(!"Compute pipeline not bound!"); \ |
79 | return; \ |
80 | } |
81 | |
82 | #define CHECK_COPYPASS \ |
83 | if (!((Pass *)copy_pass)->in_progress) { \ |
84 | SDL_assert_release(!"Copy pass not in progress!"); \ |
85 | return; \ |
86 | } |
87 | |
88 | #define CHECK_TEXTUREFORMAT_ENUM_INVALID(enumval, retval) \ |
89 | if (enumval <= SDL_GPU_TEXTUREFORMAT_INVALID || enumval >= SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE) { \ |
90 | SDL_assert_release(!"Invalid texture format enum!"); \ |
91 | return retval; \ |
92 | } |
93 | |
94 | #define CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(enumval, retval) \ |
95 | if (enumval <= SDL_GPU_VERTEXELEMENTFORMAT_INVALID || enumval >= SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE) { \ |
96 | SDL_assert_release(!"Invalid vertex format enum!"); \ |
97 | return retval; \ |
98 | } |
99 | |
100 | #define CHECK_COMPAREOP_ENUM_INVALID(enumval, retval) \ |
101 | if (enumval <= SDL_GPU_COMPAREOP_INVALID || enumval >= SDL_GPU_COMPAREOP_MAX_ENUM_VALUE) { \ |
102 | SDL_assert_release(!"Invalid compare op enum!"); \ |
103 | return retval; \ |
104 | } |
105 | |
106 | #define CHECK_STENCILOP_ENUM_INVALID(enumval, retval) \ |
107 | if (enumval <= SDL_GPU_STENCILOP_INVALID || enumval >= SDL_GPU_STENCILOP_MAX_ENUM_VALUE) { \ |
108 | SDL_assert_release(!"Invalid stencil op enum!"); \ |
109 | return retval; \ |
110 | } |
111 | |
112 | #define CHECK_BLENDOP_ENUM_INVALID(enumval, retval) \ |
113 | if (enumval <= SDL_GPU_BLENDOP_INVALID || enumval >= SDL_GPU_BLENDOP_MAX_ENUM_VALUE) { \ |
114 | SDL_assert_release(!"Invalid blend op enum!"); \ |
115 | return retval; \ |
116 | } |
117 | |
118 | #define CHECK_BLENDFACTOR_ENUM_INVALID(enumval, retval) \ |
119 | if (enumval <= SDL_GPU_BLENDFACTOR_INVALID || enumval >= SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE) { \ |
120 | SDL_assert_release(!"Invalid blend factor enum!"); \ |
121 | return retval; \ |
122 | } |
123 | |
124 | #define CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(enumval, retval) \ |
125 | if (enumval < 0 || enumval >= SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE) { \ |
126 | SDL_assert_release(!"Invalid swapchain composition enum!"); \ |
127 | return retval; \ |
128 | } |
129 | |
130 | #define CHECK_PRESENTMODE_ENUM_INVALID(enumval, retval) \ |
131 | if (enumval < 0 || enumval >= SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE) { \ |
132 | SDL_assert_release(!"Invalid present mode enum!"); \ |
133 | return retval; \ |
134 | } |
135 | |
136 | #define COMMAND_BUFFER_DEVICE \ |
137 | ((CommandBufferCommonHeader *)command_buffer)->device |
138 | |
139 | #define RENDERPASS_COMMAND_BUFFER \ |
140 | ((Pass *)render_pass)->command_buffer |
141 | |
142 | #define RENDERPASS_DEVICE \ |
143 | ((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device |
144 | |
145 | #define COMPUTEPASS_COMMAND_BUFFER \ |
146 | ((Pass *)compute_pass)->command_buffer |
147 | |
148 | #define COMPUTEPASS_DEVICE \ |
149 | ((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device |
150 | |
151 | #define COPYPASS_COMMAND_BUFFER \ |
152 | ((Pass *)copy_pass)->command_buffer |
153 | |
154 | #define COPYPASS_DEVICE \ |
155 | ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device |
156 | |
157 | // Drivers |
158 | |
159 | #ifndef SDL_GPU_DISABLED |
160 | static const SDL_GPUBootstrap *backends[] = { |
161 | #ifdef SDL_GPU_PRIVATE |
162 | &PrivateGPUDriver, |
163 | #endif |
164 | #ifdef SDL_GPU_METAL |
165 | &MetalDriver, |
166 | #endif |
167 | #ifdef SDL_GPU_VULKAN |
168 | &VulkanDriver, |
169 | #endif |
170 | #ifdef SDL_GPU_D3D12 |
171 | &D3D12Driver, |
172 | #endif |
173 | NULL |
174 | }; |
175 | #endif // !SDL_GPU_DISABLED |
176 | |
177 | // Internal Utility Functions |
178 | |
179 | SDL_GPUGraphicsPipeline *SDL_GPU_FetchBlitPipeline( |
180 | SDL_GPUDevice *device, |
181 | SDL_GPUTextureType source_texture_type, |
182 | SDL_GPUTextureFormat destination_format, |
183 | SDL_GPUShader *blit_vertex_shader, |
184 | SDL_GPUShader *blit_from_2d_shader, |
185 | SDL_GPUShader *blit_from_2d_array_shader, |
186 | SDL_GPUShader *blit_from_3d_shader, |
187 | SDL_GPUShader *blit_from_cube_shader, |
188 | SDL_GPUShader *blit_from_cube_array_shader, |
189 | BlitPipelineCacheEntry **blit_pipelines, |
190 | Uint32 *blit_pipeline_count, |
191 | Uint32 *blit_pipeline_capacity) |
192 | { |
193 | SDL_GPUGraphicsPipelineCreateInfo blit_pipeline_create_info; |
194 | SDL_GPUColorTargetDescription color_target_desc; |
195 | SDL_GPUGraphicsPipeline *pipeline; |
196 | |
197 | if (blit_pipeline_count == NULL) { |
198 | // use pre-created, format-agnostic pipelines |
199 | return (*blit_pipelines)[source_texture_type].pipeline; |
200 | } |
201 | |
202 | for (Uint32 i = 0; i < *blit_pipeline_count; i += 1) { |
203 | if ((*blit_pipelines)[i].type == source_texture_type && (*blit_pipelines)[i].format == destination_format) { |
204 | return (*blit_pipelines)[i].pipeline; |
205 | } |
206 | } |
207 | |
208 | // No pipeline found, we'll need to make one! |
209 | SDL_zero(blit_pipeline_create_info); |
210 | |
211 | SDL_zero(color_target_desc); |
212 | color_target_desc.blend_state.color_write_mask = 0xF; |
213 | color_target_desc.format = destination_format; |
214 | |
215 | blit_pipeline_create_info.target_info.color_target_descriptions = &color_target_desc; |
216 | blit_pipeline_create_info.target_info.num_color_targets = 1; |
217 | blit_pipeline_create_info.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; // arbitrary |
218 | blit_pipeline_create_info.target_info.has_depth_stencil_target = false; |
219 | |
220 | blit_pipeline_create_info.vertex_shader = blit_vertex_shader; |
221 | if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE) { |
222 | blit_pipeline_create_info.fragment_shader = blit_from_cube_shader; |
223 | } else if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { |
224 | blit_pipeline_create_info.fragment_shader = blit_from_cube_array_shader; |
225 | } else if (source_texture_type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { |
226 | blit_pipeline_create_info.fragment_shader = blit_from_2d_array_shader; |
227 | } else if (source_texture_type == SDL_GPU_TEXTURETYPE_3D) { |
228 | blit_pipeline_create_info.fragment_shader = blit_from_3d_shader; |
229 | } else { |
230 | blit_pipeline_create_info.fragment_shader = blit_from_2d_shader; |
231 | } |
232 | |
233 | blit_pipeline_create_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; |
234 | blit_pipeline_create_info.multisample_state.enable_mask = false; |
235 | |
236 | blit_pipeline_create_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; |
237 | |
238 | pipeline = SDL_CreateGPUGraphicsPipeline( |
239 | device, |
240 | &blit_pipeline_create_info); |
241 | |
242 | if (pipeline == NULL) { |
243 | SDL_SetError("Failed to create GPU pipeline for blit" ); |
244 | return NULL; |
245 | } |
246 | |
247 | // Cache the new pipeline |
248 | EXPAND_ARRAY_IF_NEEDED( |
249 | (*blit_pipelines), |
250 | BlitPipelineCacheEntry, |
251 | *blit_pipeline_count + 1, |
252 | *blit_pipeline_capacity, |
253 | *blit_pipeline_capacity * 2); |
254 | |
255 | (*blit_pipelines)[*blit_pipeline_count].pipeline = pipeline; |
256 | (*blit_pipelines)[*blit_pipeline_count].type = source_texture_type; |
257 | (*blit_pipelines)[*blit_pipeline_count].format = destination_format; |
258 | *blit_pipeline_count += 1; |
259 | |
260 | return pipeline; |
261 | } |
262 | |
263 | void SDL_GPU_BlitCommon( |
264 | SDL_GPUCommandBuffer *command_buffer, |
265 | const SDL_GPUBlitInfo *info, |
266 | SDL_GPUSampler *blit_linear_sampler, |
267 | SDL_GPUSampler *blit_nearest_sampler, |
268 | SDL_GPUShader *blit_vertex_shader, |
269 | SDL_GPUShader *blit_from_2d_shader, |
270 | SDL_GPUShader *blit_from_2d_array_shader, |
271 | SDL_GPUShader *blit_from_3d_shader, |
272 | SDL_GPUShader *blit_from_cube_shader, |
273 | SDL_GPUShader *blit_from_cube_array_shader, |
274 | BlitPipelineCacheEntry **blit_pipelines, |
275 | Uint32 *blit_pipeline_count, |
276 | Uint32 *blit_pipeline_capacity) |
277 | { |
278 | CommandBufferCommonHeader * = (CommandBufferCommonHeader *)command_buffer; |
279 | SDL_GPURenderPass *render_pass; |
280 | TextureCommonHeader * = (TextureCommonHeader *)info->source.texture; |
281 | TextureCommonHeader * = (TextureCommonHeader *)info->destination.texture; |
282 | SDL_GPUGraphicsPipeline *blit_pipeline; |
283 | SDL_GPUColorTargetInfo color_target_info; |
284 | SDL_GPUViewport viewport; |
285 | SDL_GPUTextureSamplerBinding texture_sampler_binding; |
286 | BlitFragmentUniforms blit_fragment_uniforms; |
287 | Uint32 layer_divisor; |
288 | |
289 | blit_pipeline = SDL_GPU_FetchBlitPipeline( |
290 | cmdbufHeader->device, |
291 | src_header->info.type, |
292 | dst_header->info.format, |
293 | blit_vertex_shader, |
294 | blit_from_2d_shader, |
295 | blit_from_2d_array_shader, |
296 | blit_from_3d_shader, |
297 | blit_from_cube_shader, |
298 | blit_from_cube_array_shader, |
299 | blit_pipelines, |
300 | blit_pipeline_count, |
301 | blit_pipeline_capacity); |
302 | |
303 | SDL_assert(blit_pipeline != NULL); |
304 | |
305 | color_target_info.load_op = info->load_op; |
306 | color_target_info.clear_color = info->clear_color; |
307 | color_target_info.store_op = SDL_GPU_STOREOP_STORE; |
308 | |
309 | color_target_info.texture = info->destination.texture; |
310 | color_target_info.mip_level = info->destination.mip_level; |
311 | color_target_info.layer_or_depth_plane = info->destination.layer_or_depth_plane; |
312 | color_target_info.cycle = info->cycle; |
313 | |
314 | render_pass = SDL_BeginGPURenderPass( |
315 | command_buffer, |
316 | &color_target_info, |
317 | 1, |
318 | NULL); |
319 | |
320 | viewport.x = (float)info->destination.x; |
321 | viewport.y = (float)info->destination.y; |
322 | viewport.w = (float)info->destination.w; |
323 | viewport.h = (float)info->destination.h; |
324 | viewport.min_depth = 0; |
325 | viewport.max_depth = 1; |
326 | |
327 | SDL_SetGPUViewport( |
328 | render_pass, |
329 | &viewport); |
330 | |
331 | SDL_BindGPUGraphicsPipeline( |
332 | render_pass, |
333 | blit_pipeline); |
334 | |
335 | texture_sampler_binding.texture = info->source.texture; |
336 | texture_sampler_binding.sampler = |
337 | info->filter == SDL_GPU_FILTER_NEAREST ? blit_nearest_sampler : blit_linear_sampler; |
338 | |
339 | SDL_BindGPUFragmentSamplers( |
340 | render_pass, |
341 | 0, |
342 | &texture_sampler_binding, |
343 | 1); |
344 | |
345 | blit_fragment_uniforms.left = (float)info->source.x / (src_header->info.width >> info->source.mip_level); |
346 | blit_fragment_uniforms.top = (float)info->source.y / (src_header->info.height >> info->source.mip_level); |
347 | blit_fragment_uniforms.width = (float)info->source.w / (src_header->info.width >> info->source.mip_level); |
348 | blit_fragment_uniforms.height = (float)info->source.h / (src_header->info.height >> info->source.mip_level); |
349 | blit_fragment_uniforms.mip_level = info->source.mip_level; |
350 | |
351 | layer_divisor = (src_header->info.type == SDL_GPU_TEXTURETYPE_3D) ? src_header->info.layer_count_or_depth : 1; |
352 | blit_fragment_uniforms.layer_or_depth = (float)info->source.layer_or_depth_plane / layer_divisor; |
353 | |
354 | if (info->flip_mode & SDL_FLIP_HORIZONTAL) { |
355 | blit_fragment_uniforms.left += blit_fragment_uniforms.width; |
356 | blit_fragment_uniforms.width *= -1; |
357 | } |
358 | |
359 | if (info->flip_mode & SDL_FLIP_VERTICAL) { |
360 | blit_fragment_uniforms.top += blit_fragment_uniforms.height; |
361 | blit_fragment_uniforms.height *= -1; |
362 | } |
363 | |
364 | SDL_PushGPUFragmentUniformData( |
365 | command_buffer, |
366 | 0, |
367 | &blit_fragment_uniforms, |
368 | sizeof(blit_fragment_uniforms)); |
369 | |
370 | SDL_DrawGPUPrimitives(render_pass, 3, 1, 0, 0); |
371 | SDL_EndGPURenderPass(render_pass); |
372 | } |
373 | |
374 | // Driver Functions |
375 | |
376 | #ifndef SDL_GPU_DISABLED |
377 | static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props) |
378 | { |
379 | Uint32 i; |
380 | SDL_GPUShaderFormat format_flags = 0; |
381 | const char *gpudriver; |
382 | SDL_VideoDevice *_this = SDL_GetVideoDevice(); |
383 | |
384 | if (_this == NULL) { |
385 | SDL_SetError("Video subsystem not initialized" ); |
386 | return NULL; |
387 | } |
388 | |
389 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN, false)) { |
390 | format_flags |= SDL_GPU_SHADERFORMAT_PRIVATE; |
391 | } |
392 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) { |
393 | format_flags |= SDL_GPU_SHADERFORMAT_SPIRV; |
394 | } |
395 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, false)) { |
396 | format_flags |= SDL_GPU_SHADERFORMAT_DXBC; |
397 | } |
398 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, false)) { |
399 | format_flags |= SDL_GPU_SHADERFORMAT_DXIL; |
400 | } |
401 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, false)) { |
402 | format_flags |= SDL_GPU_SHADERFORMAT_MSL; |
403 | } |
404 | if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, false)) { |
405 | format_flags |= SDL_GPU_SHADERFORMAT_METALLIB; |
406 | } |
407 | |
408 | gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER); |
409 | if (gpudriver == NULL) { |
410 | gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL); |
411 | } |
412 | |
413 | // Environment/Properties override... |
414 | if (gpudriver != NULL) { |
415 | for (i = 0; backends[i]; i += 1) { |
416 | if (SDL_strcasecmp(gpudriver, backends[i]->name) == 0) { |
417 | if (!(backends[i]->shader_formats & format_flags)) { |
418 | SDL_SetError("Required shader format for backend %s not provided!" , gpudriver); |
419 | return NULL; |
420 | } |
421 | if (backends[i]->PrepareDriver(_this)) { |
422 | return backends[i]; |
423 | } |
424 | } |
425 | } |
426 | |
427 | SDL_SetError("SDL_HINT_GPU_DRIVER %s unsupported!" , gpudriver); |
428 | return NULL; |
429 | } |
430 | |
431 | for (i = 0; backends[i]; i += 1) { |
432 | if ((backends[i]->shader_formats & format_flags) == 0) { |
433 | // Don't select a backend which doesn't support the app's shaders. |
434 | continue; |
435 | } |
436 | if (backends[i]->PrepareDriver(_this)) { |
437 | return backends[i]; |
438 | } |
439 | } |
440 | |
441 | SDL_SetError("No supported SDL_GPU backend found!" ); |
442 | return NULL; |
443 | } |
444 | |
445 | static void SDL_GPU_FillProperties( |
446 | SDL_PropertiesID props, |
447 | SDL_GPUShaderFormat format_flags, |
448 | bool debug_mode, |
449 | const char *name) |
450 | { |
451 | if (format_flags & SDL_GPU_SHADERFORMAT_PRIVATE) { |
452 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN, true); |
453 | } |
454 | if (format_flags & SDL_GPU_SHADERFORMAT_SPIRV) { |
455 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, true); |
456 | } |
457 | if (format_flags & SDL_GPU_SHADERFORMAT_DXBC) { |
458 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, true); |
459 | } |
460 | if (format_flags & SDL_GPU_SHADERFORMAT_DXIL) { |
461 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, true); |
462 | } |
463 | if (format_flags & SDL_GPU_SHADERFORMAT_MSL) { |
464 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, true); |
465 | } |
466 | if (format_flags & SDL_GPU_SHADERFORMAT_METALLIB) { |
467 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, true); |
468 | } |
469 | SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, debug_mode); |
470 | SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name); |
471 | } |
472 | #endif // SDL_GPU_DISABLED |
473 | |
474 | bool SDL_GPUSupportsShaderFormats( |
475 | SDL_GPUShaderFormat format_flags, |
476 | const char *name) |
477 | { |
478 | #ifndef SDL_GPU_DISABLED |
479 | bool result; |
480 | SDL_PropertiesID props = SDL_CreateProperties(); |
481 | SDL_GPU_FillProperties(props, format_flags, false, name); |
482 | result = SDL_GPUSupportsProperties(props); |
483 | SDL_DestroyProperties(props); |
484 | return result; |
485 | #else |
486 | SDL_SetError("SDL not built with GPU support" ); |
487 | return false; |
488 | #endif |
489 | } |
490 | |
491 | bool SDL_GPUSupportsProperties(SDL_PropertiesID props) |
492 | { |
493 | #ifndef SDL_GPU_DISABLED |
494 | return (SDL_GPUSelectBackend(props) != NULL); |
495 | #else |
496 | SDL_SetError("SDL not built with GPU support" ); |
497 | return false; |
498 | #endif |
499 | } |
500 | |
501 | SDL_GPUDevice *SDL_CreateGPUDevice( |
502 | SDL_GPUShaderFormat format_flags, |
503 | bool debug_mode, |
504 | const char *name) |
505 | { |
506 | #ifndef SDL_GPU_DISABLED |
507 | SDL_GPUDevice *result; |
508 | SDL_PropertiesID props = SDL_CreateProperties(); |
509 | SDL_GPU_FillProperties(props, format_flags, debug_mode, name); |
510 | result = SDL_CreateGPUDeviceWithProperties(props); |
511 | SDL_DestroyProperties(props); |
512 | return result; |
513 | #else |
514 | SDL_SetError("SDL not built with GPU support" ); |
515 | return NULL; |
516 | #endif // SDL_GPU_DISABLED |
517 | } |
518 | |
519 | SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props) |
520 | { |
521 | #ifndef SDL_GPU_DISABLED |
522 | bool debug_mode; |
523 | bool preferLowPower; |
524 | SDL_GPUDevice *result = NULL; |
525 | const SDL_GPUBootstrap *selectedBackend; |
526 | |
527 | selectedBackend = SDL_GPUSelectBackend(props); |
528 | if (selectedBackend != NULL) { |
529 | debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, true); |
530 | preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false); |
531 | |
532 | result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props); |
533 | if (result != NULL) { |
534 | result->backend = selectedBackend->name; |
535 | result->shader_formats = selectedBackend->shader_formats; |
536 | result->debug_mode = debug_mode; |
537 | } |
538 | } |
539 | return result; |
540 | #else |
541 | SDL_SetError("SDL not built with GPU support" ); |
542 | return NULL; |
543 | #endif // SDL_GPU_DISABLED |
544 | } |
545 | |
546 | void SDL_DestroyGPUDevice(SDL_GPUDevice *device) |
547 | { |
548 | CHECK_DEVICE_MAGIC(device, ); |
549 | |
550 | device->DestroyDevice(device); |
551 | } |
552 | |
553 | int SDL_GetNumGPUDrivers(void) |
554 | { |
555 | #ifndef SDL_GPU_DISABLED |
556 | return SDL_arraysize(backends) - 1; |
557 | #else |
558 | return 0; |
559 | #endif |
560 | } |
561 | |
562 | const char * SDL_GetGPUDriver(int index) |
563 | { |
564 | if (index < 0 || index >= SDL_GetNumGPUDrivers()) { |
565 | SDL_InvalidParamError("index" ); |
566 | return NULL; |
567 | } |
568 | #ifndef SDL_GPU_DISABLED |
569 | return backends[index]->name; |
570 | #else |
571 | return NULL; |
572 | #endif |
573 | } |
574 | |
575 | const char * SDL_GetGPUDeviceDriver(SDL_GPUDevice *device) |
576 | { |
577 | CHECK_DEVICE_MAGIC(device, NULL); |
578 | |
579 | return device->backend; |
580 | } |
581 | |
582 | SDL_GPUShaderFormat SDL_GetGPUShaderFormats(SDL_GPUDevice *device) |
583 | { |
584 | CHECK_DEVICE_MAGIC(device, SDL_GPU_SHADERFORMAT_INVALID); |
585 | |
586 | return device->shader_formats; |
587 | } |
588 | |
589 | Uint32 SDL_GPUTextureFormatTexelBlockSize( |
590 | SDL_GPUTextureFormat format) |
591 | { |
592 | switch (format) { |
593 | case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM: |
594 | case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB: |
595 | case SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM: |
596 | return 8; |
597 | case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM: |
598 | case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM: |
599 | case SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM: |
600 | case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM: |
601 | case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT: |
602 | case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT: |
603 | case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB: |
604 | case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB: |
605 | case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB: |
606 | return 16; |
607 | case SDL_GPU_TEXTUREFORMAT_R8_UNORM: |
608 | case SDL_GPU_TEXTUREFORMAT_R8_SNORM: |
609 | case SDL_GPU_TEXTUREFORMAT_A8_UNORM: |
610 | case SDL_GPU_TEXTUREFORMAT_R8_UINT: |
611 | case SDL_GPU_TEXTUREFORMAT_R8_INT: |
612 | return 1; |
613 | case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM: |
614 | case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM: |
615 | case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM: |
616 | case SDL_GPU_TEXTUREFORMAT_R16_FLOAT: |
617 | case SDL_GPU_TEXTUREFORMAT_R8G8_SNORM: |
618 | case SDL_GPU_TEXTUREFORMAT_R8G8_UNORM: |
619 | case SDL_GPU_TEXTUREFORMAT_R8G8_UINT: |
620 | case SDL_GPU_TEXTUREFORMAT_R8G8_INT: |
621 | case SDL_GPU_TEXTUREFORMAT_R16_UNORM: |
622 | case SDL_GPU_TEXTUREFORMAT_R16_SNORM: |
623 | case SDL_GPU_TEXTUREFORMAT_R16_UINT: |
624 | case SDL_GPU_TEXTUREFORMAT_R16_INT: |
625 | case SDL_GPU_TEXTUREFORMAT_D16_UNORM: |
626 | return 2; |
627 | case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM: |
628 | case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM: |
629 | case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: |
630 | case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: |
631 | case SDL_GPU_TEXTUREFORMAT_R32_FLOAT: |
632 | case SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT: |
633 | case SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT: |
634 | case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM: |
635 | case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM: |
636 | case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT: |
637 | case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT: |
638 | case SDL_GPU_TEXTUREFORMAT_R16G16_UINT: |
639 | case SDL_GPU_TEXTUREFORMAT_R16G16_INT: |
640 | case SDL_GPU_TEXTUREFORMAT_R16G16_UNORM: |
641 | case SDL_GPU_TEXTUREFORMAT_R16G16_SNORM: |
642 | case SDL_GPU_TEXTUREFORMAT_D24_UNORM: |
643 | case SDL_GPU_TEXTUREFORMAT_D32_FLOAT: |
644 | case SDL_GPU_TEXTUREFORMAT_R32_UINT: |
645 | case SDL_GPU_TEXTUREFORMAT_R32_INT: |
646 | case SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT: |
647 | return 4; |
648 | case SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT: |
649 | return 5; |
650 | case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT: |
651 | case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM: |
652 | case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM: |
653 | case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT: |
654 | case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT: |
655 | case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT: |
656 | case SDL_GPU_TEXTUREFORMAT_R32G32_UINT: |
657 | case SDL_GPU_TEXTUREFORMAT_R32G32_INT: |
658 | return 8; |
659 | case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT: |
660 | case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT: |
661 | case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT: |
662 | return 16; |
663 | case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM: |
664 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM: |
665 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM: |
666 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM: |
667 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM: |
668 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM: |
669 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM: |
670 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM: |
671 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM: |
672 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM: |
673 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM: |
674 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM: |
675 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM: |
676 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM: |
677 | case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB: |
678 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB: |
679 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB: |
680 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB: |
681 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB: |
682 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB: |
683 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB: |
684 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB: |
685 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB: |
686 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB: |
687 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB: |
688 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB: |
689 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB: |
690 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB: |
691 | case SDL_GPU_TEXTUREFORMAT_ASTC_4x4_FLOAT: |
692 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x4_FLOAT: |
693 | case SDL_GPU_TEXTUREFORMAT_ASTC_5x5_FLOAT: |
694 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x5_FLOAT: |
695 | case SDL_GPU_TEXTUREFORMAT_ASTC_6x6_FLOAT: |
696 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x5_FLOAT: |
697 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x6_FLOAT: |
698 | case SDL_GPU_TEXTUREFORMAT_ASTC_8x8_FLOAT: |
699 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x5_FLOAT: |
700 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x6_FLOAT: |
701 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x8_FLOAT: |
702 | case SDL_GPU_TEXTUREFORMAT_ASTC_10x10_FLOAT: |
703 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x10_FLOAT: |
704 | case SDL_GPU_TEXTUREFORMAT_ASTC_12x12_FLOAT: |
705 | return 16; |
706 | default: |
707 | SDL_assert_release(!"Unrecognized TextureFormat!" ); |
708 | return 0; |
709 | } |
710 | } |
711 | |
712 | bool SDL_GPUTextureSupportsFormat( |
713 | SDL_GPUDevice *device, |
714 | SDL_GPUTextureFormat format, |
715 | SDL_GPUTextureType type, |
716 | SDL_GPUTextureUsageFlags usage) |
717 | { |
718 | CHECK_DEVICE_MAGIC(device, false); |
719 | |
720 | if (device->debug_mode) { |
721 | CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false) |
722 | } |
723 | |
724 | return device->SupportsTextureFormat( |
725 | device->driverData, |
726 | format, |
727 | type, |
728 | usage); |
729 | } |
730 | |
731 | bool SDL_GPUTextureSupportsSampleCount( |
732 | SDL_GPUDevice *device, |
733 | SDL_GPUTextureFormat format, |
734 | SDL_GPUSampleCount sample_count) |
735 | { |
736 | CHECK_DEVICE_MAGIC(device, 0); |
737 | |
738 | if (device->debug_mode) { |
739 | CHECK_TEXTUREFORMAT_ENUM_INVALID(format, 0) |
740 | } |
741 | |
742 | return device->SupportsSampleCount( |
743 | device->driverData, |
744 | format, |
745 | sample_count); |
746 | } |
747 | |
748 | // State Creation |
749 | |
750 | SDL_GPUComputePipeline *SDL_CreateGPUComputePipeline( |
751 | SDL_GPUDevice *device, |
752 | const SDL_GPUComputePipelineCreateInfo *createinfo) |
753 | { |
754 | CHECK_DEVICE_MAGIC(device, NULL); |
755 | if (createinfo == NULL) { |
756 | SDL_InvalidParamError("createinfo" ); |
757 | return NULL; |
758 | } |
759 | |
760 | if (device->debug_mode) { |
761 | if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) { |
762 | SDL_assert_release(!"Shader format cannot be INVALID!" ); |
763 | return NULL; |
764 | } |
765 | if (!(createinfo->format & device->shader_formats)) { |
766 | SDL_assert_release(!"Incompatible shader format for GPU backend" ); |
767 | return NULL; |
768 | } |
769 | if (createinfo->num_readwrite_storage_textures > MAX_COMPUTE_WRITE_TEXTURES) { |
770 | SDL_assert_release(!"Compute pipeline write-only texture count cannot be higher than 8!" ); |
771 | return NULL; |
772 | } |
773 | if (createinfo->num_readwrite_storage_buffers > MAX_COMPUTE_WRITE_BUFFERS) { |
774 | SDL_assert_release(!"Compute pipeline write-only buffer count cannot be higher than 8!" ); |
775 | return NULL; |
776 | } |
777 | if (createinfo->threadcount_x == 0 || |
778 | createinfo->threadcount_y == 0 || |
779 | createinfo->threadcount_z == 0) { |
780 | SDL_assert_release(!"Compute pipeline threadCount dimensions must be at least 1!" ); |
781 | return NULL; |
782 | } |
783 | } |
784 | |
785 | return device->CreateComputePipeline( |
786 | device->driverData, |
787 | createinfo); |
788 | } |
789 | |
790 | SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( |
791 | SDL_GPUDevice *device, |
792 | const SDL_GPUGraphicsPipelineCreateInfo *graphicsPipelineCreateInfo) |
793 | { |
794 | CHECK_DEVICE_MAGIC(device, NULL); |
795 | if (graphicsPipelineCreateInfo == NULL) { |
796 | SDL_InvalidParamError("graphicsPipelineCreateInfo" ); |
797 | return NULL; |
798 | } |
799 | |
800 | if (device->debug_mode) { |
801 | if (graphicsPipelineCreateInfo->vertex_shader == NULL) { |
802 | SDL_assert_release(!"Vertex shader cannot be NULL!" ); |
803 | return NULL; |
804 | } |
805 | if (graphicsPipelineCreateInfo->fragment_shader == NULL) { |
806 | SDL_assert_release(!"Fragment shader cannot be NULL!" ); |
807 | return NULL; |
808 | } |
809 | if (graphicsPipelineCreateInfo->target_info.num_color_targets > 0 && graphicsPipelineCreateInfo->target_info.color_target_descriptions == NULL) { |
810 | SDL_assert_release(!"Color target descriptions array pointer cannot be NULL if num_color_targets is greater than zero!" ); |
811 | return NULL; |
812 | } |
813 | for (Uint32 i = 0; i < graphicsPipelineCreateInfo->target_info.num_color_targets; i += 1) { |
814 | CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, NULL); |
815 | if (IsDepthFormat(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format)) { |
816 | SDL_assert_release(!"Color target formats cannot be a depth format!" ); |
817 | return NULL; |
818 | } |
819 | if (!SDL_GPUTextureSupportsFormat(device, graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) { |
820 | SDL_assert_release(!"Format is not supported for color targets on this device!" ); |
821 | return NULL; |
822 | } |
823 | if (graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state.enable_blend) { |
824 | const SDL_GPUColorTargetBlendState *blend_state = &graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state; |
825 | CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_color_blendfactor, NULL) |
826 | CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_color_blendfactor, NULL) |
827 | CHECK_BLENDOP_ENUM_INVALID(blend_state->color_blend_op, NULL) |
828 | CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_alpha_blendfactor, NULL) |
829 | CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_alpha_blendfactor, NULL) |
830 | CHECK_BLENDOP_ENUM_INVALID(blend_state->alpha_blend_op, NULL) |
831 | } |
832 | } |
833 | if (graphicsPipelineCreateInfo->target_info.has_depth_stencil_target) { |
834 | CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.depth_stencil_format, NULL); |
835 | if (!IsDepthFormat(graphicsPipelineCreateInfo->target_info.depth_stencil_format)) { |
836 | SDL_assert_release(!"Depth-stencil target format must be a depth format!" ); |
837 | return NULL; |
838 | } |
839 | if (!SDL_GPUTextureSupportsFormat(device, graphicsPipelineCreateInfo->target_info.depth_stencil_format, SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) { |
840 | SDL_assert_release(!"Format is not supported for depth targets on this device!" ); |
841 | return NULL; |
842 | } |
843 | } |
844 | if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions == NULL) { |
845 | SDL_assert_release(!"Vertex buffer descriptions array pointer cannot be NULL!" ); |
846 | return NULL; |
847 | } |
848 | if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > MAX_VERTEX_BUFFERS) { |
849 | SDL_assert_release(!"The number of vertex buffer descriptions in a vertex input state must not exceed 16!" ); |
850 | return NULL; |
851 | } |
852 | if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes == NULL) { |
853 | SDL_assert_release(!"Vertex attributes array pointer cannot be NULL!" ); |
854 | return NULL; |
855 | } |
856 | if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > MAX_VERTEX_ATTRIBUTES) { |
857 | SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!" ); |
858 | return NULL; |
859 | } |
860 | for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers; i += 1) { |
861 | if (graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions[i].instance_step_rate != 0) { |
862 | SDL_assert_release(!"For all vertex buffer descriptions, instance_step_rate must be 0!" ); |
863 | return NULL; |
864 | } |
865 | } |
866 | Uint32 locations[MAX_VERTEX_ATTRIBUTES]; |
867 | for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) { |
868 | CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL); |
869 | |
870 | locations[i] = graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].location; |
871 | for (Uint32 j = 0; j < i; j += 1) { |
872 | if (locations[j] == locations[i]) { |
873 | SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!" ); |
874 | return NULL; |
875 | } |
876 | } |
877 | } |
878 | if (graphicsPipelineCreateInfo->multisample_state.enable_mask) { |
879 | SDL_assert_release(!"For multisample states, enable_mask must be false!" ); |
880 | return NULL; |
881 | } |
882 | if (graphicsPipelineCreateInfo->multisample_state.sample_mask != 0) { |
883 | SDL_assert_release(!"For multisample states, sample_mask must be 0!" ); |
884 | return NULL; |
885 | } |
886 | if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) { |
887 | CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL) |
888 | } |
889 | if (graphicsPipelineCreateInfo->depth_stencil_state.enable_stencil_test) { |
890 | const SDL_GPUStencilOpState *stencil_state = &graphicsPipelineCreateInfo->depth_stencil_state.back_stencil_state; |
891 | CHECK_COMPAREOP_ENUM_INVALID(stencil_state->compare_op, NULL) |
892 | CHECK_STENCILOP_ENUM_INVALID(stencil_state->fail_op, NULL) |
893 | CHECK_STENCILOP_ENUM_INVALID(stencil_state->pass_op, NULL) |
894 | CHECK_STENCILOP_ENUM_INVALID(stencil_state->depth_fail_op, NULL) |
895 | } |
896 | } |
897 | |
898 | return device->CreateGraphicsPipeline( |
899 | device->driverData, |
900 | graphicsPipelineCreateInfo); |
901 | } |
902 | |
903 | SDL_GPUSampler *SDL_CreateGPUSampler( |
904 | SDL_GPUDevice *device, |
905 | const SDL_GPUSamplerCreateInfo *createinfo) |
906 | { |
907 | CHECK_DEVICE_MAGIC(device, NULL); |
908 | if (createinfo == NULL) { |
909 | SDL_InvalidParamError("createinfo" ); |
910 | return NULL; |
911 | } |
912 | |
913 | return device->CreateSampler( |
914 | device->driverData, |
915 | createinfo); |
916 | } |
917 | |
918 | SDL_GPUShader *SDL_CreateGPUShader( |
919 | SDL_GPUDevice *device, |
920 | const SDL_GPUShaderCreateInfo *createinfo) |
921 | { |
922 | CHECK_DEVICE_MAGIC(device, NULL); |
923 | if (createinfo == NULL) { |
924 | SDL_InvalidParamError("createinfo" ); |
925 | return NULL; |
926 | } |
927 | |
928 | if (device->debug_mode) { |
929 | if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) { |
930 | SDL_assert_release(!"Shader format cannot be INVALID!" ); |
931 | return NULL; |
932 | } |
933 | if (!(createinfo->format & device->shader_formats)) { |
934 | SDL_assert_release(!"Incompatible shader format for GPU backend" ); |
935 | return NULL; |
936 | } |
937 | } |
938 | |
939 | return device->CreateShader( |
940 | device->driverData, |
941 | createinfo); |
942 | } |
943 | |
944 | SDL_GPUTexture *SDL_CreateGPUTexture( |
945 | SDL_GPUDevice *device, |
946 | const SDL_GPUTextureCreateInfo *createinfo) |
947 | { |
948 | CHECK_DEVICE_MAGIC(device, NULL); |
949 | if (createinfo == NULL) { |
950 | SDL_InvalidParamError("createinfo" ); |
951 | return NULL; |
952 | } |
953 | |
954 | if (device->debug_mode) { |
955 | bool failed = false; |
956 | |
957 | const Uint32 MAX_2D_DIMENSION = 16384; |
958 | const Uint32 MAX_3D_DIMENSION = 2048; |
959 | |
960 | // Common checks for all texture types |
961 | CHECK_TEXTUREFORMAT_ENUM_INVALID(createinfo->format, NULL) |
962 | |
963 | if (createinfo->width <= 0 || createinfo->height <= 0 || createinfo->layer_count_or_depth <= 0) { |
964 | SDL_assert_release(!"For any texture: width, height, and layer_count_or_depth must be >= 1" ); |
965 | failed = true; |
966 | } |
967 | if (createinfo->num_levels <= 0) { |
968 | SDL_assert_release(!"For any texture: num_levels must be >= 1" ); |
969 | failed = true; |
970 | } |
971 | if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) { |
972 | SDL_assert_release(!"For any texture: usage cannot contain both GRAPHICS_STORAGE_READ and SAMPLER" ); |
973 | failed = true; |
974 | } |
975 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && |
976 | (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | |
977 | SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | |
978 | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | |
979 | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE))) { |
980 | SDL_assert_release(!"For multisample textures: usage cannot contain SAMPLER or STORAGE flags" ); |
981 | failed = true; |
982 | } |
983 | if (IsDepthFormat(createinfo->format) && (createinfo->usage & ~(SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER))) { |
984 | SDL_assert_release(!"For depth textures: usage cannot contain any flags except for DEPTH_STENCIL_TARGET and SAMPLER" ); |
985 | failed = true; |
986 | } |
987 | if (IsIntegerFormat(createinfo->format) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) { |
988 | SDL_assert_release(!"For any texture: usage cannot contain SAMPLER for textures with an integer format" ); |
989 | failed = true; |
990 | } |
991 | |
992 | if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) { |
993 | // Cubemap validation |
994 | if (createinfo->width != createinfo->height) { |
995 | SDL_assert_release(!"For cube textures: width and height must be identical" ); |
996 | failed = true; |
997 | } |
998 | if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) { |
999 | SDL_assert_release(!"For cube textures: width and height must be <= 16384" ); |
1000 | failed = true; |
1001 | } |
1002 | if (createinfo->layer_count_or_depth != 6) { |
1003 | SDL_assert_release(!"For cube textures: layer_count_or_depth must be 6" ); |
1004 | failed = true; |
1005 | } |
1006 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) { |
1007 | SDL_assert_release(!"For cube textures: sample_count must be SDL_GPU_SAMPLECOUNT_1" ); |
1008 | failed = true; |
1009 | } |
1010 | if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE, createinfo->usage)) { |
1011 | SDL_assert_release(!"For cube textures: the format is unsupported for the given usage" ); |
1012 | failed = true; |
1013 | } |
1014 | } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { |
1015 | // Cubemap array validation |
1016 | if (createinfo->width != createinfo->height) { |
1017 | SDL_assert_release(!"For cube array textures: width and height must be identical" ); |
1018 | failed = true; |
1019 | } |
1020 | if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) { |
1021 | SDL_assert_release(!"For cube array textures: width and height must be <= 16384" ); |
1022 | failed = true; |
1023 | } |
1024 | if (createinfo->layer_count_or_depth % 6 != 0) { |
1025 | SDL_assert_release(!"For cube array textures: layer_count_or_depth must be a multiple of 6" ); |
1026 | failed = true; |
1027 | } |
1028 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) { |
1029 | SDL_assert_release(!"For cube array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1" ); |
1030 | failed = true; |
1031 | } |
1032 | if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE_ARRAY, createinfo->usage)) { |
1033 | SDL_assert_release(!"For cube array textures: the format is unsupported for the given usage" ); |
1034 | failed = true; |
1035 | } |
1036 | } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { |
1037 | // 3D Texture Validation |
1038 | if (createinfo->width > MAX_3D_DIMENSION || createinfo->height > MAX_3D_DIMENSION || createinfo->layer_count_or_depth > MAX_3D_DIMENSION) { |
1039 | SDL_assert_release(!"For 3D textures: width, height, and layer_count_or_depth must be <= 2048" ); |
1040 | failed = true; |
1041 | } |
1042 | if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { |
1043 | SDL_assert_release(!"For 3D textures: usage must not contain DEPTH_STENCIL_TARGET" ); |
1044 | failed = true; |
1045 | } |
1046 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) { |
1047 | SDL_assert_release(!"For 3D textures: sample_count must be SDL_GPU_SAMPLECOUNT_1" ); |
1048 | failed = true; |
1049 | } |
1050 | if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_3D, createinfo->usage)) { |
1051 | SDL_assert_release(!"For 3D textures: the format is unsupported for the given usage" ); |
1052 | failed = true; |
1053 | } |
1054 | } else { |
1055 | if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { |
1056 | // Array Texture Validation |
1057 | if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { |
1058 | SDL_assert_release(!"For array textures: usage must not contain DEPTH_STENCIL_TARGET" ); |
1059 | failed = true; |
1060 | } |
1061 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) { |
1062 | SDL_assert_release(!"For array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1" ); |
1063 | failed = true; |
1064 | } |
1065 | } |
1066 | if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) { |
1067 | SDL_assert_release(!"For 2D multisample textures: num_levels must be 1" ); |
1068 | failed = true; |
1069 | } |
1070 | if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_2D, createinfo->usage)) { |
1071 | SDL_assert_release(!"For 2D textures: the format is unsupported for the given usage" ); |
1072 | failed = true; |
1073 | } |
1074 | } |
1075 | |
1076 | if (failed) { |
1077 | return NULL; |
1078 | } |
1079 | } |
1080 | |
1081 | return device->CreateTexture( |
1082 | device->driverData, |
1083 | createinfo); |
1084 | } |
1085 | |
1086 | SDL_GPUBuffer *SDL_CreateGPUBuffer( |
1087 | SDL_GPUDevice *device, |
1088 | const SDL_GPUBufferCreateInfo *createinfo) |
1089 | { |
1090 | CHECK_DEVICE_MAGIC(device, NULL); |
1091 | if (createinfo == NULL) { |
1092 | SDL_InvalidParamError("createinfo" ); |
1093 | return NULL; |
1094 | } |
1095 | |
1096 | const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, NULL); |
1097 | |
1098 | return device->CreateBuffer( |
1099 | device->driverData, |
1100 | createinfo->usage, |
1101 | createinfo->size, |
1102 | debugName); |
1103 | } |
1104 | |
1105 | SDL_GPUTransferBuffer *SDL_CreateGPUTransferBuffer( |
1106 | SDL_GPUDevice *device, |
1107 | const SDL_GPUTransferBufferCreateInfo *createinfo) |
1108 | { |
1109 | CHECK_DEVICE_MAGIC(device, NULL); |
1110 | if (createinfo == NULL) { |
1111 | SDL_InvalidParamError("createinfo" ); |
1112 | return NULL; |
1113 | } |
1114 | |
1115 | const char *debugName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING, NULL); |
1116 | |
1117 | return device->CreateTransferBuffer( |
1118 | device->driverData, |
1119 | createinfo->usage, |
1120 | createinfo->size, |
1121 | debugName); |
1122 | } |
1123 | |
1124 | // Debug Naming |
1125 | |
1126 | void SDL_SetGPUBufferName( |
1127 | SDL_GPUDevice *device, |
1128 | SDL_GPUBuffer *buffer, |
1129 | const char *text) |
1130 | { |
1131 | CHECK_DEVICE_MAGIC(device, ); |
1132 | if (buffer == NULL) { |
1133 | SDL_InvalidParamError("buffer" ); |
1134 | return; |
1135 | } |
1136 | if (text == NULL) { |
1137 | SDL_InvalidParamError("text" ); |
1138 | } |
1139 | |
1140 | device->SetBufferName( |
1141 | device->driverData, |
1142 | buffer, |
1143 | text); |
1144 | } |
1145 | |
1146 | void SDL_SetGPUTextureName( |
1147 | SDL_GPUDevice *device, |
1148 | SDL_GPUTexture *texture, |
1149 | const char *text) |
1150 | { |
1151 | CHECK_DEVICE_MAGIC(device, ); |
1152 | if (texture == NULL) { |
1153 | SDL_InvalidParamError("texture" ); |
1154 | return; |
1155 | } |
1156 | if (text == NULL) { |
1157 | SDL_InvalidParamError("text" ); |
1158 | } |
1159 | |
1160 | device->SetTextureName( |
1161 | device->driverData, |
1162 | texture, |
1163 | text); |
1164 | } |
1165 | |
1166 | void SDL_InsertGPUDebugLabel( |
1167 | SDL_GPUCommandBuffer *command_buffer, |
1168 | const char *text) |
1169 | { |
1170 | if (command_buffer == NULL) { |
1171 | SDL_InvalidParamError("command_buffer" ); |
1172 | return; |
1173 | } |
1174 | if (text == NULL) { |
1175 | SDL_InvalidParamError("text" ); |
1176 | return; |
1177 | } |
1178 | |
1179 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1180 | CHECK_COMMAND_BUFFER |
1181 | } |
1182 | |
1183 | COMMAND_BUFFER_DEVICE->InsertDebugLabel( |
1184 | command_buffer, |
1185 | text); |
1186 | } |
1187 | |
1188 | void SDL_PushGPUDebugGroup( |
1189 | SDL_GPUCommandBuffer *command_buffer, |
1190 | const char *name) |
1191 | { |
1192 | if (command_buffer == NULL) { |
1193 | SDL_InvalidParamError("command_buffer" ); |
1194 | return; |
1195 | } |
1196 | if (name == NULL) { |
1197 | SDL_InvalidParamError("name" ); |
1198 | return; |
1199 | } |
1200 | |
1201 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1202 | CHECK_COMMAND_BUFFER |
1203 | } |
1204 | |
1205 | COMMAND_BUFFER_DEVICE->PushDebugGroup( |
1206 | command_buffer, |
1207 | name); |
1208 | } |
1209 | |
1210 | void SDL_PopGPUDebugGroup( |
1211 | SDL_GPUCommandBuffer *command_buffer) |
1212 | { |
1213 | if (command_buffer == NULL) { |
1214 | SDL_InvalidParamError("command_buffer" ); |
1215 | return; |
1216 | } |
1217 | |
1218 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1219 | CHECK_COMMAND_BUFFER |
1220 | } |
1221 | |
1222 | COMMAND_BUFFER_DEVICE->PopDebugGroup( |
1223 | command_buffer); |
1224 | } |
1225 | |
1226 | // Disposal |
1227 | |
1228 | void SDL_ReleaseGPUTexture( |
1229 | SDL_GPUDevice *device, |
1230 | SDL_GPUTexture *texture) |
1231 | { |
1232 | CHECK_DEVICE_MAGIC(device, ); |
1233 | if (texture == NULL) { |
1234 | return; |
1235 | } |
1236 | |
1237 | device->ReleaseTexture( |
1238 | device->driverData, |
1239 | texture); |
1240 | } |
1241 | |
1242 | void SDL_ReleaseGPUSampler( |
1243 | SDL_GPUDevice *device, |
1244 | SDL_GPUSampler *sampler) |
1245 | { |
1246 | CHECK_DEVICE_MAGIC(device, ); |
1247 | if (sampler == NULL) { |
1248 | return; |
1249 | } |
1250 | |
1251 | device->ReleaseSampler( |
1252 | device->driverData, |
1253 | sampler); |
1254 | } |
1255 | |
1256 | void SDL_ReleaseGPUBuffer( |
1257 | SDL_GPUDevice *device, |
1258 | SDL_GPUBuffer *buffer) |
1259 | { |
1260 | CHECK_DEVICE_MAGIC(device, ); |
1261 | if (buffer == NULL) { |
1262 | return; |
1263 | } |
1264 | |
1265 | device->ReleaseBuffer( |
1266 | device->driverData, |
1267 | buffer); |
1268 | } |
1269 | |
1270 | void SDL_ReleaseGPUTransferBuffer( |
1271 | SDL_GPUDevice *device, |
1272 | SDL_GPUTransferBuffer *transfer_buffer) |
1273 | { |
1274 | CHECK_DEVICE_MAGIC(device, ); |
1275 | if (transfer_buffer == NULL) { |
1276 | return; |
1277 | } |
1278 | |
1279 | device->ReleaseTransferBuffer( |
1280 | device->driverData, |
1281 | transfer_buffer); |
1282 | } |
1283 | |
1284 | void SDL_ReleaseGPUShader( |
1285 | SDL_GPUDevice *device, |
1286 | SDL_GPUShader *shader) |
1287 | { |
1288 | CHECK_DEVICE_MAGIC(device, ); |
1289 | if (shader == NULL) { |
1290 | return; |
1291 | } |
1292 | |
1293 | device->ReleaseShader( |
1294 | device->driverData, |
1295 | shader); |
1296 | } |
1297 | |
1298 | void SDL_ReleaseGPUComputePipeline( |
1299 | SDL_GPUDevice *device, |
1300 | SDL_GPUComputePipeline *compute_pipeline) |
1301 | { |
1302 | CHECK_DEVICE_MAGIC(device, ); |
1303 | if (compute_pipeline == NULL) { |
1304 | return; |
1305 | } |
1306 | |
1307 | device->ReleaseComputePipeline( |
1308 | device->driverData, |
1309 | compute_pipeline); |
1310 | } |
1311 | |
1312 | void SDL_ReleaseGPUGraphicsPipeline( |
1313 | SDL_GPUDevice *device, |
1314 | SDL_GPUGraphicsPipeline *graphics_pipeline) |
1315 | { |
1316 | CHECK_DEVICE_MAGIC(device, ); |
1317 | if (graphics_pipeline == NULL) { |
1318 | return; |
1319 | } |
1320 | |
1321 | device->ReleaseGraphicsPipeline( |
1322 | device->driverData, |
1323 | graphics_pipeline); |
1324 | } |
1325 | |
1326 | // Command Buffer |
1327 | |
1328 | SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer( |
1329 | SDL_GPUDevice *device) |
1330 | { |
1331 | SDL_GPUCommandBuffer *command_buffer; |
1332 | CommandBufferCommonHeader *commandBufferHeader; |
1333 | |
1334 | CHECK_DEVICE_MAGIC(device, NULL); |
1335 | |
1336 | command_buffer = device->AcquireCommandBuffer( |
1337 | device->driverData); |
1338 | |
1339 | if (command_buffer == NULL) { |
1340 | return NULL; |
1341 | } |
1342 | |
1343 | commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
1344 | commandBufferHeader->device = device; |
1345 | commandBufferHeader->render_pass.command_buffer = command_buffer; |
1346 | commandBufferHeader->render_pass.in_progress = false; |
1347 | commandBufferHeader->graphics_pipeline_bound = false; |
1348 | commandBufferHeader->compute_pass.command_buffer = command_buffer; |
1349 | commandBufferHeader->compute_pass.in_progress = false; |
1350 | commandBufferHeader->compute_pipeline_bound = false; |
1351 | commandBufferHeader->copy_pass.command_buffer = command_buffer; |
1352 | commandBufferHeader->copy_pass.in_progress = false; |
1353 | commandBufferHeader->swapchain_texture_acquired = false; |
1354 | commandBufferHeader->submitted = false; |
1355 | |
1356 | return command_buffer; |
1357 | } |
1358 | |
1359 | // Uniforms |
1360 | |
1361 | void SDL_PushGPUVertexUniformData( |
1362 | SDL_GPUCommandBuffer *command_buffer, |
1363 | Uint32 slot_index, |
1364 | const void *data, |
1365 | Uint32 length) |
1366 | { |
1367 | if (command_buffer == NULL) { |
1368 | SDL_InvalidParamError("command_buffer" ); |
1369 | return; |
1370 | } |
1371 | if (data == NULL) { |
1372 | SDL_InvalidParamError("data" ); |
1373 | return; |
1374 | } |
1375 | |
1376 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1377 | CHECK_COMMAND_BUFFER |
1378 | } |
1379 | |
1380 | COMMAND_BUFFER_DEVICE->PushVertexUniformData( |
1381 | command_buffer, |
1382 | slot_index, |
1383 | data, |
1384 | length); |
1385 | } |
1386 | |
1387 | void SDL_PushGPUFragmentUniformData( |
1388 | SDL_GPUCommandBuffer *command_buffer, |
1389 | Uint32 slot_index, |
1390 | const void *data, |
1391 | Uint32 length) |
1392 | { |
1393 | if (command_buffer == NULL) { |
1394 | SDL_InvalidParamError("command_buffer" ); |
1395 | return; |
1396 | } |
1397 | if (data == NULL) { |
1398 | SDL_InvalidParamError("data" ); |
1399 | return; |
1400 | } |
1401 | |
1402 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1403 | CHECK_COMMAND_BUFFER |
1404 | } |
1405 | |
1406 | COMMAND_BUFFER_DEVICE->PushFragmentUniformData( |
1407 | command_buffer, |
1408 | slot_index, |
1409 | data, |
1410 | length); |
1411 | } |
1412 | |
1413 | void SDL_PushGPUComputeUniformData( |
1414 | SDL_GPUCommandBuffer *command_buffer, |
1415 | Uint32 slot_index, |
1416 | const void *data, |
1417 | Uint32 length) |
1418 | { |
1419 | if (command_buffer == NULL) { |
1420 | SDL_InvalidParamError("command_buffer" ); |
1421 | return; |
1422 | } |
1423 | if (data == NULL) { |
1424 | SDL_InvalidParamError("data" ); |
1425 | return; |
1426 | } |
1427 | |
1428 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1429 | CHECK_COMMAND_BUFFER |
1430 | } |
1431 | |
1432 | COMMAND_BUFFER_DEVICE->PushComputeUniformData( |
1433 | command_buffer, |
1434 | slot_index, |
1435 | data, |
1436 | length); |
1437 | } |
1438 | |
1439 | // Render Pass |
1440 | |
1441 | SDL_GPURenderPass *SDL_BeginGPURenderPass( |
1442 | SDL_GPUCommandBuffer *command_buffer, |
1443 | const SDL_GPUColorTargetInfo *color_target_infos, |
1444 | Uint32 num_color_targets, |
1445 | const SDL_GPUDepthStencilTargetInfo *depth_stencil_target_info) |
1446 | { |
1447 | CommandBufferCommonHeader *commandBufferHeader; |
1448 | |
1449 | if (command_buffer == NULL) { |
1450 | SDL_InvalidParamError("command_buffer" ); |
1451 | return NULL; |
1452 | } |
1453 | if (color_target_infos == NULL && num_color_targets > 0) { |
1454 | SDL_InvalidParamError("color_target_infos" ); |
1455 | return NULL; |
1456 | } |
1457 | |
1458 | if (num_color_targets > MAX_COLOR_TARGET_BINDINGS) { |
1459 | SDL_SetError("num_color_targets exceeds MAX_COLOR_TARGET_BINDINGS" ); |
1460 | return NULL; |
1461 | } |
1462 | |
1463 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1464 | CHECK_COMMAND_BUFFER_RETURN_NULL |
1465 | CHECK_ANY_PASS_IN_PROGRESS("Cannot begin render pass during another pass!" , NULL) |
1466 | |
1467 | for (Uint32 i = 0; i < num_color_targets; i += 1) { |
1468 | TextureCommonHeader * = (TextureCommonHeader *)color_target_infos[i].texture; |
1469 | |
1470 | if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) { |
1471 | SDL_assert_release(!"Cannot cycle color target when load op is LOAD!" ); |
1472 | } |
1473 | |
1474 | if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { |
1475 | if (color_target_infos[i].resolve_texture == NULL) { |
1476 | SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!" ); |
1477 | } else { |
1478 | TextureCommonHeader * = (TextureCommonHeader *)color_target_infos[i].resolve_texture; |
1479 | if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) { |
1480 | SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!" ); |
1481 | } |
1482 | if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) { |
1483 | SDL_assert_release(!"Resolve texture must have a sample count of 1!" ); |
1484 | } |
1485 | if (resolveTextureHeader->info.format != textureHeader->info.format) { |
1486 | SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!" ); |
1487 | } |
1488 | if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) { |
1489 | SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!" ); |
1490 | } |
1491 | if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) { |
1492 | SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!" ); |
1493 | } |
1494 | } |
1495 | } |
1496 | } |
1497 | |
1498 | if (depth_stencil_target_info != NULL) { |
1499 | |
1500 | TextureCommonHeader * = (TextureCommonHeader *)depth_stencil_target_info->texture; |
1501 | if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) { |
1502 | SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!" ); |
1503 | } |
1504 | |
1505 | if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) { |
1506 | SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!" ); |
1507 | } |
1508 | |
1509 | if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE || |
1510 | depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE || |
1511 | depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE || |
1512 | depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { |
1513 | SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!" ); |
1514 | } |
1515 | } |
1516 | } |
1517 | |
1518 | COMMAND_BUFFER_DEVICE->BeginRenderPass( |
1519 | command_buffer, |
1520 | color_target_infos, |
1521 | num_color_targets, |
1522 | depth_stencil_target_info); |
1523 | |
1524 | commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
1525 | commandBufferHeader->render_pass.in_progress = true; |
1526 | return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass); |
1527 | } |
1528 | |
1529 | void SDL_BindGPUGraphicsPipeline( |
1530 | SDL_GPURenderPass *render_pass, |
1531 | SDL_GPUGraphicsPipeline *graphics_pipeline) |
1532 | { |
1533 | CommandBufferCommonHeader *commandBufferHeader; |
1534 | |
1535 | if (render_pass == NULL) { |
1536 | SDL_InvalidParamError("render_pass" ); |
1537 | return; |
1538 | } |
1539 | if (graphics_pipeline == NULL) { |
1540 | SDL_InvalidParamError("graphics_pipeline" ); |
1541 | return; |
1542 | } |
1543 | |
1544 | RENDERPASS_DEVICE->BindGraphicsPipeline( |
1545 | RENDERPASS_COMMAND_BUFFER, |
1546 | graphics_pipeline); |
1547 | |
1548 | commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER; |
1549 | commandBufferHeader->graphics_pipeline_bound = true; |
1550 | } |
1551 | |
1552 | void SDL_SetGPUViewport( |
1553 | SDL_GPURenderPass *render_pass, |
1554 | const SDL_GPUViewport *viewport) |
1555 | { |
1556 | if (render_pass == NULL) { |
1557 | SDL_InvalidParamError("render_pass" ); |
1558 | return; |
1559 | } |
1560 | if (viewport == NULL) { |
1561 | SDL_InvalidParamError("viewport" ); |
1562 | return; |
1563 | } |
1564 | |
1565 | if (RENDERPASS_DEVICE->debug_mode) { |
1566 | CHECK_RENDERPASS |
1567 | } |
1568 | |
1569 | RENDERPASS_DEVICE->SetViewport( |
1570 | RENDERPASS_COMMAND_BUFFER, |
1571 | viewport); |
1572 | } |
1573 | |
1574 | void SDL_SetGPUScissor( |
1575 | SDL_GPURenderPass *render_pass, |
1576 | const SDL_Rect *scissor) |
1577 | { |
1578 | if (render_pass == NULL) { |
1579 | SDL_InvalidParamError("render_pass" ); |
1580 | return; |
1581 | } |
1582 | if (scissor == NULL) { |
1583 | SDL_InvalidParamError("scissor" ); |
1584 | return; |
1585 | } |
1586 | |
1587 | if (RENDERPASS_DEVICE->debug_mode) { |
1588 | CHECK_RENDERPASS |
1589 | } |
1590 | |
1591 | RENDERPASS_DEVICE->SetScissor( |
1592 | RENDERPASS_COMMAND_BUFFER, |
1593 | scissor); |
1594 | } |
1595 | |
1596 | void SDL_SetGPUBlendConstants( |
1597 | SDL_GPURenderPass *render_pass, |
1598 | SDL_FColor blend_constants) |
1599 | { |
1600 | if (render_pass == NULL) { |
1601 | SDL_InvalidParamError("render_pass" ); |
1602 | return; |
1603 | } |
1604 | |
1605 | if (RENDERPASS_DEVICE->debug_mode) { |
1606 | CHECK_RENDERPASS |
1607 | } |
1608 | |
1609 | RENDERPASS_DEVICE->SetBlendConstants( |
1610 | RENDERPASS_COMMAND_BUFFER, |
1611 | blend_constants); |
1612 | } |
1613 | |
1614 | void SDL_SetGPUStencilReference( |
1615 | SDL_GPURenderPass *render_pass, |
1616 | Uint8 reference) |
1617 | { |
1618 | if (render_pass == NULL) { |
1619 | SDL_InvalidParamError("render_pass" ); |
1620 | return; |
1621 | } |
1622 | |
1623 | if (RENDERPASS_DEVICE->debug_mode) { |
1624 | CHECK_RENDERPASS |
1625 | } |
1626 | |
1627 | RENDERPASS_DEVICE->SetStencilReference( |
1628 | RENDERPASS_COMMAND_BUFFER, |
1629 | reference); |
1630 | } |
1631 | |
1632 | void SDL_BindGPUVertexBuffers( |
1633 | SDL_GPURenderPass *render_pass, |
1634 | Uint32 first_binding, |
1635 | const SDL_GPUBufferBinding *bindings, |
1636 | Uint32 num_bindings) |
1637 | { |
1638 | if (render_pass == NULL) { |
1639 | SDL_InvalidParamError("render_pass" ); |
1640 | return; |
1641 | } |
1642 | if (bindings == NULL && num_bindings > 0) { |
1643 | SDL_InvalidParamError("bindings" ); |
1644 | return; |
1645 | } |
1646 | |
1647 | if (RENDERPASS_DEVICE->debug_mode) { |
1648 | CHECK_RENDERPASS |
1649 | } |
1650 | |
1651 | RENDERPASS_DEVICE->BindVertexBuffers( |
1652 | RENDERPASS_COMMAND_BUFFER, |
1653 | first_binding, |
1654 | bindings, |
1655 | num_bindings); |
1656 | } |
1657 | |
1658 | void SDL_BindGPUIndexBuffer( |
1659 | SDL_GPURenderPass *render_pass, |
1660 | const SDL_GPUBufferBinding *binding, |
1661 | SDL_GPUIndexElementSize index_element_size) |
1662 | { |
1663 | if (render_pass == NULL) { |
1664 | SDL_InvalidParamError("render_pass" ); |
1665 | return; |
1666 | } |
1667 | if (binding == NULL) { |
1668 | SDL_InvalidParamError("binding" ); |
1669 | return; |
1670 | } |
1671 | |
1672 | if (RENDERPASS_DEVICE->debug_mode) { |
1673 | CHECK_RENDERPASS |
1674 | } |
1675 | |
1676 | RENDERPASS_DEVICE->BindIndexBuffer( |
1677 | RENDERPASS_COMMAND_BUFFER, |
1678 | binding, |
1679 | index_element_size); |
1680 | } |
1681 | |
1682 | void SDL_BindGPUVertexSamplers( |
1683 | SDL_GPURenderPass *render_pass, |
1684 | Uint32 first_slot, |
1685 | const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, |
1686 | Uint32 num_bindings) |
1687 | { |
1688 | if (render_pass == NULL) { |
1689 | SDL_InvalidParamError("render_pass" ); |
1690 | return; |
1691 | } |
1692 | if (texture_sampler_bindings == NULL && num_bindings > 0) { |
1693 | SDL_InvalidParamError("texture_sampler_bindings" ); |
1694 | return; |
1695 | } |
1696 | |
1697 | if (RENDERPASS_DEVICE->debug_mode) { |
1698 | CHECK_RENDERPASS |
1699 | } |
1700 | |
1701 | RENDERPASS_DEVICE->BindVertexSamplers( |
1702 | RENDERPASS_COMMAND_BUFFER, |
1703 | first_slot, |
1704 | texture_sampler_bindings, |
1705 | num_bindings); |
1706 | } |
1707 | |
1708 | void SDL_BindGPUVertexStorageTextures( |
1709 | SDL_GPURenderPass *render_pass, |
1710 | Uint32 first_slot, |
1711 | SDL_GPUTexture *const *storage_textures, |
1712 | Uint32 num_bindings) |
1713 | { |
1714 | if (render_pass == NULL) { |
1715 | SDL_InvalidParamError("render_pass" ); |
1716 | return; |
1717 | } |
1718 | if (storage_textures == NULL && num_bindings > 0) { |
1719 | SDL_InvalidParamError("storage_textures" ); |
1720 | return; |
1721 | } |
1722 | |
1723 | if (RENDERPASS_DEVICE->debug_mode) { |
1724 | CHECK_RENDERPASS |
1725 | } |
1726 | |
1727 | RENDERPASS_DEVICE->BindVertexStorageTextures( |
1728 | RENDERPASS_COMMAND_BUFFER, |
1729 | first_slot, |
1730 | storage_textures, |
1731 | num_bindings); |
1732 | } |
1733 | |
1734 | void SDL_BindGPUVertexStorageBuffers( |
1735 | SDL_GPURenderPass *render_pass, |
1736 | Uint32 first_slot, |
1737 | SDL_GPUBuffer *const *storage_buffers, |
1738 | Uint32 num_bindings) |
1739 | { |
1740 | if (render_pass == NULL) { |
1741 | SDL_InvalidParamError("render_pass" ); |
1742 | return; |
1743 | } |
1744 | if (storage_buffers == NULL && num_bindings > 0) { |
1745 | SDL_InvalidParamError("storage_buffers" ); |
1746 | return; |
1747 | } |
1748 | |
1749 | if (RENDERPASS_DEVICE->debug_mode) { |
1750 | CHECK_RENDERPASS |
1751 | } |
1752 | |
1753 | RENDERPASS_DEVICE->BindVertexStorageBuffers( |
1754 | RENDERPASS_COMMAND_BUFFER, |
1755 | first_slot, |
1756 | storage_buffers, |
1757 | num_bindings); |
1758 | } |
1759 | |
1760 | void SDL_BindGPUFragmentSamplers( |
1761 | SDL_GPURenderPass *render_pass, |
1762 | Uint32 first_slot, |
1763 | const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, |
1764 | Uint32 num_bindings) |
1765 | { |
1766 | if (render_pass == NULL) { |
1767 | SDL_InvalidParamError("render_pass" ); |
1768 | return; |
1769 | } |
1770 | if (texture_sampler_bindings == NULL && num_bindings > 0) { |
1771 | SDL_InvalidParamError("texture_sampler_bindings" ); |
1772 | return; |
1773 | } |
1774 | |
1775 | if (RENDERPASS_DEVICE->debug_mode) { |
1776 | CHECK_RENDERPASS |
1777 | } |
1778 | |
1779 | RENDERPASS_DEVICE->BindFragmentSamplers( |
1780 | RENDERPASS_COMMAND_BUFFER, |
1781 | first_slot, |
1782 | texture_sampler_bindings, |
1783 | num_bindings); |
1784 | } |
1785 | |
1786 | void SDL_BindGPUFragmentStorageTextures( |
1787 | SDL_GPURenderPass *render_pass, |
1788 | Uint32 first_slot, |
1789 | SDL_GPUTexture *const *storage_textures, |
1790 | Uint32 num_bindings) |
1791 | { |
1792 | if (render_pass == NULL) { |
1793 | SDL_InvalidParamError("render_pass" ); |
1794 | return; |
1795 | } |
1796 | if (storage_textures == NULL && num_bindings > 0) { |
1797 | SDL_InvalidParamError("storage_textures" ); |
1798 | return; |
1799 | } |
1800 | |
1801 | if (RENDERPASS_DEVICE->debug_mode) { |
1802 | CHECK_RENDERPASS |
1803 | } |
1804 | |
1805 | RENDERPASS_DEVICE->BindFragmentStorageTextures( |
1806 | RENDERPASS_COMMAND_BUFFER, |
1807 | first_slot, |
1808 | storage_textures, |
1809 | num_bindings); |
1810 | } |
1811 | |
1812 | void SDL_BindGPUFragmentStorageBuffers( |
1813 | SDL_GPURenderPass *render_pass, |
1814 | Uint32 first_slot, |
1815 | SDL_GPUBuffer *const *storage_buffers, |
1816 | Uint32 num_bindings) |
1817 | { |
1818 | if (render_pass == NULL) { |
1819 | SDL_InvalidParamError("render_pass" ); |
1820 | return; |
1821 | } |
1822 | if (storage_buffers == NULL && num_bindings > 0) { |
1823 | SDL_InvalidParamError("storage_buffers" ); |
1824 | return; |
1825 | } |
1826 | |
1827 | if (RENDERPASS_DEVICE->debug_mode) { |
1828 | CHECK_RENDERPASS |
1829 | } |
1830 | |
1831 | RENDERPASS_DEVICE->BindFragmentStorageBuffers( |
1832 | RENDERPASS_COMMAND_BUFFER, |
1833 | first_slot, |
1834 | storage_buffers, |
1835 | num_bindings); |
1836 | } |
1837 | |
1838 | void SDL_DrawGPUIndexedPrimitives( |
1839 | SDL_GPURenderPass *render_pass, |
1840 | Uint32 num_indices, |
1841 | Uint32 num_instances, |
1842 | Uint32 first_index, |
1843 | Sint32 vertex_offset, |
1844 | Uint32 first_instance) |
1845 | { |
1846 | if (render_pass == NULL) { |
1847 | SDL_InvalidParamError("render_pass" ); |
1848 | return; |
1849 | } |
1850 | |
1851 | if (RENDERPASS_DEVICE->debug_mode) { |
1852 | CHECK_RENDERPASS |
1853 | CHECK_GRAPHICS_PIPELINE_BOUND |
1854 | } |
1855 | |
1856 | RENDERPASS_DEVICE->DrawIndexedPrimitives( |
1857 | RENDERPASS_COMMAND_BUFFER, |
1858 | num_indices, |
1859 | num_instances, |
1860 | first_index, |
1861 | vertex_offset, |
1862 | first_instance); |
1863 | } |
1864 | |
1865 | void SDL_DrawGPUPrimitives( |
1866 | SDL_GPURenderPass *render_pass, |
1867 | Uint32 num_vertices, |
1868 | Uint32 num_instances, |
1869 | Uint32 first_vertex, |
1870 | Uint32 first_instance) |
1871 | { |
1872 | if (render_pass == NULL) { |
1873 | SDL_InvalidParamError("render_pass" ); |
1874 | return; |
1875 | } |
1876 | |
1877 | if (RENDERPASS_DEVICE->debug_mode) { |
1878 | CHECK_RENDERPASS |
1879 | CHECK_GRAPHICS_PIPELINE_BOUND |
1880 | } |
1881 | |
1882 | RENDERPASS_DEVICE->DrawPrimitives( |
1883 | RENDERPASS_COMMAND_BUFFER, |
1884 | num_vertices, |
1885 | num_instances, |
1886 | first_vertex, |
1887 | first_instance); |
1888 | } |
1889 | |
1890 | void SDL_DrawGPUPrimitivesIndirect( |
1891 | SDL_GPURenderPass *render_pass, |
1892 | SDL_GPUBuffer *buffer, |
1893 | Uint32 offset, |
1894 | Uint32 draw_count) |
1895 | { |
1896 | if (render_pass == NULL) { |
1897 | SDL_InvalidParamError("render_pass" ); |
1898 | return; |
1899 | } |
1900 | if (buffer == NULL) { |
1901 | SDL_InvalidParamError("buffer" ); |
1902 | return; |
1903 | } |
1904 | |
1905 | if (RENDERPASS_DEVICE->debug_mode) { |
1906 | CHECK_RENDERPASS |
1907 | CHECK_GRAPHICS_PIPELINE_BOUND |
1908 | } |
1909 | |
1910 | RENDERPASS_DEVICE->DrawPrimitivesIndirect( |
1911 | RENDERPASS_COMMAND_BUFFER, |
1912 | buffer, |
1913 | offset, |
1914 | draw_count); |
1915 | } |
1916 | |
1917 | void SDL_DrawGPUIndexedPrimitivesIndirect( |
1918 | SDL_GPURenderPass *render_pass, |
1919 | SDL_GPUBuffer *buffer, |
1920 | Uint32 offset, |
1921 | Uint32 draw_count) |
1922 | { |
1923 | if (render_pass == NULL) { |
1924 | SDL_InvalidParamError("render_pass" ); |
1925 | return; |
1926 | } |
1927 | if (buffer == NULL) { |
1928 | SDL_InvalidParamError("buffer" ); |
1929 | return; |
1930 | } |
1931 | |
1932 | if (RENDERPASS_DEVICE->debug_mode) { |
1933 | CHECK_RENDERPASS |
1934 | CHECK_GRAPHICS_PIPELINE_BOUND |
1935 | } |
1936 | |
1937 | RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect( |
1938 | RENDERPASS_COMMAND_BUFFER, |
1939 | buffer, |
1940 | offset, |
1941 | draw_count); |
1942 | } |
1943 | |
1944 | void SDL_EndGPURenderPass( |
1945 | SDL_GPURenderPass *render_pass) |
1946 | { |
1947 | CommandBufferCommonHeader *commandBufferCommonHeader; |
1948 | |
1949 | if (render_pass == NULL) { |
1950 | SDL_InvalidParamError("render_pass" ); |
1951 | return; |
1952 | } |
1953 | |
1954 | if (RENDERPASS_DEVICE->debug_mode) { |
1955 | CHECK_RENDERPASS |
1956 | } |
1957 | |
1958 | RENDERPASS_DEVICE->EndRenderPass( |
1959 | RENDERPASS_COMMAND_BUFFER); |
1960 | |
1961 | commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER; |
1962 | commandBufferCommonHeader->render_pass.in_progress = false; |
1963 | commandBufferCommonHeader->graphics_pipeline_bound = false; |
1964 | } |
1965 | |
1966 | // Compute Pass |
1967 | |
1968 | SDL_GPUComputePass *SDL_BeginGPUComputePass( |
1969 | SDL_GPUCommandBuffer *command_buffer, |
1970 | const SDL_GPUStorageTextureReadWriteBinding *storage_texture_bindings, |
1971 | Uint32 num_storage_texture_bindings, |
1972 | const SDL_GPUStorageBufferReadWriteBinding *storage_buffer_bindings, |
1973 | Uint32 num_storage_buffer_bindings) |
1974 | { |
1975 | CommandBufferCommonHeader *commandBufferHeader; |
1976 | |
1977 | if (command_buffer == NULL) { |
1978 | SDL_InvalidParamError("command_buffer" ); |
1979 | return NULL; |
1980 | } |
1981 | if (storage_texture_bindings == NULL && num_storage_texture_bindings > 0) { |
1982 | SDL_InvalidParamError("storage_texture_bindings" ); |
1983 | return NULL; |
1984 | } |
1985 | if (storage_buffer_bindings == NULL && num_storage_buffer_bindings > 0) { |
1986 | SDL_InvalidParamError("storage_buffer_bindings" ); |
1987 | return NULL; |
1988 | } |
1989 | if (num_storage_texture_bindings > MAX_COMPUTE_WRITE_TEXTURES) { |
1990 | SDL_InvalidParamError("num_storage_texture_bindings" ); |
1991 | return NULL; |
1992 | } |
1993 | if (num_storage_buffer_bindings > MAX_COMPUTE_WRITE_BUFFERS) { |
1994 | SDL_InvalidParamError("num_storage_buffer_bindings" ); |
1995 | return NULL; |
1996 | } |
1997 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
1998 | CHECK_COMMAND_BUFFER_RETURN_NULL |
1999 | CHECK_ANY_PASS_IN_PROGRESS("Cannot begin compute pass during another pass!" , NULL) |
2000 | |
2001 | for (Uint32 i = 0; i < num_storage_texture_bindings; i += 1) { |
2002 | TextureCommonHeader * = (TextureCommonHeader *)storage_texture_bindings[i].texture; |
2003 | if (!(header->info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) && !(header->info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { |
2004 | SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag" ); |
2005 | return NULL; |
2006 | } |
2007 | } |
2008 | |
2009 | // TODO: validate buffer usage? |
2010 | } |
2011 | |
2012 | COMMAND_BUFFER_DEVICE->BeginComputePass( |
2013 | command_buffer, |
2014 | storage_texture_bindings, |
2015 | num_storage_texture_bindings, |
2016 | storage_buffer_bindings, |
2017 | num_storage_buffer_bindings); |
2018 | |
2019 | commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2020 | commandBufferHeader->compute_pass.in_progress = true; |
2021 | return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass); |
2022 | } |
2023 | |
2024 | void SDL_BindGPUComputePipeline( |
2025 | SDL_GPUComputePass *compute_pass, |
2026 | SDL_GPUComputePipeline *compute_pipeline) |
2027 | { |
2028 | CommandBufferCommonHeader *commandBufferHeader; |
2029 | |
2030 | if (compute_pass == NULL) { |
2031 | SDL_InvalidParamError("compute_pass" ); |
2032 | return; |
2033 | } |
2034 | if (compute_pipeline == NULL) { |
2035 | SDL_InvalidParamError("compute_pipeline" ); |
2036 | return; |
2037 | } |
2038 | |
2039 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2040 | CHECK_COMPUTEPASS |
2041 | } |
2042 | |
2043 | COMPUTEPASS_DEVICE->BindComputePipeline( |
2044 | COMPUTEPASS_COMMAND_BUFFER, |
2045 | compute_pipeline); |
2046 | |
2047 | commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER; |
2048 | commandBufferHeader->compute_pipeline_bound = true; |
2049 | } |
2050 | |
2051 | void SDL_BindGPUComputeSamplers( |
2052 | SDL_GPUComputePass *compute_pass, |
2053 | Uint32 first_slot, |
2054 | const SDL_GPUTextureSamplerBinding *texture_sampler_bindings, |
2055 | Uint32 num_bindings) |
2056 | { |
2057 | if (compute_pass == NULL) { |
2058 | SDL_InvalidParamError("compute_pass" ); |
2059 | return; |
2060 | } |
2061 | if (texture_sampler_bindings == NULL && num_bindings > 0) { |
2062 | SDL_InvalidParamError("texture_sampler_bindings" ); |
2063 | return; |
2064 | } |
2065 | |
2066 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2067 | CHECK_COMPUTEPASS |
2068 | } |
2069 | |
2070 | COMPUTEPASS_DEVICE->BindComputeSamplers( |
2071 | COMPUTEPASS_COMMAND_BUFFER, |
2072 | first_slot, |
2073 | texture_sampler_bindings, |
2074 | num_bindings); |
2075 | } |
2076 | |
2077 | void SDL_BindGPUComputeStorageTextures( |
2078 | SDL_GPUComputePass *compute_pass, |
2079 | Uint32 first_slot, |
2080 | SDL_GPUTexture *const *storage_textures, |
2081 | Uint32 num_bindings) |
2082 | { |
2083 | if (compute_pass == NULL) { |
2084 | SDL_InvalidParamError("compute_pass" ); |
2085 | return; |
2086 | } |
2087 | if (storage_textures == NULL && num_bindings > 0) { |
2088 | SDL_InvalidParamError("storage_textures" ); |
2089 | return; |
2090 | } |
2091 | |
2092 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2093 | CHECK_COMPUTEPASS |
2094 | } |
2095 | |
2096 | COMPUTEPASS_DEVICE->BindComputeStorageTextures( |
2097 | COMPUTEPASS_COMMAND_BUFFER, |
2098 | first_slot, |
2099 | storage_textures, |
2100 | num_bindings); |
2101 | } |
2102 | |
2103 | void SDL_BindGPUComputeStorageBuffers( |
2104 | SDL_GPUComputePass *compute_pass, |
2105 | Uint32 first_slot, |
2106 | SDL_GPUBuffer *const *storage_buffers, |
2107 | Uint32 num_bindings) |
2108 | { |
2109 | if (compute_pass == NULL) { |
2110 | SDL_InvalidParamError("compute_pass" ); |
2111 | return; |
2112 | } |
2113 | if (storage_buffers == NULL && num_bindings > 0) { |
2114 | SDL_InvalidParamError("storage_buffers" ); |
2115 | return; |
2116 | } |
2117 | |
2118 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2119 | CHECK_COMPUTEPASS |
2120 | } |
2121 | |
2122 | COMPUTEPASS_DEVICE->BindComputeStorageBuffers( |
2123 | COMPUTEPASS_COMMAND_BUFFER, |
2124 | first_slot, |
2125 | storage_buffers, |
2126 | num_bindings); |
2127 | } |
2128 | |
2129 | void SDL_DispatchGPUCompute( |
2130 | SDL_GPUComputePass *compute_pass, |
2131 | Uint32 groupcount_x, |
2132 | Uint32 groupcount_y, |
2133 | Uint32 groupcount_z) |
2134 | { |
2135 | if (compute_pass == NULL) { |
2136 | SDL_InvalidParamError("compute_pass" ); |
2137 | return; |
2138 | } |
2139 | |
2140 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2141 | CHECK_COMPUTEPASS |
2142 | CHECK_COMPUTE_PIPELINE_BOUND |
2143 | } |
2144 | |
2145 | COMPUTEPASS_DEVICE->DispatchCompute( |
2146 | COMPUTEPASS_COMMAND_BUFFER, |
2147 | groupcount_x, |
2148 | groupcount_y, |
2149 | groupcount_z); |
2150 | } |
2151 | |
2152 | void SDL_DispatchGPUComputeIndirect( |
2153 | SDL_GPUComputePass *compute_pass, |
2154 | SDL_GPUBuffer *buffer, |
2155 | Uint32 offset) |
2156 | { |
2157 | if (compute_pass == NULL) { |
2158 | SDL_InvalidParamError("compute_pass" ); |
2159 | return; |
2160 | } |
2161 | |
2162 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2163 | CHECK_COMPUTEPASS |
2164 | CHECK_COMPUTE_PIPELINE_BOUND |
2165 | } |
2166 | |
2167 | COMPUTEPASS_DEVICE->DispatchComputeIndirect( |
2168 | COMPUTEPASS_COMMAND_BUFFER, |
2169 | buffer, |
2170 | offset); |
2171 | } |
2172 | |
2173 | void SDL_EndGPUComputePass( |
2174 | SDL_GPUComputePass *compute_pass) |
2175 | { |
2176 | CommandBufferCommonHeader *commandBufferCommonHeader; |
2177 | |
2178 | if (compute_pass == NULL) { |
2179 | SDL_InvalidParamError("compute_pass" ); |
2180 | return; |
2181 | } |
2182 | |
2183 | if (COMPUTEPASS_DEVICE->debug_mode) { |
2184 | CHECK_COMPUTEPASS |
2185 | } |
2186 | |
2187 | COMPUTEPASS_DEVICE->EndComputePass( |
2188 | COMPUTEPASS_COMMAND_BUFFER); |
2189 | |
2190 | commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER; |
2191 | commandBufferCommonHeader->compute_pass.in_progress = false; |
2192 | commandBufferCommonHeader->compute_pipeline_bound = false; |
2193 | } |
2194 | |
2195 | // TransferBuffer Data |
2196 | |
2197 | void *SDL_MapGPUTransferBuffer( |
2198 | SDL_GPUDevice *device, |
2199 | SDL_GPUTransferBuffer *transfer_buffer, |
2200 | bool cycle) |
2201 | { |
2202 | CHECK_DEVICE_MAGIC(device, NULL); |
2203 | if (transfer_buffer == NULL) { |
2204 | SDL_InvalidParamError("transfer_buffer" ); |
2205 | return NULL; |
2206 | } |
2207 | |
2208 | return device->MapTransferBuffer( |
2209 | device->driverData, |
2210 | transfer_buffer, |
2211 | cycle); |
2212 | } |
2213 | |
2214 | void SDL_UnmapGPUTransferBuffer( |
2215 | SDL_GPUDevice *device, |
2216 | SDL_GPUTransferBuffer *transfer_buffer) |
2217 | { |
2218 | CHECK_DEVICE_MAGIC(device, ); |
2219 | if (transfer_buffer == NULL) { |
2220 | SDL_InvalidParamError("transfer_buffer" ); |
2221 | return; |
2222 | } |
2223 | |
2224 | device->UnmapTransferBuffer( |
2225 | device->driverData, |
2226 | transfer_buffer); |
2227 | } |
2228 | |
2229 | // Copy Pass |
2230 | |
2231 | SDL_GPUCopyPass *SDL_BeginGPUCopyPass( |
2232 | SDL_GPUCommandBuffer *command_buffer) |
2233 | { |
2234 | CommandBufferCommonHeader *commandBufferHeader; |
2235 | |
2236 | if (command_buffer == NULL) { |
2237 | SDL_InvalidParamError("command_buffer" ); |
2238 | return NULL; |
2239 | } |
2240 | |
2241 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2242 | CHECK_COMMAND_BUFFER_RETURN_NULL |
2243 | CHECK_ANY_PASS_IN_PROGRESS("Cannot begin copy pass during another pass!" , NULL) |
2244 | } |
2245 | |
2246 | COMMAND_BUFFER_DEVICE->BeginCopyPass( |
2247 | command_buffer); |
2248 | |
2249 | commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2250 | commandBufferHeader->copy_pass.in_progress = true; |
2251 | return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass); |
2252 | } |
2253 | |
2254 | void SDL_UploadToGPUTexture( |
2255 | SDL_GPUCopyPass *copy_pass, |
2256 | const SDL_GPUTextureTransferInfo *source, |
2257 | const SDL_GPUTextureRegion *destination, |
2258 | bool cycle) |
2259 | { |
2260 | if (copy_pass == NULL) { |
2261 | SDL_InvalidParamError("copy_pass" ); |
2262 | return; |
2263 | } |
2264 | if (source == NULL) { |
2265 | SDL_InvalidParamError("source" ); |
2266 | return; |
2267 | } |
2268 | if (destination == NULL) { |
2269 | SDL_InvalidParamError("destination" ); |
2270 | return; |
2271 | } |
2272 | |
2273 | if (COPYPASS_DEVICE->debug_mode) { |
2274 | CHECK_COPYPASS |
2275 | if (source->transfer_buffer == NULL) { |
2276 | SDL_assert_release(!"Source transfer buffer cannot be NULL!" ); |
2277 | return; |
2278 | } |
2279 | if (destination->texture == NULL) { |
2280 | SDL_assert_release(!"Destination texture cannot be NULL!" ); |
2281 | return; |
2282 | } |
2283 | } |
2284 | |
2285 | COPYPASS_DEVICE->UploadToTexture( |
2286 | COPYPASS_COMMAND_BUFFER, |
2287 | source, |
2288 | destination, |
2289 | cycle); |
2290 | } |
2291 | |
2292 | void SDL_UploadToGPUBuffer( |
2293 | SDL_GPUCopyPass *copy_pass, |
2294 | const SDL_GPUTransferBufferLocation *source, |
2295 | const SDL_GPUBufferRegion *destination, |
2296 | bool cycle) |
2297 | { |
2298 | if (copy_pass == NULL) { |
2299 | SDL_InvalidParamError("copy_pass" ); |
2300 | return; |
2301 | } |
2302 | if (source == NULL) { |
2303 | SDL_InvalidParamError("source" ); |
2304 | return; |
2305 | } |
2306 | if (destination == NULL) { |
2307 | SDL_InvalidParamError("destination" ); |
2308 | return; |
2309 | } |
2310 | |
2311 | if (COPYPASS_DEVICE->debug_mode) { |
2312 | CHECK_COPYPASS |
2313 | if (source->transfer_buffer == NULL) { |
2314 | SDL_assert_release(!"Source transfer buffer cannot be NULL!" ); |
2315 | return; |
2316 | } |
2317 | if (destination->buffer == NULL) { |
2318 | SDL_assert_release(!"Destination buffer cannot be NULL!" ); |
2319 | return; |
2320 | } |
2321 | } |
2322 | |
2323 | COPYPASS_DEVICE->UploadToBuffer( |
2324 | COPYPASS_COMMAND_BUFFER, |
2325 | source, |
2326 | destination, |
2327 | cycle); |
2328 | } |
2329 | |
2330 | void SDL_CopyGPUTextureToTexture( |
2331 | SDL_GPUCopyPass *copy_pass, |
2332 | const SDL_GPUTextureLocation *source, |
2333 | const SDL_GPUTextureLocation *destination, |
2334 | Uint32 w, |
2335 | Uint32 h, |
2336 | Uint32 d, |
2337 | bool cycle) |
2338 | { |
2339 | if (copy_pass == NULL) { |
2340 | SDL_InvalidParamError("copy_pass" ); |
2341 | return; |
2342 | } |
2343 | if (source == NULL) { |
2344 | SDL_InvalidParamError("source" ); |
2345 | return; |
2346 | } |
2347 | if (destination == NULL) { |
2348 | SDL_InvalidParamError("destination" ); |
2349 | return; |
2350 | } |
2351 | |
2352 | if (COPYPASS_DEVICE->debug_mode) { |
2353 | CHECK_COPYPASS |
2354 | if (source->texture == NULL) { |
2355 | SDL_assert_release(!"Source texture cannot be NULL!" ); |
2356 | return; |
2357 | } |
2358 | if (destination->texture == NULL) { |
2359 | SDL_assert_release(!"Destination texture cannot be NULL!" ); |
2360 | return; |
2361 | } |
2362 | |
2363 | TextureCommonHeader * = (TextureCommonHeader *)source->texture; |
2364 | TextureCommonHeader * = (TextureCommonHeader *)destination->texture; |
2365 | if (srcHeader->info.format != dstHeader->info.format) { |
2366 | SDL_assert_release(!"Source and destination textures must have the same format!" ); |
2367 | return; |
2368 | } |
2369 | } |
2370 | |
2371 | COPYPASS_DEVICE->CopyTextureToTexture( |
2372 | COPYPASS_COMMAND_BUFFER, |
2373 | source, |
2374 | destination, |
2375 | w, |
2376 | h, |
2377 | d, |
2378 | cycle); |
2379 | } |
2380 | |
2381 | void SDL_CopyGPUBufferToBuffer( |
2382 | SDL_GPUCopyPass *copy_pass, |
2383 | const SDL_GPUBufferLocation *source, |
2384 | const SDL_GPUBufferLocation *destination, |
2385 | Uint32 size, |
2386 | bool cycle) |
2387 | { |
2388 | if (copy_pass == NULL) { |
2389 | SDL_InvalidParamError("copy_pass" ); |
2390 | return; |
2391 | } |
2392 | if (source == NULL) { |
2393 | SDL_InvalidParamError("source" ); |
2394 | return; |
2395 | } |
2396 | if (destination == NULL) { |
2397 | SDL_InvalidParamError("destination" ); |
2398 | return; |
2399 | } |
2400 | |
2401 | if (COPYPASS_DEVICE->debug_mode) { |
2402 | CHECK_COPYPASS |
2403 | if (source->buffer == NULL) { |
2404 | SDL_assert_release(!"Source buffer cannot be NULL!" ); |
2405 | return; |
2406 | } |
2407 | if (destination->buffer == NULL) { |
2408 | SDL_assert_release(!"Destination buffer cannot be NULL!" ); |
2409 | return; |
2410 | } |
2411 | } |
2412 | |
2413 | COPYPASS_DEVICE->CopyBufferToBuffer( |
2414 | COPYPASS_COMMAND_BUFFER, |
2415 | source, |
2416 | destination, |
2417 | size, |
2418 | cycle); |
2419 | } |
2420 | |
2421 | void SDL_DownloadFromGPUTexture( |
2422 | SDL_GPUCopyPass *copy_pass, |
2423 | const SDL_GPUTextureRegion *source, |
2424 | const SDL_GPUTextureTransferInfo *destination) |
2425 | { |
2426 | if (copy_pass == NULL) { |
2427 | SDL_InvalidParamError("copy_pass" ); |
2428 | return; |
2429 | } |
2430 | if (source == NULL) { |
2431 | SDL_InvalidParamError("source" ); |
2432 | return; |
2433 | } |
2434 | if (destination == NULL) { |
2435 | SDL_InvalidParamError("destination" ); |
2436 | return; |
2437 | } |
2438 | |
2439 | if (COPYPASS_DEVICE->debug_mode) { |
2440 | CHECK_COPYPASS |
2441 | if (source->texture == NULL) { |
2442 | SDL_assert_release(!"Source texture cannot be NULL!" ); |
2443 | return; |
2444 | } |
2445 | if (destination->transfer_buffer == NULL) { |
2446 | SDL_assert_release(!"Destination transfer buffer cannot be NULL!" ); |
2447 | return; |
2448 | } |
2449 | } |
2450 | |
2451 | COPYPASS_DEVICE->DownloadFromTexture( |
2452 | COPYPASS_COMMAND_BUFFER, |
2453 | source, |
2454 | destination); |
2455 | } |
2456 | |
2457 | void SDL_DownloadFromGPUBuffer( |
2458 | SDL_GPUCopyPass *copy_pass, |
2459 | const SDL_GPUBufferRegion *source, |
2460 | const SDL_GPUTransferBufferLocation *destination) |
2461 | { |
2462 | if (copy_pass == NULL) { |
2463 | SDL_InvalidParamError("copy_pass" ); |
2464 | return; |
2465 | } |
2466 | if (source == NULL) { |
2467 | SDL_InvalidParamError("source" ); |
2468 | return; |
2469 | } |
2470 | if (destination == NULL) { |
2471 | SDL_InvalidParamError("destination" ); |
2472 | return; |
2473 | } |
2474 | |
2475 | if (COPYPASS_DEVICE->debug_mode) { |
2476 | CHECK_COPYPASS |
2477 | if (source->buffer == NULL) { |
2478 | SDL_assert_release(!"Source buffer cannot be NULL!" ); |
2479 | return; |
2480 | } |
2481 | if (destination->transfer_buffer == NULL) { |
2482 | SDL_assert_release(!"Destination transfer buffer cannot be NULL!" ); |
2483 | return; |
2484 | } |
2485 | } |
2486 | |
2487 | COPYPASS_DEVICE->DownloadFromBuffer( |
2488 | COPYPASS_COMMAND_BUFFER, |
2489 | source, |
2490 | destination); |
2491 | } |
2492 | |
2493 | void SDL_EndGPUCopyPass( |
2494 | SDL_GPUCopyPass *copy_pass) |
2495 | { |
2496 | if (copy_pass == NULL) { |
2497 | SDL_InvalidParamError("copy_pass" ); |
2498 | return; |
2499 | } |
2500 | |
2501 | if (COPYPASS_DEVICE->debug_mode) { |
2502 | CHECK_COPYPASS |
2503 | } |
2504 | |
2505 | COPYPASS_DEVICE->EndCopyPass( |
2506 | COPYPASS_COMMAND_BUFFER); |
2507 | |
2508 | ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false; |
2509 | } |
2510 | |
2511 | void SDL_GenerateMipmapsForGPUTexture( |
2512 | SDL_GPUCommandBuffer *command_buffer, |
2513 | SDL_GPUTexture *texture) |
2514 | { |
2515 | if (command_buffer == NULL) { |
2516 | SDL_InvalidParamError("command_buffer" ); |
2517 | return; |
2518 | } |
2519 | if (texture == NULL) { |
2520 | SDL_InvalidParamError("texture" ); |
2521 | return; |
2522 | } |
2523 | |
2524 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2525 | CHECK_COMMAND_BUFFER |
2526 | CHECK_ANY_PASS_IN_PROGRESS("Cannot generate mipmaps during a pass!" , ) |
2527 | |
2528 | TextureCommonHeader * = (TextureCommonHeader *)texture; |
2529 | if (header->info.num_levels <= 1) { |
2530 | SDL_assert_release(!"Cannot generate mipmaps for texture with num_levels <= 1!" ); |
2531 | return; |
2532 | } |
2533 | |
2534 | if (!(header->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) || !(header->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) { |
2535 | SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!" ); |
2536 | return; |
2537 | } |
2538 | } |
2539 | |
2540 | COMMAND_BUFFER_DEVICE->GenerateMipmaps( |
2541 | command_buffer, |
2542 | texture); |
2543 | } |
2544 | |
2545 | void SDL_BlitGPUTexture( |
2546 | SDL_GPUCommandBuffer *command_buffer, |
2547 | const SDL_GPUBlitInfo *info) |
2548 | { |
2549 | if (command_buffer == NULL) { |
2550 | SDL_InvalidParamError("command_buffer" ); |
2551 | return; |
2552 | } |
2553 | if (info == NULL) { |
2554 | SDL_InvalidParamError("info" ); |
2555 | return; |
2556 | } |
2557 | |
2558 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2559 | CHECK_COMMAND_BUFFER |
2560 | CHECK_ANY_PASS_IN_PROGRESS("Cannot blit during a pass!" , ) |
2561 | |
2562 | // Validation |
2563 | bool failed = false; |
2564 | TextureCommonHeader * = (TextureCommonHeader *)info->source.texture; |
2565 | TextureCommonHeader * = (TextureCommonHeader *)info->destination.texture; |
2566 | |
2567 | if (srcHeader == NULL) { |
2568 | SDL_assert_release(!"Blit source texture must be non-NULL" ); |
2569 | return; // attempting to proceed will crash |
2570 | } |
2571 | if (dstHeader == NULL) { |
2572 | SDL_assert_release(!"Blit destination texture must be non-NULL" ); |
2573 | return; // attempting to proceed will crash |
2574 | } |
2575 | if (srcHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) { |
2576 | SDL_assert_release(!"Blit source texture must have a sample count of 1" ); |
2577 | failed = true; |
2578 | } |
2579 | if ((srcHeader->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) == 0) { |
2580 | SDL_assert_release(!"Blit source texture must be created with the SAMPLER usage flag" ); |
2581 | failed = true; |
2582 | } |
2583 | if ((dstHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) == 0) { |
2584 | SDL_assert_release(!"Blit destination texture must be created with the COLOR_TARGET usage flag" ); |
2585 | failed = true; |
2586 | } |
2587 | if (IsDepthFormat(srcHeader->info.format)) { |
2588 | SDL_assert_release(!"Blit source texture cannot have a depth format" ); |
2589 | failed = true; |
2590 | } |
2591 | if (info->source.w == 0 || info->source.h == 0 || info->destination.w == 0 || info->destination.h == 0) { |
2592 | SDL_assert_release(!"Blit source/destination regions must have non-zero width, height, and depth" ); |
2593 | failed = true; |
2594 | } |
2595 | |
2596 | if (failed) { |
2597 | return; |
2598 | } |
2599 | } |
2600 | |
2601 | COMMAND_BUFFER_DEVICE->Blit( |
2602 | command_buffer, |
2603 | info); |
2604 | } |
2605 | |
2606 | // Submission/Presentation |
2607 | |
2608 | bool SDL_WindowSupportsGPUSwapchainComposition( |
2609 | SDL_GPUDevice *device, |
2610 | SDL_Window *window, |
2611 | SDL_GPUSwapchainComposition swapchain_composition) |
2612 | { |
2613 | CHECK_DEVICE_MAGIC(device, false); |
2614 | if (window == NULL) { |
2615 | SDL_InvalidParamError("window" ); |
2616 | return false; |
2617 | } |
2618 | |
2619 | if (device->debug_mode) { |
2620 | CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false) |
2621 | } |
2622 | |
2623 | return device->SupportsSwapchainComposition( |
2624 | device->driverData, |
2625 | window, |
2626 | swapchain_composition); |
2627 | } |
2628 | |
2629 | bool SDL_WindowSupportsGPUPresentMode( |
2630 | SDL_GPUDevice *device, |
2631 | SDL_Window *window, |
2632 | SDL_GPUPresentMode present_mode) |
2633 | { |
2634 | CHECK_DEVICE_MAGIC(device, false); |
2635 | if (window == NULL) { |
2636 | SDL_InvalidParamError("window" ); |
2637 | return false; |
2638 | } |
2639 | |
2640 | if (device->debug_mode) { |
2641 | CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false) |
2642 | } |
2643 | |
2644 | return device->SupportsPresentMode( |
2645 | device->driverData, |
2646 | window, |
2647 | present_mode); |
2648 | } |
2649 | |
2650 | bool SDL_ClaimWindowForGPUDevice( |
2651 | SDL_GPUDevice *device, |
2652 | SDL_Window *window) |
2653 | { |
2654 | CHECK_DEVICE_MAGIC(device, false); |
2655 | if (window == NULL) { |
2656 | SDL_InvalidParamError("window" ); |
2657 | return false; |
2658 | } |
2659 | |
2660 | return device->ClaimWindow( |
2661 | device->driverData, |
2662 | window); |
2663 | } |
2664 | |
2665 | void SDL_ReleaseWindowFromGPUDevice( |
2666 | SDL_GPUDevice *device, |
2667 | SDL_Window *window) |
2668 | { |
2669 | CHECK_DEVICE_MAGIC(device, ); |
2670 | if (window == NULL) { |
2671 | SDL_InvalidParamError("window" ); |
2672 | return; |
2673 | } |
2674 | |
2675 | device->ReleaseWindow( |
2676 | device->driverData, |
2677 | window); |
2678 | } |
2679 | |
2680 | bool SDL_SetGPUSwapchainParameters( |
2681 | SDL_GPUDevice *device, |
2682 | SDL_Window *window, |
2683 | SDL_GPUSwapchainComposition swapchain_composition, |
2684 | SDL_GPUPresentMode present_mode) |
2685 | { |
2686 | CHECK_DEVICE_MAGIC(device, false); |
2687 | if (window == NULL) { |
2688 | SDL_InvalidParamError("window" ); |
2689 | return false; |
2690 | } |
2691 | |
2692 | if (device->debug_mode) { |
2693 | CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false) |
2694 | CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false) |
2695 | } |
2696 | |
2697 | return device->SetSwapchainParameters( |
2698 | device->driverData, |
2699 | window, |
2700 | swapchain_composition, |
2701 | present_mode); |
2702 | } |
2703 | |
2704 | bool SDL_SetGPUAllowedFramesInFlight( |
2705 | SDL_GPUDevice *device, |
2706 | Uint32 allowed_frames_in_flight) |
2707 | { |
2708 | CHECK_DEVICE_MAGIC(device, false); |
2709 | |
2710 | if (device->debug_mode) { |
2711 | if (allowed_frames_in_flight < 1 || allowed_frames_in_flight > 3) |
2712 | { |
2713 | SDL_assert_release(!"allowed_frames_in_flight value must be between 1 and 3!" ); |
2714 | } |
2715 | } |
2716 | |
2717 | allowed_frames_in_flight = SDL_clamp(allowed_frames_in_flight, 1, 3); |
2718 | return device->SetAllowedFramesInFlight( |
2719 | device->driverData, |
2720 | allowed_frames_in_flight); |
2721 | } |
2722 | |
2723 | SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat( |
2724 | SDL_GPUDevice *device, |
2725 | SDL_Window *window) |
2726 | { |
2727 | CHECK_DEVICE_MAGIC(device, SDL_GPU_TEXTUREFORMAT_INVALID); |
2728 | if (window == NULL) { |
2729 | SDL_InvalidParamError("window" ); |
2730 | return SDL_GPU_TEXTUREFORMAT_INVALID; |
2731 | } |
2732 | |
2733 | return device->GetSwapchainTextureFormat( |
2734 | device->driverData, |
2735 | window); |
2736 | } |
2737 | |
2738 | bool SDL_AcquireGPUSwapchainTexture( |
2739 | SDL_GPUCommandBuffer *command_buffer, |
2740 | SDL_Window *window, |
2741 | SDL_GPUTexture **swapchain_texture, |
2742 | Uint32 *swapchain_texture_width, |
2743 | Uint32 *swapchain_texture_height) |
2744 | { |
2745 | CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2746 | |
2747 | if (command_buffer == NULL) { |
2748 | return SDL_InvalidParamError("command_buffer" ); |
2749 | } |
2750 | if (window == NULL) { |
2751 | return SDL_InvalidParamError("window" ); |
2752 | } |
2753 | if (swapchain_texture == NULL) { |
2754 | return SDL_InvalidParamError("swapchain_texture" ); |
2755 | } |
2756 | |
2757 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2758 | CHECK_COMMAND_BUFFER_RETURN_FALSE |
2759 | CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!" , false) |
2760 | } |
2761 | |
2762 | bool result = COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture( |
2763 | command_buffer, |
2764 | window, |
2765 | swapchain_texture, |
2766 | swapchain_texture_width, |
2767 | swapchain_texture_height); |
2768 | |
2769 | if (*swapchain_texture != NULL){ |
2770 | commandBufferHeader->swapchain_texture_acquired = true; |
2771 | } |
2772 | |
2773 | return result; |
2774 | } |
2775 | |
2776 | bool SDL_WaitForGPUSwapchain( |
2777 | SDL_GPUDevice *device, |
2778 | SDL_Window *window) |
2779 | { |
2780 | CHECK_DEVICE_MAGIC(device, false); |
2781 | |
2782 | if (window == NULL) { |
2783 | return SDL_InvalidParamError("window" ); |
2784 | } |
2785 | |
2786 | return device->WaitForSwapchain( |
2787 | device->driverData, |
2788 | window); |
2789 | } |
2790 | |
2791 | bool SDL_WaitAndAcquireGPUSwapchainTexture( |
2792 | SDL_GPUCommandBuffer *command_buffer, |
2793 | SDL_Window *window, |
2794 | SDL_GPUTexture **swapchain_texture, |
2795 | Uint32 *swapchain_texture_width, |
2796 | Uint32 *swapchain_texture_height) |
2797 | { |
2798 | CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2799 | |
2800 | if (command_buffer == NULL) { |
2801 | return SDL_InvalidParamError("command_buffer" ); |
2802 | } |
2803 | if (window == NULL) { |
2804 | return SDL_InvalidParamError("window" ); |
2805 | } |
2806 | if (swapchain_texture == NULL) { |
2807 | return SDL_InvalidParamError("swapchain_texture" ); |
2808 | } |
2809 | |
2810 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2811 | CHECK_COMMAND_BUFFER_RETURN_FALSE |
2812 | CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!" , false) |
2813 | } |
2814 | |
2815 | bool result = COMMAND_BUFFER_DEVICE->WaitAndAcquireSwapchainTexture( |
2816 | command_buffer, |
2817 | window, |
2818 | swapchain_texture, |
2819 | swapchain_texture_width, |
2820 | swapchain_texture_height); |
2821 | |
2822 | if (*swapchain_texture != NULL){ |
2823 | commandBufferHeader->swapchain_texture_acquired = true; |
2824 | } |
2825 | |
2826 | return result; |
2827 | } |
2828 | |
2829 | bool SDL_SubmitGPUCommandBuffer( |
2830 | SDL_GPUCommandBuffer *command_buffer) |
2831 | { |
2832 | CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2833 | |
2834 | if (command_buffer == NULL) { |
2835 | SDL_InvalidParamError("command_buffer" ); |
2836 | return false; |
2837 | } |
2838 | |
2839 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2840 | CHECK_COMMAND_BUFFER_RETURN_FALSE |
2841 | if ( |
2842 | commandBufferHeader->render_pass.in_progress || |
2843 | commandBufferHeader->compute_pass.in_progress || |
2844 | commandBufferHeader->copy_pass.in_progress) { |
2845 | SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!" ); |
2846 | return false; |
2847 | } |
2848 | } |
2849 | |
2850 | commandBufferHeader->submitted = true; |
2851 | |
2852 | return COMMAND_BUFFER_DEVICE->Submit( |
2853 | command_buffer); |
2854 | } |
2855 | |
2856 | SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence( |
2857 | SDL_GPUCommandBuffer *command_buffer) |
2858 | { |
2859 | CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2860 | |
2861 | if (command_buffer == NULL) { |
2862 | SDL_InvalidParamError("command_buffer" ); |
2863 | return NULL; |
2864 | } |
2865 | |
2866 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2867 | CHECK_COMMAND_BUFFER_RETURN_NULL |
2868 | if ( |
2869 | commandBufferHeader->render_pass.in_progress || |
2870 | commandBufferHeader->compute_pass.in_progress || |
2871 | commandBufferHeader->copy_pass.in_progress) { |
2872 | SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!" ); |
2873 | return NULL; |
2874 | } |
2875 | } |
2876 | |
2877 | commandBufferHeader->submitted = true; |
2878 | |
2879 | return COMMAND_BUFFER_DEVICE->SubmitAndAcquireFence( |
2880 | command_buffer); |
2881 | } |
2882 | |
2883 | bool SDL_CancelGPUCommandBuffer( |
2884 | SDL_GPUCommandBuffer *command_buffer) |
2885 | { |
2886 | CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; |
2887 | |
2888 | if (command_buffer == NULL) { |
2889 | SDL_InvalidParamError("command_buffer" ); |
2890 | return false; |
2891 | } |
2892 | |
2893 | if (COMMAND_BUFFER_DEVICE->debug_mode) { |
2894 | if (commandBufferHeader->swapchain_texture_acquired) { |
2895 | SDL_assert_release(!"Cannot cancel command buffer after a swapchain texture has been acquired!" ); |
2896 | return false; |
2897 | } |
2898 | } |
2899 | |
2900 | return COMMAND_BUFFER_DEVICE->Cancel( |
2901 | command_buffer); |
2902 | } |
2903 | |
2904 | bool SDL_WaitForGPUIdle( |
2905 | SDL_GPUDevice *device) |
2906 | { |
2907 | CHECK_DEVICE_MAGIC(device, false); |
2908 | |
2909 | return device->Wait( |
2910 | device->driverData); |
2911 | } |
2912 | |
2913 | bool SDL_WaitForGPUFences( |
2914 | SDL_GPUDevice *device, |
2915 | bool wait_all, |
2916 | SDL_GPUFence *const *fences, |
2917 | Uint32 num_fences) |
2918 | { |
2919 | CHECK_DEVICE_MAGIC(device, false); |
2920 | if (fences == NULL && num_fences > 0) { |
2921 | SDL_InvalidParamError("fences" ); |
2922 | return false; |
2923 | } |
2924 | |
2925 | return device->WaitForFences( |
2926 | device->driverData, |
2927 | wait_all, |
2928 | fences, |
2929 | num_fences); |
2930 | } |
2931 | |
2932 | bool SDL_QueryGPUFence( |
2933 | SDL_GPUDevice *device, |
2934 | SDL_GPUFence *fence) |
2935 | { |
2936 | CHECK_DEVICE_MAGIC(device, false); |
2937 | if (fence == NULL) { |
2938 | SDL_InvalidParamError("fence" ); |
2939 | return false; |
2940 | } |
2941 | |
2942 | return device->QueryFence( |
2943 | device->driverData, |
2944 | fence); |
2945 | } |
2946 | |
2947 | void SDL_ReleaseGPUFence( |
2948 | SDL_GPUDevice *device, |
2949 | SDL_GPUFence *fence) |
2950 | { |
2951 | CHECK_DEVICE_MAGIC(device, ); |
2952 | if (fence == NULL) { |
2953 | return; |
2954 | } |
2955 | |
2956 | device->ReleaseFence( |
2957 | device->driverData, |
2958 | fence); |
2959 | } |
2960 | |
2961 | Uint32 SDL_CalculateGPUTextureFormatSize( |
2962 | SDL_GPUTextureFormat format, |
2963 | Uint32 width, |
2964 | Uint32 height, |
2965 | Uint32 depth_or_layer_count) |
2966 | { |
2967 | Uint32 blockWidth = SDL_max(Texture_GetBlockWidth(format), 1); |
2968 | Uint32 blockHeight = SDL_max(Texture_GetBlockHeight(format), 1); |
2969 | Uint32 blocksPerRow = (width + blockWidth - 1) / blockWidth; |
2970 | Uint32 blocksPerColumn = (height + blockHeight - 1) / blockHeight; |
2971 | return depth_or_layer_count * blocksPerRow * blocksPerColumn * SDL_GPUTextureFormatTexelBlockSize(format); |
2972 | } |
2973 | |