Closed thinkyhead closed 7 years ago
I think it should be this:
((u8g_pb_t *)((u8g.getU8g())->dev->dev_mem))->p.page_height
At least if you have not applied any rotation. Will this work?
That seems about right. I'll have to pass it on to one of my enthusiastic minions. At the moment I don't have access to a graphical display.
The key thing will be to figure out precisely the starting and ending Y positions of the current page, allowing for total optimization. According to our display guru, the RepRap Discount Smart Graphic Controller (by far the most common) updates in 2 segments, while most (all?) others update in 8 segments.
Apart from picking the correct segment to display, there's some other smart caching we can do. And I've also proposed unrolling the loop in the page drawing function.
The current cols are also there, if I remember correctly: p.y0 and p.y1 y0 is the first and y1 the last row, e.g. 0 and 7 for the first page.
That's handy. (With 0-7 I assume you're referring to a screen that draws in 8 segments.)
Turns out unrolling the byte-sending loop (https://github.com/MarlinFirmware/Marlin/pull/5279/files#diff-fd4e126c88d2a0a2b188632d47501a43R115) is giving bad results. Apparently the overhead of the loop is providing a needed delay for SPI… maybe.
Yes, it would be 0 and 15 if the page height is 15
Hmm can not say much about the unrolling
If the screen is rotated 180°, would y
start with (for example) 56-63, then 48-55, etc. ?
No, even more worse, you will not get the page height any more, because the dev member will point to a different data structure.
the dev member will point to a different data structure
Interesting. So in the case of the rotated screen, is there simply an alternative way to access the .page
, .page_y0
, and .page_y1
data members?
Hmm. I just tried compiling with the VIKI2
display option (plus RAMPS as the board) and this combination has LCD_SCREEN_ROT_180
set by default. It compiled successfully.
I'm using the following to initialize the page
reference and to test the current range:
// The current graphical page being rendered
u8g_page_t &page = ((u8g_pb_t *)((u8g.getU8g())->dev->dev_mem))->p;
// For selective rendering within a Y range
#define PAGE_CONTAINS(ya, yb) \
(page.page_y0 <= (yb) && ((ya) ? page.page_y1 >= (ya) : true))
For example:
if (PAGE_CONTAINS(42 - (TALL_FONT_CORRECTION), 51 - (TALL_FONT_CORRECTION))) {
// Upper box
u8g.drawBox(42, 42 - (TALL_FONT_CORRECTION), 8, 7); // 42-48 (or 41-47)
// Right edge
u8g.drawBox(50, 44 - (TALL_FONT_CORRECTION), 2, 5); // 44-48 (or 43-47)
// Bottom hollow box
u8g.drawFrame(42, 49 - (TALL_FONT_CORRECTION), 10, 4); // 49-52 (or 48-51)
// Corner pixel
u8g.drawPixel(50, 43 - (TALL_FONT_CORRECTION)); // 43 (or 42)
}
One other question! Does the value of ((u8g_pb_t *)((u8g.getU8g())->dev->dev_mem))->p
remain constant once initialized, or can it change during program run?
Yes, it remains constant. Get the pointer to p just before you apply the rotation, then access the members through this new pointer later.
The problem is, that dev gets changed by the rotation.
I think I have it correct (*purely by luck). My implementation defines the page
reference as a global, after the u8g
global object is instantiated (of course), but before our lcd_implementation_init
function is called.
I've posted the new code for testing at MarlinFirmware/Marlin#5288 and expect to get feedback on this optimization soon. I think this will be a huge improvement. It's amazing how easy this turned out to be — and to think I've been avoiding doing this for months because I thought it would be too difficult.
Thanks for the assistance!
Btw... I think there is a function to check whether something is visible or not.
Hmm the function is u8g_IsBBXIntersection from u8g_clip.c
Ok, maybe because i have not worked for a long time on u8glib, after looking at u8g_clip.c i think there is a more simpler way to access the height and the current page boundaries.
u8g.GetU8g()->current_page
contains also some information on the current page. Especially this is independently from the applied rotation. "current_page" has the following members: struct _u8g_box_t { u8g_uint_t x0, y0, x1, y1; };
The height of the page is u8g.GetU8g()->current_page.y1 - u8g.GetU8g()->current_page.y0 + 1
u8g.GetU8g()->current_page.y0 and u8g.GetU8g()->current_page.y1 are actually just copied from page.page_y0 and page.page_y1, but are also corrected if the rotation is applied.
Please excause the confusion. I should have pointed out this solution more earlier. Actually this part of u8g was completly removed when I wrote the successor of u8glib (which is u8g2). The page drawing procedures are now much simpler (and hopefully also faster) in u8g2.
I should have pointed out this solution more earlier.
No problem! After initial testing of my PR I'll try the in-built options and compare performance. I might end up needing to use your supplied functions if the screen rotation breaks my implementation.
The page drawing procedures are now much simpler (and hopefully also faster) in u8g2.
It was suggested to move to u8g2 for speed gains, but so far our testing has shown u8g2 to be much slower. (See https://www.youtube.com/watch?v=fyPpYOoHn0I) But perhaps we are missing some optimizations…?
Oh, that video was done by the Marlin community. Nice. I commented this already on youtube. I wrote U8g2 to get rid of the hardware specific optimization. U8g2 now should work with all current and hopfully all upcoming Arduino boards. This is not true for the old u8glib library which had a lot of AVR (and SAM) specific optimizations and finally it was impossible to keep u8glib compatible to all these Arduino boards around. Mainly, i wanted to have a clear base implementation on which further optimization can be build. Indeed the same optimization can be reintroduced to u8g2. There are some topics which might be of interest for Marlin:
Of course there are still some work required:
Initial testing of #5288 shows that the bounds-checking and string caching strategies are saving about 8000 cycles per update (i.e., 2ms) which is pretty significant! I'm sure optimization is possible. Perhaps even within the old U8glib. I'll be exploring all options as time allows.
U8g2 sounds like it's coming along well. Here's a list of displays we need to support:
DOGLCD (ST7565R)
REPRAPWORLD_GRAPHICAL_LCD (ST7920)
VIKI2 / miniVIKI (C12864)
ELB_FULL_GRAPHIC_CONTROLLER (ST7565 / LM6059_AF)
REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER (ST7920)
MAKRPANEL (C12864)
MINIPANEL (MINI12864)
CARTESIO_UI (DOGM128)
SAV_3DGLCD (SSD1306 / SH1106)
…or to put it another way…
U8GLIB_ST7920_128X64_4X
U8GLIB_ST7920_128X64_RRD
U8GLIB_DOGM128
U8GLIB_LM6059
U8GLIB_NHD_C12864
U8GLIB_SSD1306_128X64
U8GLIB_SH1106_128X64
U8GLIB_MINI12864
We've been wondering, too, whether for certain boards a hardware-based SPI could improve performance even more. Most boards are based on the Mega2560, so that's our main target for this. With that board especially in mind, we just added interrupt-based endstops, and that's showing some performance benefit. The more hardware-based we can go, the better it will be, especially for all those beleaguered deltabots with graphical displays out there.
For U8g2 situation is like this:
SW SPI needs to be analyzed. paralle interface can be improved
U8GLIB_ST7920_128X64_4X --> Ported U8GLIB_ST7920_128X64_RRD --> Not sure what this is U8GLIB_DOGM128 --> Ported U8GLIB_LM6059 --> Controller is ported, but the specific display setup needs to be analysed U8GLIB_NHD_C12864 --> Controller is ported, but the specific display setup needs to be analysed U8GLIB_SSD1306_128X64 --> Ported U8GLIB_SH1106_128X64 --> Ported U8GLIB_MINI12864 --> Controller is ported, but the specific display setup needs to be analysed
Created an issue in u8g2: olikraus/u8g2#94
Ah… The U8GLIB_ST7920_128X64_RRD
type comes from here:
https://github.com/MarlinFirmware/Marlin/blob/RCBugFix/Marlin/ultralcd_st7920_u8glib_rrd.h
Thanks for all the help and attention. I think this question is resolved. We'll talk more as we get on with more optimization.
Hi @olikraus — Sorry if this has been asked and answered elsewhere. I wasn't able to find it.
I simply want to know how to ask u8glib for the current page's bounds during the draw loop so that we can have the screen update code in Marlin draw only the items that are within the page being rendered. This way we can save cycles in the draw loop, which is a major bottleneck, especially on deltabots with graphical displays.
Or, if we can't ask for the current page bounds directly, then at least be able to pre-determine the page size, number of loops, whether it's being drawn bottom-to-top, etc.
Thanks for any guidance you can provide!