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