-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
display: add display_show #79936
display: add display_show #79936
Conversation
1a8083d
to
5a4c54b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introducing an API change should be accompanied with at least one driver that implements it.
That being said, this would tie the display driver closely to the lvgl way of working, which might require some more discussion.
I don't think there is an upstream driver that requires this right now :/
I kind of disagree with this (that it ties to LVGL, i'm of course open to discussions). I think every display works in frames, and every frame has an end. An alternative API would be |
The problem I have is that regardless of LVGL, the |
46b2de1
to
025da2b
Compare
Implemented it in |
025da2b
to
5dc15d0
Compare
Is the name bothering? Would EDIT: added a couple of options and thoughts in the PR description |
2f35a81
to
642835f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR should be split into different commits:
- Introduce API function
- Implement in dummy driver
- Calling from LVGL
@danieldegrasse @jfischer-no can you weigh in here? |
0937b71
to
1e6150d
Compare
I am not contradicting myself: 1 PR, 3 commits please |
Aaaah. Now it makes sense. Thanks for clarifying. |
Implements the `display_flush` API function, introduced in zephyrproject-rtos#79936. Signed-off-by: Martin Stumpf <[email protected]>
Displays with the capability `SCREEN_INFO_REQUIRES_SHOW` now require `display_show` to be called before the new frame is shown on screen. Signed-off-by: Martin Stumpf <[email protected]>
Adds frame synchronization to every frame. This prevents frame tearing. Signed-off-by: Martin Stumpf <[email protected]>
06cfb9d
to
56465bb
Compare
Agreed, thank you for doing this! Something I was considered regarding the API as we have it now- what Another use case I'm looking at right now that would benefit from this information is the "tearing enable" signal used by some displays. The idea of this signal is that it indicates when the display controller will start reading from its internal graphics ram- so if used correctly, the MCU can time writes to that graphics RAM so that the read pointer of the display controller never overlaps with the write pointer from the MCU, and the tearing effect is avoided. Here's a timing diagram that makes this a bit more clear (from the ST7796S controller datasheet): When using a framebuffer that only covers part of the screen (IE 1/10), we would ideally like to stream all the framebuffers for a given frame after one TE output signal- to do this, the display controller needs a way to know which framebuffer is the last one in the given frame. The driver would wait for the TE signal during the next We could use I know we previously discussed extending the |
@danieldegrasse I specifically don't want to add it to Meaning, you can reuse the partial frame buffer already while That said, this is already possible with the On the other hand, if you say "let's not introduce an API that breaks downstream GUI frameworks", that would annoy me a little, because that's exactly what I was saying a couple of weeks ago, and where other people here said it's fine. |
@danieldegrasse That's kind of exactly what I was talking about here, and what was dismissed. So I though the fact that displays will no longer be backward compatible with existing GUI managers is something everyone understands and accepts. |
@danieldegrasse Also you said this, which I thought includes the |
This would introduce the same problem as was previously discussed, though. All displays that only show their content once the My previous suggestion was to add a That has the drawback, though, that every GUI that doesn't explicitly zero this bit technically leaves it uninitialized, and hence causes undefined behavior. I think it will get zeroed in most cases, but it still is undefined behavior in C I think. |
@danieldegrasse Summary:
Disregarding the asynchronism advantage, I think adding a flag in So your decision: Should I refactor? I can do it, if requested, no problem. That will also make this change a lot smaller. |
Okay, I follow- essentially
I apologize if I or anyone else came off as dismissive here- I think the concern is that we wanted to avoid a hard migration- that is changing the
I think this is undefined behavior, yeah. I agree though that modifying the To be clear, I'm not opposed to the current state of the PR- I just wanted to engage because I realized that displays using the tearing enable signal will also benefit from the GUI framework communicating the "last frame" to them in some way- the reason I leaned towards the display buffer descriptor is that the MIPI DBI layer is used for SPI based displays- if we extended the display buffer descriptor, we could pass the "last frame" flag to the MIPI DBI controller (where it would actually be used) very easily |
@danieldegrasse To be honest, the more I think about it the less this seems like an actual advantage. You can already use double buffering and the additional present thread for that; so there is already some kind of asynchronism. I'm kind of leaning towards a refactor. Although at this point I might even create a new PR as it will be completely different. |
I personally am in favor of using a flag in the To summarize- we have the following use cases:
The API changes we'd add to enable this:
GUI frameworks can use this feature by setting the "frame_incomplete" flag for all writes except the final write in a display frame. This way, the controller is effectively aware which write is the final one, and can take appropriate action. The only open issue here to solve is how to deal with GUI frameworks that have not been updated and do not initialize the "frame_incomplete" flag- the flag would be an undefined value if the display buffer descriptor was declared on the stack. @Finomnis does this seem like a good summary? |
@danieldegrasse Yes, I think so.
In the case they do struct display_buffer_descriptor desc = {
.member = foo,
.member2 = foo2,
}; then it should work, I think, I think missing members do get zeroed. (Which is how we use most of our APIs; if drivers don't implement an API function we assume it is a null pointer) However, if they do struct display_buffer_descriptor desc;
desc.member = foo;
desc.member2 = foo2; ... then I think it's undefined behavior. Which is why I strongly favor the first version everywhere I can. |
One option here is to add a check to all display drivers that throws an error if the "bufferable" flag is set- as display drivers enable support for this, we would remove this check. Not sure how I feel about that- it would quickly "catch" GUI managers that were not initializing the flag, but once we add support for the "bufferable" flag in a display driver then it would be impossible to tell the difference between a GUI framework that recognized the flag and was setting it, and one that was leaving it uninitialized. |
Great. Again, I apologize for the churn here- I should have considered the tearing enable case a bit more during my initial review. @pdgendt, @faxe1008, @JarmouniA and @jfischer-no do you (or anyone else) have thoughts on this change? Edit: comment where the proposed change is described: #79936 (comment) |
Yeah, I believe it is. I'll note that structures have been extended like this in the past- see an example here #77502 |
@danieldegrasse be aware that you want to wait before the first frame of the image, not after the last, in your TE case. Otherwise the GUI needs to render the frame after the TE and the data will come later than desired. |
Sure, thanks for the clarification- I'm aware that display drivers would still need some kind of flag to indicate "the last framebuffer we received wasn't bufferable, so this next framebuffer should be sent at the TE interval" |
This is very confusing to read :D maybe we should not call it Maybe |
Sure, I like |
@danieldegrasse The only thing I dislike about this solution is that |
@danieldegrasse For the rework, could you take a look at
|
@danieldegrasse Rework at #81250. |
I'm less familiar with e-ink displays, but I would guess that tearing is much more obvious there due to the slower refresh rate. It does seem like the change was intended to prevent flicker: zephyrproject-rtos/lvgl@0db5fca
I'll be honest, this one stumps me. It has been present in the LVGL port since the initial port to Zephyr: cbfcae7#diff-aff42d60cfd55aebd4f8e00f4415a92a6a40d300a0b673cd381d4a3ba6ed4377R28 The only driver that was using it was the SSD1673: 49ffca4#diff-9d44933c67e307bb75712984b2aa52ed1b07a4feb1edd6bd1674c0fe6cc6c1b0R339. No drivers in tree currently use it:
I suspect that the double buffer flag might have been related to this code that exists in the current version of the SSD1673 driver: zephyr/drivers/display/ssd16xx.c Line 484 in c50777a
IMO, both of these should be removed (thank you for catching them), but we don't have to do it as part of this PR- we can log an issue against these and remove them in the future |
Superseded by #81250. |
Fixes #79798.
Indicates to the display that all previous writes should be flushed to the display.
This adds support for display drivers that internally contain a double-buffering or latching mechanism.
Currently the only way to implement those displays is to present all
write
s to the user immediately, which could cause tearing artifacts for multi-write renders. (it's quite common for UI managers to render to partial framebuffers in low-memory situations. LVGL, for example, recommends 1/10th of the screen size)Open questions:
display_show
(current PR code)display_present
(could be confused with "display is present")display_flush
(sounds like it's optional)display_finalize_frame
(might be a little too verbose)display_flip
(probably not because could be confused with x or y pixel order setting, like, 'flipping' the image)display_pageflip
(might be too usecase specific)