8#define DRIVER_DISPLAY_VULKAN "Vulkan"
9#define DRIVER_DISPLAY_DIRECT3D12 "Direct3D 12"
11#ifdef DTTR_MODS_ENABLED
26 return SDL_GPU_SAMPLECOUNT_2;
28 return SDL_GPU_SAMPLECOUNT_4;
30 return SDL_GPU_SAMPLECOUNT_8;
32 return SDL_GPU_SAMPLECOUNT_1;
38 case SDL_GPU_SAMPLECOUNT_2:
40 case SDL_GPU_SAMPLECOUNT_4:
42 case SDL_GPU_SAMPLECOUNT_8:
54 if (requested == SDL_GPU_SAMPLECOUNT_1) {
55 return SDL_GPU_SAMPLECOUNT_1;
58 const SDL_GPUTextureFormat swapchain_fmt = SDL_GetGPUSwapchainTextureFormat(
62 const bool color_supported = SDL_GPUTextureSupportsSampleCount(
67 const bool depth_supported = SDL_GPUTextureSupportsSampleCount(
69 SDL_GPU_TEXTUREFORMAT_D32_FLOAT,
73 if (color_supported && depth_supported) {
78 "Requested MSAA x%d is unsupported on this device/format. "
79 "Falling back to x1.",
82 return SDL_GPU_SAMPLECOUNT_1;
90 SDL_DestroyGPUDevice(
state->device);
99 SDL_ReleaseWindowFromGPUDevice(
state->device,
state->window);
106 const SDL_GPUShaderFormat requested_formats,
109 state->device = SDL_CreateGPUDevice(requested_formats,
false, driver);
111 if (!
state->device) {
113 "Failed to create SDL GPU device for driver '%s' "
114 "(requested_formats=0x%x): %s",
115 driver ? driver :
"default",
116 (
unsigned int)requested_formats,
122 if (!SDL_ClaimWindowForGPUDevice(
state->device,
state->window)) {
124 "Failed to claim window for SDL GPU driver '%s': %s",
125 driver ? driver :
"default",
132 const bool immediate_ok = SDL_WindowSupportsGPUPresentMode(
135 SDL_GPU_PRESENTMODE_IMMEDIATE
139 "IMMEDIATE present mode unsupported for '%s', falling back to VSYNC",
140 driver ? driver :
"default"
144 if (!SDL_SetGPUSwapchainParameters(
147 SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
148 immediate_ok ? SDL_GPU_PRESENTMODE_IMMEDIATE : SDL_GPU_PRESENTMODE_VSYNC
150 DTTR_LOG_ERROR(
"Failed to set swap chain parameters: %s", SDL_GetError());
153 const SDL_GPUShaderFormat available_formats = SDL_GetGPUShaderFormats(
state->device);
154 const char *active_driver = SDL_GetGPUDeviceDriver(
state->device);
160 if (
state->shader_format != SDL_GPU_SHADERFORMAT_INVALID) {
165 "SDL GPU driver '%s' does not support required shader format. Available "
167 active_driver ? active_driver :
"unknown",
168 (
unsigned int)available_formats
193 if (requested_driver) {
199 "GPU device creation failed for configured graphics_api='%s'; no fallback "
207 const char *
const driver_candidates[] = {
213 for (
size_t i = 0; i < SDL_arraysize(driver_candidates); i++) {
219 DTTR_LOG_ERROR(
"GPU device creation failed for all supported APIs (d3d12/vulkan)");
235 state->backend_data = bd;
241 "MSAA requested: x%d, effective: x%d",
247 "SDL GPU initialized with %s (shaders: %s)",
248 SDL_GetGPUDeviceDriver(
state->device),
265 if (!
state->device) {
270 if (
state->samplers[i]) {
271 SDL_ReleaseGPUSampler(
state->device,
state->samplers[i]);
275 if (
state->dummy_texture) {
276 SDL_ReleaseGPUTexture(
state->device,
state->dummy_texture);
279 if (
state->depth_texture) {
280 SDL_ReleaseGPUTexture(
state->device,
state->depth_texture);
283 if (
state->msaa_render_target) {
284 SDL_ReleaseGPUTexture(
state->device,
state->msaa_render_target);
287 if (
state->render_target) {
288 SDL_ReleaseGPUTexture(
state->device,
state->render_target);
291 if (
state->transfer_buffer) {
292 SDL_ReleaseGPUTransferBuffer(
state->device,
state->transfer_buffer);
295 if (
state->vertex_buffer) {
296 SDL_ReleaseGPUBuffer(
state->device,
state->vertex_buffer);
312 if (
state->pipelines[i]) {
313 SDL_ReleaseGPUGraphicsPipeline(
state->device,
state->pipelines[i]);
343 return state->msaa_sample_count != SDL_GPU_SAMPLECOUNT_1
351 const SDL_GPUTransferBufferCreateInfo info = {
352 .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
356 return SDL_CreateGPUTransferBuffer(
state->device, &info);
364 state->upload_pool[pool_slot].in_use =
false;
397 const int slot_index = (grow_slot >= 0) ? grow_slot : free_slot;
399 if (slot_index < 0) {
425 SDL_GPURenderPass *render_pass
431 const SDL_GPUBufferBinding vbuf_binding = {
432 .buffer =
state->vertex_buffer,
435 SDL_BindGPUVertexBuffers(render_pass, 0, &vbuf_binding, 1);
439 if (!
state->render_pass) {
443 SDL_EndGPURenderPass(
state->render_pass);
454 SDL_LockMutex(
state->texture_mutex);
461 SDL_UnlockMutex(
state->texture_mutex);
472 if (
st->gpu_tex &&
state->device
482 SDL_GPUCopyPass *copy,
489 if (!copy || !tex || !pixels || bytes == 0) {
494 SDL_GPUTransferBuffer *tbuf =
NULL;
495 bool from_pool =
false;
502 if (pool_slot >= 0) {
503 tbuf =
state->upload_pool[pool_slot].transfer_buffer;
514 void *mapped = SDL_MapGPUTransferBuffer(
state->device, tbuf,
false);
520 SDL_ReleaseGPUTransferBuffer(
state->device, tbuf);
527 memcpy(mapped, pixels, bytes);
528 SDL_UnmapGPUTransferBuffer(
state->device, tbuf);
530 const SDL_GPUTextureTransferInfo
src = {
531 .transfer_buffer = tbuf,
532 .pixels_per_row = (Uint32)width,
535 const SDL_GPUTextureRegion
dst = {
542 SDL_UploadToGPUTexture(copy, &
src, &
dst,
false);
547 SDL_ReleaseGPUTransferBuffer(
state->device, tbuf);
558 SDL_GPUCopyPass *copy,
562 if (!
state->texture_mutex) {
566 int pending_count = 0;
567 SDL_LockMutex(
state->texture_mutex);
568 const size_t queued_count = kv_size(
state->pending_upload_indices);
569 size_t deferred_write = 0;
582 for (
size_t q = 0; q < queued_count; q++) {
583 const int idx = kv_A(
state->pending_upload_indices, q);
585 if (idx < 0 || idx >=
state->staged_texture_count) {
592 st->pending_upload =
false;
596 if (max_uploads > 0 && pending_count >= max_uploads) {
597 kv_A(
state->pending_upload_indices, deferred_write++) = idx;
601 st->pending_upload =
false;
609 const uint32_t bytes = (uint32_t)(
st->width *
st->height * 4);
623 detached[pending_count] = (detached_upload){
625 .pixels =
st->pixels,
627 .height =
st->height,
629 .generate_mips =
dttr_config.generate_texture_mipmaps,
636 state->pending_upload_indices.n = deferred_write;
637 SDL_UnlockMutex(
state->texture_mutex);
639 for (
int i = 0; i < pending_count; i++) {
650 .tex = detached[i].tex,
651 .bytes = detached[i].bytes,
652 .generate_mips = detached[i].generate_mips,
657 return pending_count;
663 SDL_GPUCommandBuffer *cmd,
666 uint32_t *uploaded_texture_count,
667 uint64_t *uploaded_bytes
669 for (
int p = 0; p < pending_count; p++) {
670 if (!pending[p].uploaded || !pending[p].tex) {
674 if (pending[p].generate_mips) {
675 SDL_GenerateMipmapsForGPUTexture(cmd, pending[p].tex);
676 state->perf_mips_generated_accum++;
678 state->perf_mips_skipped_accum++;
681 if (uploaded_texture_count) {
682 (*uploaded_texture_count)++;
685 if (uploaded_bytes) {
686 (*uploaded_bytes) += pending[p].
bytes;
699 SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
703 SDL_EndGPUCopyPass(copy);
706 if (pending_count == 0) {
710 uint32_t uploaded_texture_count = 0;
711 uint64_t uploaded_bytes = 0;
717 &uploaded_texture_count,
721 state->perf_upload_textures_accum += uploaded_texture_count;
722 state->perf_upload_bytes_accum += uploaded_bytes;
726 if (!
state->render_pass) {
730 const SDL_GPUViewport viewport = {
734 .h = (
float)
state->height,
739 SDL_SetGPUViewport(
state->render_pass, &viewport);
741 const SDL_Rect scissor = {
748 SDL_SetGPUScissor(
state->render_pass, &scissor);
754 if (
state->render_pass) {
759 const SDL_GPUColorTargetInfo color_target = {
760 .texture = use_msaa ?
state->msaa_render_target :
state->render_target,
761 .load_op = SDL_GPU_LOADOP_LOAD,
762 .store_op = use_msaa ? SDL_GPU_STOREOP_RESOLVE_AND_STORE : SDL_GPU_STOREOP_STORE,
763 .resolve_texture = use_msaa ?
state->render_target :
NULL,
764 .resolve_mip_level = 0,
768 const SDL_GPUDepthStencilTargetInfo depth_target = {
769 .texture =
state->depth_texture,
770 .load_op = SDL_GPU_LOADOP_LOAD,
771 .store_op = SDL_GPU_STOREOP_DONT_CARE,
774 state->render_pass = SDL_BeginGPURenderPass(
781 if (!
state->render_pass) {
811 const SDL_GPUColorTargetInfo color_target = {
812 .texture = use_msaa ?
state->msaa_render_target :
state->render_target,
815 : SDL_GPU_LOADOP_LOAD,
816 .store_op = use_msaa ? SDL_GPU_STOREOP_RESOLVE_AND_STORE : SDL_GPU_STOREOP_STORE,
817 .resolve_texture = use_msaa ?
state->render_target :
NULL,
818 .resolve_mip_level = 0,
822 const SDL_GPUDepthStencilTargetInfo depth_target = {
823 .texture =
state->depth_texture,
826 : SDL_GPU_LOADOP_LOAD,
827 .store_op = SDL_GPU_STOREOP_STORE,
830 state->render_pass = SDL_BeginGPURenderPass(
854 if (!
state->render_pass) {
865 SDL_BindGPUGraphicsPipeline(
state->render_pass,
state->pipelines[pidx]);
876 SDL_PushGPUVertexUniformData(
882 SDL_PushGPUFragmentUniformData(
891 const SDL_GPUTextureSamplerBinding tex_binding = {
896 SDL_BindGPUFragmentSamplers(
state->render_pass, 0, &tex_binding, 1);
908 SDL_DrawGPUPrimitives(
925 if (kv_size(
state->batch_records) == 0) {
933 for (
size_t i = 0; i < kv_size(
state->batch_records); i++) {
955 state->frame_index++;
957 state->cmd = SDL_AcquireGPUCommandBuffer(
state->device);
966 if (!SDL_WaitAndAcquireGPUSwapchainTexture(
969 &
state->swapchain_tex,
970 &
state->swapchain_width,
971 &
state->swapchain_height
973 DTTR_LOG_WARN(
"Failed to acquire swapchain texture: %s", SDL_GetError());
974 SDL_CancelGPUCommandBuffer(
state->cmd);
980 if (!
state->swapchain_tex) {
981 SDL_CancelGPUCommandBuffer(
state->cmd);
989 state->batch_records.n = 0;
990 state->vertex_offset = 0;
991 state->transfer_mapped = SDL_MapGPUTransferBuffer(
993 state->transfer_buffer,
997 if (!
state->transfer_mapped) {
1001 state->frame_active =
true;
1007 state->frame_active =
false;
1011 if (
state->transfer_mapped) {
1012 SDL_UnmapGPUTransferBuffer(
state->device,
state->transfer_buffer);
1020 if (
state->vertex_offset > 0) {
1021 SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(
state->cmd);
1024 const SDL_GPUTransferBufferLocation
src = {
1025 .transfer_buffer =
state->transfer_buffer,
1028 const SDL_GPUBufferRegion
dst = {
1029 .buffer =
state->vertex_buffer,
1033 SDL_UploadToGPUBuffer(copy, &
src, &
dst,
true);
1034 SDL_EndGPUCopyPass(copy);
1044#ifdef DTTR_MODS_ENABLED
1047 state->render_target,
1048 (uint32_t)
state->width,
1049 (uint32_t)
state->height
1061 bool overlay_rendered =
false;
1062 if (
state->swapchain_tex) {
1063 const Uint32 swap_w = (
state->swapchain_width > 0) ?
state->swapchain_width
1064 : (Uint32)
state->width;
1065 const Uint32 swap_h = (
state->swapchain_height > 0) ?
state->swapchain_height
1066 : (Uint32)
state->height;
1075 (!is_internal_method)
1079 overlay_rendered =
true;
1081 const SDL_GPUBlitInfo blit = {
1084 .texture =
state->render_target,
1090 .texture =
state->swapchain_tex,
1096 .clear_color = {0.0f, 0.0f, 0.0f, 1.0f},
1097 .load_op = SDL_GPU_LOADOP_CLEAR,
1101 SDL_BlitGPUTexture(
state->cmd, &blit);
1103#ifdef DTTR_MODS_ENABLED
1106 state->swapchain_tex,
1118 SDL_SubmitGPUCommandBuffer(
state->cmd);
1121 SDL_WaitForGPUIdle(
state->device);
1131 if (
state->video_texture &&
state->video_width == width
1132 &&
state->video_height == height) {
1136 if (
state->video_texture) {
1137 SDL_ReleaseGPUTexture(
state->device,
state->video_texture);
1141 const SDL_GPUTextureCreateInfo tex_info = {
1142 .type = SDL_GPU_TEXTURETYPE_2D,
1143 .format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM,
1144 .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER,
1147 .layer_count_or_depth = 1,
1149 .sample_count = SDL_GPU_SAMPLECOUNT_1,
1152 state->video_texture = SDL_CreateGPUTexture(
state->device, &tex_info);
1154 if (!
state->video_texture) {
1158 state->video_width = width;
1159 state->video_height = height;
1167 const uint8_t *pixels,
1176 if (
state->frame_active) {
1185 const Uint32 upload_size = (Uint32)(
stride * height);
1192 void *mapped = SDL_MapGPUTransferBuffer(
state->device, tbuf,
false);
1195 SDL_ReleaseGPUTransferBuffer(
state->device, tbuf);
1199 memcpy(mapped, pixels, upload_size);
1200 SDL_UnmapGPUTransferBuffer(
state->device, tbuf);
1202 SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(
state->device);
1205 SDL_ReleaseGPUTransferBuffer(
state->device, tbuf);
1209 SDL_GPUTexture *swapchain_tex =
NULL;
1210 Uint32 swapchain_w = 0;
1211 Uint32 swapchain_h = 0;
1212 SDL_WaitAndAcquireGPUSwapchainTexture(
1220 SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
1223 const SDL_GPUTextureTransferInfo
src = {
1224 .transfer_buffer = tbuf,
1226 .pixels_per_row = (Uint32)(
stride / 4),
1227 .rows_per_layer = (Uint32)height,
1230 const SDL_GPUTextureRegion
dst = {
1231 .texture =
state->video_texture,
1238 .
h = (Uint32)height,
1242 SDL_UploadToGPUTexture(copy, &
src, &
dst,
false);
1243 SDL_EndGPUCopyPass(copy);
1246 if (swapchain_tex) {
1257 const SDL_GPUBlitInfo blit = {
1260 .texture =
state->video_texture,
1262 .layer_or_depth_plane = 0,
1266 .
h = (Uint32)height,
1270 .texture = swapchain_tex,
1272 .layer_or_depth_plane = 0,
1278 .load_op = SDL_GPU_LOADOP_CLEAR,
1279 .clear_color = (SDL_FColor){0.0f, 0.0f, 0.0f, 1.0f},
1280 .flip_mode = SDL_FLIP_NONE,
1285 SDL_BlitGPUTexture(cmd, &blit);
1288 SDL_SubmitGPUCommandBuffer(cmd);
1289 SDL_ReleaseGPUTransferBuffer(
state->device, tbuf);
static void defer_texture_destroy(DTTR_BackendState *state, int texture_index)
static void begin_frame(DTTR_BackendState *state)
static const char * get_driver_name(const DTTR_BackendState *state)
static void end_frame(DTTR_BackendState *state)
static void cleanup(DTTR_BackendState *state)
static const DTTR_RendererVtbl renderer
static bool present_video_frame_bgra(DTTR_BackendState *state, const uint8_t *pixels, int width, int height, int stride)
#define DRIVER_DISPLAY_VULKAN
static void begin_clear_pass(DTTR_BackendState *state, const DTTR_BatchRecord *rec, graphics_replay_state *replay_state)
static void release_window_device(DTTR_BackendState *state)
static SDL_GPUTransferBuffer * create_upload_buffer(DTTR_BackendState *state, uint32_t bytes)
static void generate_pending_mipmaps(DTTR_BackendState *state, SDL_GPUCommandBuffer *cmd, const graphics_pending_upload *pending, int pending_count, uint32_t *uploaded_texture_count, uint64_t *uploaded_bytes)
static void defer_texture_destroy(DTTR_BackendState *state, int texture_index)
static bool try_create_device_for_driver(DTTR_BackendState *state, const SDL_GPUShaderFormat requested_formats, const char *driver)
static bool ensure_video_texture(DTTR_BackendState *state, int width, int height)
static void set_default_viewport(const DTTR_BackendState *state)
static SDL_GPUSampleCount select_msaa_sample_count(DTTR_BackendState *state)
static void end_render_pass_if_active(DTTR_BackendState *state)
static void release_deferred_texture_destroys(DTTR_BackendState *state)
static void begin_frame(DTTR_BackendState *state)
bool dttr_graphics_sdl3gpu_init(DTTR_BackendState *state)
static const char * get_driver_name(const DTTR_BackendState *state)
static void release_upload_pool_slot(DTTR_BackendState *state, int pool_slot)
static SDL_GPUSampleCount msaa_sample_count_from_config(int value)
static void upload_pending_textures(DTTR_BackendState *state, SDL_GPUCommandBuffer *cmd)
static bool create_device(DTTR_BackendState *state)
static bool msaa_enabled(const DTTR_BackendState *state)
static graphics_replay_stats replay_batch_records(DTTR_BackendState *state)
static bool resize(DTTR_BackendState *state, int width, int height)
static const char * graphics_api_driver_name(DTTR_GraphicsApi api)
static void draw_batch_record(DTTR_BackendState *state, const DTTR_BatchRecord *rec, graphics_replay_state *replay_state, graphics_replay_stats *replay_stats)
static void destroy_device(DTTR_BackendState *state)
static bool begin_draw_pass_if_needed(DTTR_BackendState *state)
static void bind_frame_vertex_buffer(const DTTR_BackendState *state, SDL_GPURenderPass *render_pass)
static bool upload_texture_data(DTTR_BackendState *state, SDL_GPUCopyPass *copy, SDL_GPUTexture *tex, void *pixels, int width, int height, uint32_t bytes)
static void end_frame(DTTR_BackendState *state)
static int msaa_sample_count_to_int(SDL_GPUSampleCount value)
#define DRIVER_DISPLAY_DIRECT3D12
static int acquire_upload_pool_slot(DTTR_BackendState *state, uint32_t bytes)
static void cleanup(DTTR_BackendState *state)
static const char * driver_display_name(const char *driver)
static int collect_and_upload_pending(DTTR_BackendState *state, SDL_GPUCopyPass *copy, graphics_pending_upload *pending_uploads, int max_uploads)
static void reset_replay_state(graphics_replay_state *replay_state)
static bool present_video_frame_bgra(DTTR_BackendState *state, const uint8_t *pixels, int width, int height, int stride)
bool dttr_graphics_sdl3gpu_create_pipelines()
Builds all graphics pipelines used by the SDL3 GPU backend.
bool dttr_graphics_sdl3gpu_resize_render_textures(int width, int height)
Recreates resolution-dependent render textures after updating target size.
bool dttr_graphics_sdl3gpu_create_resources()
Creates shared GPU resources used by the SDL3 GPU backend.
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD idx float
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void DWORD st
const DTTR_BackendState * state
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void * dst
DTTR_Graphics_COM_DirectDraw7 *self DWORD DWORD h
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
@ DTTR_GRAPHICS_API_DIRECT3D12
@ DTTR_GRAPHICS_API_VULKAN
#define DTTR_DRIVER_VULKAN
@ DTTR_SCALING_METHOD_LOGICAL
#define DTTR_DRIVER_DIRECT3D12
@ DTTR_SCALING_MODE_STRETCH
@ DTTR_SCALING_MODE_INTEGER
#define DTTR_LOG_WARN(...)
#define DTTR_LOG_INFO(...)
#define DTTR_LOG_ERROR(...)
void dttr_graphics_mod_present_rect_before(DTTR_BackendState *state, const DTTR_PresentRect *present)
void dttr_graphics_mod_present_rect_after(DTTR_BackendState *state, const DTTR_PresentRect *present, bool overlay_rendered)
#define DTTR_PIPELINE_COUNT
#define DTTR_SAMPLER_COUNT
SDL_GPUShaderFormat dttr_graphics_select_shader_format_for_driver(const char *driver, SDL_GPUShaderFormat formats)
bool dttr_graphics_ensure_staged_texture(DTTR_BackendState *state, DTTR_StagedTexture *st)
bool dttr_graphics_is_gpu_thread()
#define DTTR_UPLOAD_POOL_SIZE
SDL_GPUShaderFormat dttr_graphics_requested_shader_formats()
static void dttr_graphics_mod_before_game_frame(DTTR_BackendState *)
DTTR_PresentRect dttr_graphics_compute_present_rect(int dst_w, int dst_h, int src_w, int src_h, bool stretch, bool integer_fit, float fallback_scale)
#define DTTR_PIPELINE_INDEX(bmode, dtest, dwrite)
const char * dttr_graphics_shader_format_name(SDL_GPUShaderFormat format)
static void dttr_graphics_mod_after_game_frame(DTTR_BackendState *)
static void dttr_graphics_mod_frame_begin(DTTR_BackendState *)
static void dttr_graphics_mod_frame_end(DTTR_BackendState *)
#define DTTR_MAX_STAGED_TEXTURES
void dttr_imgui_render_game_sdl3gpu(SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *render_target, uint32_t w, uint32_t h)
void dttr_imgui_render_sdl3gpu(SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *swapchain_tex, uint32_t swap_w, uint32_t swap_h, uint32_t game_x, uint32_t game_y, uint32_t game_w, uint32_t game_h)
A recorded clear or draw command replayed during frame submission.
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@317066375077304207167347173122133172104242212006 clear
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@107356260052026241174121242151011150024304321020 draw
DTTR_BatchRecordType type
Game-image placement within the present target, in target pixels.
Backend-specific operations dispatched through function pointers.
One reusable upload slot holding a transfer buffer for texture uploads.
SDL_GPUTransferBuffer * transfer_buffer
SDL_GPUSampler * last_sampler
SDL_GPUTexture * last_texture
uint32_t pipeline_bind_count
uint32_t sampler_bind_count
SDL3GPU backend-private deferred texture destroy queue.
int deferred_destroy_count
SDL_GPUTexture * deferred_destroys[DTTR_MAX_STAGED_TEXTURES]