mirror of
https://github.com/Genymobile/scrcpy
synced 2025-08-31 14:25:56 +00:00
Improve startup time
On startup, the client has to: 1. listen on a port 2. push and start the server to the device 3. wait for the server to connect (accept) 4. read device name and size 5. initialize SDL 6. initialize the window and renderer 7. show the window From the execution of the app_process command to start the server on the device, to the execution of the java main method, it takes ~800ms. As a consequence, step 3 also takes ~800ms on the client. Once complete, the client initializes SDL, which takes ~500ms. These two expensive actions are executed sequentially: HOST DEVICE listen on port | | push/start the server |----------------->|| app_process loads the jar accept the connection . ^ || . | || . | WASTE || . | OF || . | TIME || . | || . | || . v X execution of our java main connection accepted |<-----------------| connect to the host init SDL || | || ,----------------| send frames || |,---------------| || ||,--------------| || |||,-------------| || ||||,------------| init window/renderer | |||||,-----------| display frames |<++++++-----------| (many frames skipped) The rationale for step 3 occuring before step 5 is that initializing SDL replaces the SIGTERM handler to receive the event in the event loop, so pressing Ctrl+C during step 5 would not work (since it blocks the event loop). But this is not so important; let's parallelize the SDL initialization with the app_process execution (we'll just add a timeout to the connection): HOST DEVICE listen on port | | push/start the server |----------------->||app_process loads the jar init SDL || || || || || || || || || || || || accept the connection . || . X execution of our java main connection accepted |<-----------------| connect to the host init window/renderer | | display frames |<-----------------| send frames |<-----------------| In addition, show the window only once the first frame is available to avoid flickering (opening a black window for 100~200ms). Note: the window and renderer are initialized after the connection is accepted because they use the device information received from the device.
This commit is contained in:
@@ -57,6 +57,11 @@ static void event_loop(void) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "User requested to quit");
|
||||
return;
|
||||
case EVENT_NEW_FRAME:
|
||||
if (!screen.has_frame) {
|
||||
screen.has_frame = SDL_TRUE;
|
||||
// this is the very first frame, show the window
|
||||
screen_show_window(&screen);
|
||||
}
|
||||
if (!screen_update_frame(&screen, &frames)) {
|
||||
return;
|
||||
}
|
||||
@@ -101,6 +106,11 @@ SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 b
|
||||
|
||||
SDL_bool ret = SDL_TRUE;
|
||||
|
||||
if (!sdl_init_and_configure()) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_destroy_server;
|
||||
}
|
||||
|
||||
// to reduce startup time, we could be tempted to init other stuff before blocking here
|
||||
// but we should not block after SDL_Init since it handles the signals (Ctrl+C) in its
|
||||
// event loop: blocking could lead to deadlock
|
||||
@@ -149,11 +159,6 @@ SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 b
|
||||
goto finally_destroy_controller;
|
||||
}
|
||||
|
||||
if (!sdl_init_and_configure()) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_stop_and_join_controller;
|
||||
}
|
||||
|
||||
if (!screen_init_rendering(&screen, device_name, frame_size)) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_stop_and_join_controller;
|
||||
|
Reference in New Issue
Block a user