Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add background image #2419

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Add background image #2419

wants to merge 13 commits into from

Conversation

mysty0
Copy link

@mysty0 mysty0 commented Mar 14, 2024

This relates to #342

  • Add background image that can be specified in config with vim.g.neovide_background_image = "E:\\downloads\\102075572_p0.jpg"
  • Slightly bump skia version to add support for new image loading API
  • Add background_transparancy config option to control background color transparancy independently from window. Therefore background image could be still visible without adding transparancy to the whole window

It will have the same blur and opacity settings as single color background and look like this:
image

What kind of change does this PR introduce?

  • Feature

Did this PR introduce a breaking change?

A breaking change includes anything that breaks backwards compatibility either at compile or run time.

  • No

Copy link
Contributor

@MultisampledNight MultisampledNight 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!

src/renderer/mod.rs Outdated Show resolved Hide resolved
@@ -16,6 +17,7 @@ pub struct WindowSettings {
pub touch_deadzone: f32,
pub touch_drag_timeout: f32,
pub background_color: String,
pub background_image: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be in src/renderer/mod.rs in RendererSettings instead? (alongside with background_color)

Copy link
Author

Choose a reason for hiding this comment

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

I think it makes more sesnse to keep it in window settings as it modifies the window property rather than how the window is being rendered

@@ -148,12 +157,14 @@ impl Renderer {
self.cursor_renderer.prepare_frame()
}

pub fn draw_frame(&mut self, root_canvas: &Canvas, dt: f32) {
pub fn draw_frame(&mut self, root_canvas: &Canvas, dt: f32, width: f32, height: f32) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be able to use Canvas::base_layer_size instead of passing width and height by parameter?

(fwiw you can look up the things available in skia_safe on skia.org, e.g. [SkCanvas::getBaseLayerSize] corresponds to Canvas::base_layer_size. The docs for skia_safe are available directly by running cargo doc --open locally)

Copy link
Author

Choose a reason for hiding this comment

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

With the latest renderer changes using base_layer_size makes things much more cleaner however it doesn't cover full screen. There is some space left in the bottom that isn't covered by the image.
image
I don't think it's very critical but it would be nice if image could cover the whole screen. Do you know how this can be achived?

src/renderer/rendered_window.rs Outdated Show resolved Hide resolved
@fredizzimo fredizzimo linked an issue Mar 25, 2024 that may be closed by this pull request
@pidgeon777
Copy link

pidgeon777 commented May 12, 2024

Very cool, I was thinking of the same functionality just yesterday.

I've a question though, what will happen if Neovide and background images sizes are different? For example:

  • Background image will be stretched
  • Background image will be padded

etc.

I wonder that If I make Neovide fullscreen and pass a background image sharing the same screen resolution, no image stretches / paddings will occur? That would be the "ideal" case.

@mysty0
Copy link
Author

mysty0 commented May 12, 2024

Thank you!

Thank you for the review @MultisampledNight! Sorry for the wait I just noticed that there is some activity on this pr. I merged latest changes and implimented your suggestions.

@mysty0
Copy link
Author

mysty0 commented May 12, 2024

Very cool, I was thinking of the same functionality just yesterday.

I've a question though, what will happen if Neovide and background images sizes are different? For example:

  • Background image will be stretched
  • Background image will be padded

etc.

Before it was stretching however in latest commit I made it to keep aspect ratio, fill the screen and center the image and crop the longest side in case if it overflows as suggested here

I wonder that If I make Neovide fullscreen and pass a background image sharing the same screen resolution, no image stretches / paddings will occur? That would be the "ideal" case.

Yes it would fill the screen without any stretching and padding

@MultisampledNight
Copy link
Contributor

(fwiw I am not familiar enough with the neovide codebase anymore to qualitatively review this PR anymore, sorry)

src/window/renderer.rs Outdated Show resolved Hide resolved
@pidgeon777
Copy link

Is there a way to test the artifact without building from sources?

@fredizzimo
Copy link
Member

@pidgeon777, I started the CI run, the artifacts should be there once it finishes

Copy link

github-actions bot commented May 13, 2024

Test Results

  6 files  ±0    6 suites  ±0   21s ⏱️ +3s
110 tests ±0  110 ✅ ±0  0 💤 ±0  0 ❌ ±0 
644 runs  ±0  644 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit b6bfaa9. ± Comparison against base commit 35ea46a.

♻️ This comment has been updated with latest results.

@fredizzimo
Copy link
Member

fredizzimo commented May 13, 2024

@pidgeon777, the artifacts are a bit hard to find currently, we need to improve or at least document it, but you should be able to find them here
image

@pidgeon777
Copy link

pidgeon777 commented May 13, 2024

I just did a quick test with these settings:

  vim.g.neovide_transparency = 0.8
  -- vim.g.neovide_transparency = 1.0
  vim.g.neovide_background_image = "C:\\Users\\<NAME>\\Downloads\\pexels-photo-1483054.jpeg"

Background image is now shown but it makes Neovide extremely laggy, even with simple cursor movements in normal mode.

Image resolution is 8192 x 5063, 72 DPI, 24 bit

@pidgeon777
Copy link

When utilizing an image with a resolution of 1920x1080 as a background, the performance and smoothness of Neovide appear to remain unaffected (but more tests should be done).

I would like to inquire about the configuration settings of Neovide, specifically pertaining to the transparency of the background image. Could you provide guidance on how to adjust these settings so that:

  • When the transparency is set to 0, the background image is entirely obscured, and only the Neovim background color is visible.

Example:

image

  • Conversely, when the transparency is set to 1, the background image is fully displayed without any overlay of the Neovim background color:

image

To achieve the above image, I simply moved the Neovide window on the top of a Chrome background image.

But it would be great to obtain the second setup by setting the path to the background image in Neovide, and toggle between the amount of image and the neovide background, with the transparency option.

@pidgeon777
Copy link

The aforementioned test was conducted using the artifact linked below. This version of the software did not yet include the background image feature. However, it did allow for the adjustment of the Neovide background transparency:

Artifact Link

@mysty0
Copy link
Author

mysty0 commented May 13, 2024

But it would be great to obtain the second setup by setting the path to the background image in Neovide, and toggle between the amount of image and the neovide background, with the transparency option.

You can do it with neovide_background_transparency option, it controls how transparent is build-in neovide background color. neovide_transparency controls how transparent is the whole window.

This is also probably why you can't see the background image. Try setting neovide_background_transparency to lower values like 0.5 to have a mix between a neovide's background color and image.

Background image is now shown but it makes Neovide extremely laggy, even with simple cursor movements in normal mode.

I tried with 8k image but unfortunatly I wasn't able to reproduce it. Could you send your image that you are testing?

@pidgeon777
Copy link

pidgeon777 commented May 13, 2024

You're right, I didn't know about this new neovide_background_transparency option.

Below the background image causing the lag:

pexels-photo-1483054

UPDATE: I also zipped it:

pexels-photo-1483054.zip

@pidgeon777
Copy link

I have conducted some tests using the artifacts available at Neovide Actions Run. I collected some observations regarding it:

  1. Background Image Stretching: The background image appears to stretch when the Neovide window is resized.

  2. Background Image Replication: The background image is replicated for each window (including Trouble, window split, etc.). This could lead to a cluttered appearance, particularly when multiple windows are open.

Given these observations, I have a couple of suggestions for potential improvements:

For Issue 1 (Background Image Stretching):

  • Investigate the possibility of maintaining the aspect ratio of the background image during window resizing. This could prevent distortion and ensure the image remains visually appealing regardless of window size. For example, by adding some padding. It would be nice to leave this strech feature enabled by specifying a configuration option.

For Issue 2 (Background Image Replication):

  • Consider allowing users to assign a unique background image to each window. This could enhance customization and allow users to differentiate between windows more easily. It seems to be something technically doable, given that the background image is currently replicated for each window.

  • Alternatively, consider assigning a single background image to the Neovide background only, regardless of the number of open splits. This would prevent the replication of the background image for each window split, which currently occurs.

@fredizzimo
Copy link
Member

  • Consider allowing users to assign a unique background image to each window. This could enhance customization and allow users to differentiate between windows more easily. It seems to be something technically doable, given that the background image is currently replicated for each window.

I think this is quite hard currently. We don't have any support for window specific options in Neovide. And the Neovim gui protocol does not really support it easily either, which means that if we use the Neovim api to do it, things could get out of sync.

It's something that we want to add support for in the future though, for example, we should be able to control the shadows, and blur effects per window.

@pidgeon777
Copy link

Understand, so for now a simple "hack" to achieve the same effect could be just set vim.g.neovide_background_transparency to a value and put a static background under the Neovide window

@mysty0
Copy link
Author

mysty0 commented May 13, 2024

I fixed both stretching and replication bugs

Below the background image causing the lag:

I was able to reproduce it with this image, however I don't know how to fix it. I narrowed the problem down to this call

canvas.draw_image_rect(
    image,
    Some((&src_rect, SrcRectConstraint::Strict)),
    window_rect,
    paint,
);

which draws a background image and it takes 200ms on my pc with the image. I can reduce it to 40ms by unpacking the image into bitmap on loading and using SrcRectConstraint::Fast but it involves unsafe calls and still feels laggy. It probably possible to cache a layer but it will still lag when resizing a window. So I am not sure how else this can be optimized. If anyone have some ideas I am happy to try implimenting them.

@fredizzimo
Copy link
Member

@mysty0, are you able to test if a smaller image is fast, I mean the cost should be way less than a ms?

In that case, the solution is probably to either scale the image first when loading, or draw in sections loading different parts of the image.

@mysty0
Copy link
Author

mysty0 commented May 13, 2024

@mysty0, are you able to test if a smaller image is fast, I mean the cost should be way less than a ms?

In that case, the solution is probably to either scale the image first when loading, or draw in sections loading different parts of the image.

Yep, for 1080p image I get around 1.5us for background rendering

@pidgeon777
Copy link

Does it also support .webp images?

@mysty0
Copy link
Author

mysty0 commented May 15, 2024

Does it also support .webp images?

No, I don't think it supports them

@mysty0
Copy link
Author

mysty0 commented May 15, 2024

I was able to optimize it to render for less than 1ms for 10k image while text editing. However it still can go up to 15ms when resizing windows but it doesn't really feel that laggy. To further optimize I can probably prescale image to maximum monitor size but it would involve a lot of platform specific code and I don't think it really worth it.

@pidgeon777
Copy link

I have a question regarding the changes made in the previous commit. Previously, we had the capability to load high-resolution images, but this process was time-consuming and resulted in significant lag in Neovide.

With the new implementation, my understanding is that the image loading time has been reduced. However, I'm curious about the impact on Neovide's performance. Will it still be influenced by the size of the image, albeit to a lesser extent than before?

To put it more succinctly, if we load a high-resolution image as a background and do not resize the Neovide window, will the overall performance, such as cursor movement and scrolling, remain the same as if no background image was loaded at all? Or rather, would loading a 10K image as a background result in the same performance as loading a 2K image?

@mysty0
Copy link
Author

mysty0 commented May 16, 2024

Will it still be influenced by the size of the image, albeit to a lesser extent than before?

Yes, but only when resizing windows

will the overall performance, such as cursor movement and scrolling, remain the same as if no background image was loaded at all?

Yes, it would be similar

Or rather, would loading a 10K image as a background result in the same performance as loading a 2K image?

Yes, performace would be very simular unless resizing

So basicaly previous bottlenect was in image rescaling. Before I would scale a 10k image to much smaller resolution of a window each frame which take significan amount of time. However with the latest changes I cache the resized image and until the window size doesn't change it will just render cached image without any significan performace impact.

Copy link
Member

@fredizzimo fredizzimo left a comment

Choose a reason for hiding this comment

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

This still needs documentation, including instructions that tells that the image is only shown when g_neovide_transparency is less than 1.0

@@ -172,6 +176,35 @@ impl WinitWindowWrapper {
wrapper
}

fn load_image(image: &str) -> Option<Image> {
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to add some logging here with the filename it tries to load

if image.is_empty() {
None
} else {
let skia_data = Data::from_filename(std::path::Path::new(image))?;
Copy link
Member

Choose a reason for hiding this comment

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

And after this line that it succeeded to load the file

);
if !success {
return None;
}
Copy link
Member

Choose a reason for hiding this comment

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

And the final success and failure status

if image.is_empty() {
None
} else {
let skia_data = Data::from_filename(std::path::Path::new(image))?;
Copy link
Member

Choose a reason for hiding this comment

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

I think we might want to use https://docs.rs/shellexpand/latest/shellexpand/fn.tilde_with_context.html here so that you can easily refer to the home directory

// background,
// &pixel_region,
// screen_rect,
// );
Copy link
Member

Choose a reason for hiding this comment

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

There's an extra comment here.

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.

Add support for background images
5 participants