22
22
23
23
#include < SDL3/SDL.h>
24
24
#include < SDL3/SDL_vulkan.h>
25
+ #include < atomic>
25
26
26
27
#include " application.hpp"
27
28
#include " application_wsi.hpp"
@@ -102,6 +103,49 @@ struct WSIPlatformSDL : GraniteWSIPlatform
102
103
{
103
104
}
104
105
106
+ void run_gamepad_init ()
107
+ {
108
+ Util::Timer tmp_timer;
109
+ tmp_timer.start ();
110
+
111
+ if (SDL_Init (SDL_INIT_GAMEPAD) < 0 )
112
+ {
113
+ LOGE (" Failed to init gamepad.\n " );
114
+ return ;
115
+ }
116
+
117
+ LOGI (" SDL_Init(GAMEPAD) took %.3f seconds async.\n " , tmp_timer.end ());
118
+
119
+ push_task_to_main_thread ([this ]() {
120
+ if (!pad.init (get_input_tracker (), [](std::function<void ()> func) { func (); }))
121
+ LOGE (" Failed to init gamepad tracker.\n " );
122
+
123
+ gamepad_init_async.store (true , std::memory_order_release);
124
+ });
125
+ }
126
+
127
+ void kick_gamepad_init ()
128
+ {
129
+ SDL_SetHint (SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, " 1" );
130
+ // Adding gamepad events will make main loop spin without waiting.
131
+ SDL_SetHint (SDL_HINT_AUTO_UPDATE_JOYSTICKS, " 0" );
132
+
133
+ // Enumerating gamepads can be extremely slow in some cases. Do this async.
134
+ // Gamepad interface is very async friendly.
135
+
136
+ gamepad_init_async = false ;
137
+
138
+ if (auto *tg = GRANITE_THREAD_GROUP ())
139
+ {
140
+ gamepad_init_task = tg->create_task ([this ]() { run_gamepad_init (); });
141
+ gamepad_init_task->set_desc (" SDL init gamepad" );
142
+ gamepad_init_task->set_task_class (TaskClass::Background);
143
+ gamepad_init_task->flush ();
144
+ }
145
+ else
146
+ run_gamepad_init ();
147
+ }
148
+
105
149
bool init (const std::string &name, unsigned width_, unsigned height_)
106
150
{
107
151
request_tear_down.store (false );
@@ -126,16 +170,15 @@ struct WSIPlatformSDL : GraniteWSIPlatform
126
170
127
171
Util::Timer tmp_timer;
128
172
tmp_timer.start ();
129
- if (SDL_Init (SDL_INIT_EVENTS | SDL_INIT_GAMEPAD | SDL_INIT_VIDEO) < 0 )
173
+ if (SDL_Init (SDL_INIT_EVENTS | SDL_INIT_VIDEO) < 0 )
130
174
{
131
175
LOGE (" Failed to init SDL.\n " );
132
176
return false ;
133
177
}
134
178
LOGI (" SDL_Init took %.3f seconds.\n " , tmp_timer.end ());
135
179
136
- SDL_SetHint (SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, " 1" );
137
- // Adding gamepad events will make main loop spin without waiting.
138
- SDL_SetHint (SDL_HINT_AUTO_UPDATE_JOYSTICKS, " 0" );
180
+ kick_gamepad_init ();
181
+
139
182
SDL_SetEventEnabled (SDL_EVENT_DROP_FILE, SDL_FALSE);
140
183
SDL_SetEventEnabled (SDL_EVENT_DROP_TEXT, SDL_FALSE);
141
184
@@ -174,7 +217,7 @@ struct WSIPlatformSDL : GraniteWSIPlatform
174
217
application.info .pApplicationName = application.name .empty () ? " Granite" : application.name .c_str ();
175
218
application.info .apiVersion = VK_API_VERSION_1_1;
176
219
177
- return pad. init ( get_input_tracker (), [](std::function< void ()> func) { func (); }) ;
220
+ return true ;
178
221
}
179
222
180
223
const VkApplicationInfo *get_application_info () override
@@ -268,7 +311,9 @@ struct WSIPlatformSDL : GraniteWSIPlatform
268
311
std::lock_guard<std::mutex> holder{get_input_tracker ().get_lock ()};
269
312
flush_deferred_input_events ();
270
313
process_events_async_thread ();
271
- pad.update (get_input_tracker ());
314
+
315
+ if (gamepad_init_async.load (std::memory_order_acquire))
316
+ pad.update (get_input_tracker ());
272
317
get_input_tracker ().dispatch_current_state (get_frame_timer ().get_frame_time ());
273
318
}
274
319
@@ -278,7 +323,8 @@ struct WSIPlatformSDL : GraniteWSIPlatform
278
323
begin_async_input_handling ();
279
324
{
280
325
process_events_async_thread ();
281
- pad.update (get_input_tracker ());
326
+ if (gamepad_init_async.load (std::memory_order_acquire))
327
+ pad.update (get_input_tracker ());
282
328
}
283
329
end_async_input_handling ();
284
330
get_input_tracker ().dispatch_current_state (0.0 , override_handler);
@@ -316,8 +362,12 @@ struct WSIPlatformSDL : GraniteWSIPlatform
316
362
317
363
~WSIPlatformSDL ()
318
364
{
365
+ if (gamepad_init_task)
366
+ gamepad_init_task->wait ();
367
+
319
368
if (window)
320
369
SDL_DestroyWindow (window);
370
+
321
371
pad.close ();
322
372
SDL_Quit ();
323
373
}
@@ -656,6 +706,8 @@ struct WSIPlatformSDL : GraniteWSIPlatform
656
706
uint32_t wake_event_type = 0 ;
657
707
Options options;
658
708
std::string clipboard;
709
+ TaskGroupHandle gamepad_init_task;
710
+ std::atomic<bool > gamepad_init_async;
659
711
660
712
struct
661
713
{
0 commit comments