Skip to content

Add adaptive virtual display that adjusts to window size.#6705

Open
TinuraD wants to merge 2 commits intoGenymobile:masterfrom
TinuraD:adaptive-virtual-display
Open

Add adaptive virtual display that adjusts to window size.#6705
TinuraD wants to merge 2 commits intoGenymobile:masterfrom
TinuraD:adaptive-virtual-display

Conversation

@TinuraD
Copy link

@TinuraD TinuraD commented Mar 4, 2026

I noticed some developers have made GUI or companion apps using scrcpy, so being able to open apps in resizable windows would be cool. SO I’ve just added an adaptive virtual display option.

  • Instead of using --new-display, you can now also use --adaptive-new-display too, which provides an adaptive virtual display that resizes according to your current window.
  • It also includes --adaptive-scale, which allows you to change the scale (default is 1). [Eg: 0.5, 2.0]
  • This basically changes the virtual display's resolution and calculates an adaptive DPI based on your current PC screen resolution.
  • All existing functions remain untouched, so --new-display still works as before.
  • I attached two video clips to show how it works.
  • But i didn't update documentations.

adaptivevd.mp4
adaptiveapp.mp4

@TinuraD TinuraD changed the title Added adaptive virtual display that adjusts to window size. Add adaptive virtual display that adjusts to window size. Mar 4, 2026
@TinuraD TinuraD closed this Mar 4, 2026
@TinuraD
Copy link
Author

TinuraD commented Mar 4, 2026

P.S. I noticed that someone implemented the same feature in [#6351]. Since it hasn't been merged yet, I decided to reopen my PR too. I hope one of these will be added to scrcpy soon.

@TinuraD TinuraD reopened this Mar 5, 2026
Copy link
Contributor

@LHLaurini LHLaurini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR!

I left you some comments. I personally find your implementation cleaner than the other one, although that one works a bit better at the moment.

Your implementation makes the video look a bit blurry, probably because the server does some rounding to the dimensions.

Comment on lines +300 to +305
} catch (Exception e) {
Ln.w("Virtual display resize failed, fallback to recreate", e);
displaySizeMonitor.stopAndRelease();
virtualDisplay.release();
virtualDisplay = null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole point of resize is to "to allow applications using virtual displays to adapt to changing conditions without having to tear down and recreate the display" (from the docs). Is this really necessary?

IMO unless this happens in some devices, you should just show a warning and keep going

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed and added the warning.

app/src/screen.c Outdated
Comment on lines +88 to +93
if (size.width == 0 || size.height == 0) {
return;
}
if (size.width < 64 || size.height < 64) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

app/src/screen.c Outdated
Comment on lines +925 to +937
@@ -811,6 +934,7 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
return true;
}
case SC_EVENT_NEW_FRAME: {
sc_screen_maybe_send_vd_resize(screen);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably only need one sc_screen_maybe_send_vd_resize here. I'd keep the one in SC_EVENT_NEW_FRAME.

Copy link
Author

@TinuraD TinuraD Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed. Kept the one you did recommend.

{
.longopt_id = OPT_ADAPTIVE_NEW_DISPLAY,
.longopt = "adaptive-new-display",
.argdesc = "[<width>x<height>][/<dpi>]",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dpi value is almost immediately ignored in favor of the one from adaptive-scale

Copy link
Author

@TinuraD TinuraD Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since scaling can basically handle dpi I thought it wasn’t needed. But it makes sense to add a known dpi value. So I fixed it.


static uint16_t
get_window_dpi(const struct sc_screen *screen) {
if (screen->adaptive_new_display) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you meant to check vd_scale here? This is always true.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

app/src/screen.c Outdated
}
screen->vd_resize_size = size;
screen->vd_resize_pending = true;
screen->vd_resize_deadline_ms = SDL_GetTicks() + 250;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a constant for this value

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines -494 to +605
struct sc_size window_size =
get_initial_optimal_size(screen->content_size, screen->req.width,
screen->req.height);
struct sc_size window_size;
if (screen->adaptive_new_display
&& !screen->req.width && !screen->req.height) {
struct sc_size bounds;
if (get_preferred_display_bounds(&bounds)) {
window_size = get_optimal_size(bounds, screen->content_size, true);
} else {
window_size = get_initial_optimal_size(screen->content_size,
screen->req.width,
screen->req.height);
}
} else {
window_size = get_initial_optimal_size(screen->content_size,
screen->req.width,
screen->req.height);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the goal of this change?

Copy link
Author

@TinuraD TinuraD Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, the resizing function isn’t tied to the initial startup, as it’s mostly based on normal new-display behavior. This allows the virtual display to have adaptive window size on initial launch following px to dpi conversion or using custom arguments.

Comment on lines +669 to +676
if (screen->new_display) {
// For new-display, keep the window size controlled by the user.
// Do not auto-resize the window to the content size to avoid
// feedback loops with virtual display resizing.
screen->content_size = new_content_size;
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really a problem? Unless I'm mistaken, shouldn't the check in lines 108-110 avoid that?

Copy link
Author

@TinuraD TinuraD Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to avoid issues when Android's rotation causes the virtual display to resize. Some Android apps, like video players, change the rotation while the app is in use, such as when opening a video. Even though the window appears the same, it still makes a very small size change as i noticed which can create loops.

Comment on lines +152 to +156
if (pendingRelaunchOnResize && lastStartedAppPackage != null) {
pendingRelaunchOnResize = false;
Ln.i("Relaunching app \"" + lastStartedAppPackage + "\" on resized display " + virtualDisplayId + "...");
Device.startApp(lastStartedAppPackage, virtualDisplayId, lastStartedAppForceStop);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't relaunch the app if you were able to resize the display successfully, as that causes some apps to restart (particularly PWAs)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to not restart

…plication | dpi value arg added | Avoid relaunching on successful resizes
@TinuraD
Copy link
Author

TinuraD commented Mar 8, 2026

Hey, thanks for reviewing the PR. I’ve checked your comments and updated the required files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants