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

Blurry 1px-wide borders on Windows #869

Open
eugenesvk opened this issue Feb 15, 2025 · 10 comments
Open

Blurry 1px-wide borders on Windows #869

eugenesvk opened this issue Feb 15, 2025 · 10 comments

Comments

@eugenesvk
Copy link
Contributor

eugenesvk commented Feb 15, 2025

Was trying to replicate a Windows button style, and set the border to 1px width instead of 2 (and changed the color), but the button has a "fuzzy" border, see this scaled up image

  • top is default windows button from a Wordpad, it has a crisp border exactly 1-px width both vertically and horizontally

  • bottom is a Masonry button widget, which is not universally 1px (and also the color is washed out, so it's blended with the button color?)

Image

Is there a way to preserve the exact color and border size?

After some experiments: there seems to be 2 issues here

  • Border is incorrectly drawn "halfway", on top of the inner rect, not adjacent to it, so only half of the border width gets show, the other half is obscured by the background. And stroke widthborder width
  • Border is drawn before background, so they get "blended" at the edge?

For example, here green border is drawn with a corrected positioning - it's drawn adjacent to the inner rect, not on top of it (it's drawn on top of the

  • rect - ½stroke_width, but background is filling the
  • rect - 1stroke_width)

, so it's not blended (red one is)
Image

But if red border is drawn on top of the background, then even its incorrect positioning doesn't matter - you still get crisp border

Image

(these are buttons with stroke width 1/dpi_scaling_factor so you get 1px)

@eugenesvk
Copy link
Contributor Author

Interestingly enough, the color wash out is inconsistent:

  • left: 1px border stroke new
  • right: 1px border stroke with dashes of 0 offset and 1 0` pattern (so, I guess, would be identical to a solid line)

On the right top border is proper non-washed-out color, but then its other borders are even worse than on the left as they have a "checkered" dashed pattern (and they are also not 1px, just like the left one)
Image

@burrbull
Copy link

There were render improvements in last egui release. Maybe this is helpful.
emilk/egui#5669

@DJMcNab
Copy link
Member

DJMcNab commented Feb 17, 2025

There are a couple of relevant things here:

  1. I suspect that you're requesting a stroke which can only reasonably be drawn as that. See #gpu > Pixel-perfect stroked squares
  2. Our current system for scaling won't support single-pixel drawn lines, as you cannot currently know the scaling factor. I'd like for us to develop a coherent model here, but we haven't yet.

@eugenesvk
Copy link
Contributor Author

As per update notes, playing with positioning and drawing a border adjacent instead of on top helps with pixel-precise cases.

For the other issue - is it possible to selectively disable "blending" and let the shape that takes the bigger part of a given pixel win completely instead of having
a higher % in the blend?

Otherwise will see if playing with more precise positioning could help

@DJMcNab
Copy link
Member

DJMcNab commented Feb 17, 2025

For the other issue - is it possible to selectively disable "blending" and let the shape that takes the bigger part of a given pixel win completely instead of having
a higher % in the blend?

Not really. The imaging model of Vello will draw what you request it to. The way to fix this kind of issue is to request exactly what you want to be rendered. The issue with the fill/contents looks like the shape's edges are partway inside the stroke, still.

I believe that we have answered the question being asked, so I'm going to close this issue. The right forum for this kind of question in future is our Zulip, which means that it will likely be seen by more people.

@eugenesvk
Copy link
Contributor Author

As far as I understand it, the answer is "it's impossible" since there is no dpi data, so while the questionis answered, the issue remains open

And while I've addressed it partially in the linked PR, the other issue remains - that of positioning imposed on a widget by the higher ups, so you perfectly internally-per-pixel-aligned line can still be blurry becase your widget's 0,0 isn't pixel-aligned

So how would a widget get information on which screen pixel coordinates (preferably physical, but with the now available scale factor could also be logical)?

@DJMcNab
Copy link
Member

DJMcNab commented Feb 18, 2025

And while I've addressed it partially in the linked PR, the other issue remains - that of positioning imposed on a widget by the higher ups, so you perfectly internally-per-pixel-aligned line can still be blurry becase your widget's 0,0 isn't pixel-aligned

I entirely missed that this was an issue you were raising, and I cannot now find where in this thread before that comment you said so. This is part of what I meant when I said "I'd like for us to develop a coherent model here, but we haven't yet". We have had some previous discussion here https://xi.zulipchat.com/#narrow/channel/147932-chatter/topic/Pixel.20snapping.20behaviors.
This effectively needs coöperation from the layout containers to always lay things out to a pixel position. My current understanding is that this is desirable, but no-one has done the work. Of note, the decision was made (not by me) to reduce the priority of this kind of pixel precise rendering - #753 is largely incompatible with that, for example.

So how would a widget get information on which screen pixel coordinates (preferably physical, but with the now available scale factor could also be logical)?

As I understand it, you currently cannot. Widgets are intentionally not told their position on the screen. This allows caching the painting, which is both an important optimisation, and will also be necessary for system compositor integration (but note that integer-snapped rendering is also necessary there).

I don't have any perfect answers here.

As far as I understand it, the answer is "it's impossible" since there is no dpi data, so while the question is answered, the issue remains open

Having a tracking issue for the different aspects of getting physical pixel aware would be welcome. However, this issue specifically is formatted as an exploratory grab-bag of questions, which isn't useful for us to actually track any concrete work.

@PoignardAzur PoignardAzur reopened this Feb 18, 2025
@PoignardAzur
Copy link
Contributor

I think we can leave that issue open. It's definitely something we intend to address, we're just not sure how.

Ideally, I would like us to get scaling-independent layout. That is, you're allowed to paint rectangles that are exactly one physical pixel thick, but you're not allowed to have a button that's N logical pixels + 2 physical pixels tall, because the layout system doesn't know how large a physical pixel is.

How that works out in practice is that maybe the layout system says "Rect1 starts at y = 0 and ends at y = 10.5, and Rect2 starts at y = 10.5 and ends at y = 20", and though both rectangles are unaware of each other, they both agree that 10.5 rounds to 10 and so you still get a seamless picture.

That could mean that widgets would need to be aware of their coordinates, which as Daniel points out, is incompatible with our current caching model; so this needs more design work.

@PoignardAzur
Copy link
Contributor

Having a tracking issue for the different aspects of getting physical pixel aware would be welcome. However, this issue specifically is formatted as an exploratory grab-bag of questions, which isn't useful for us to actually track any concrete work.

I missed that part of Daniel's comment.

I'm okay with grab-bag issues, but maybe we should make a policy of not having them.

@DJMcNab
Copy link
Member

DJMcNab commented Feb 20, 2025

How that works out in practice is that maybe the layout system says "Rect1 starts at y = 0 and ends at y = 10.5, and Rect2 starts at y = 10.5 and ends at y = 20", and though both rectangles are unaware of each other, they both agree that 10.5 rounds to 10 and so you still get a seamless picture.

Hmm, that seems like a nice solution to get pixel-precise borders. Can we make that work to make sure that a widget always maintains the same height in pixels, so as to avoid shimmering?

As I said earlier, this is much better placed to be a discussion on Zulip. I'm not going to close this again, but I would still strongly advocate doing so. Concretely, this issue is tracking "please answer the questions I have", which I believe that we have now done. As I said, an issue which tracks "Physical pixel aware layout/positioning" as a concrete goal would be welcome. If you want to edit this issue to do so, then that would also be reasonable, although I would lean towards making that a new issue would be better. This halfway position is pretty far from ideal

github-merge-queue bot pushed a commit that referenced this issue Feb 20, 2025
so that it's available to widgets that can fix blurry lines due to bad
overlapping positioning of its internal elements

partially addresses #869

---------

Co-authored-by: Daniel McNab <[email protected]>
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

No branches or pull requests

4 participants