Jump to content

is possible to achieve double buffer?


enrico.dallavia

Recommended Posts

Hi,

I'm trying to display a clock, so every 1 second I'm redrawing the screen, but the effect is very poor since I got a bad effect during the redraw of the screen with the new values. Is it possible to have a double buffer or syncronizing the redraw of the screen when the display begins redrawing with first line?

Thanks

I'm using this function to draw


//initialization of some variables at the beginning
swidth = gdispGetWidth();
sheight = gdispGetHeight();
curr_font = gdispScaleFont(font,2,2);
fheight1 = gdispGetFontMetric(curr_font, fontHeight)+2;

//code to call every 1s
GetDateTime(&_date,&_time);
gdispFillStringBox(0, 0, swidth, fheight1, _date, curr_font, Black, White, justifyCenter);
gdispFillStringBox(0, fheight1+5, swidth, fheight1, _time, curr_font, Black, White, justifyCenter);

Link to comment
Share on other sites

You can handle double buffering with uGFX but your hardware needs to support it too. For double buffering you actually need memory to store two entire frames - most microcontroller based systems don't offer this. If you can tell us which microcontroller and which display controller you are using we can give some more information.

As you are only updating a small portion of the display area we would recommend using Pixmaps for this job. A pixmap is like a small virtual display to which you can draw. Then, you can just copy the contents of the pixmap to anywhere on your real display.

The reason this increases performance is because the thing that's by far the slowest is writing pixels to the frame buffer in the display controller and especially if you don't write sequentially (continuous blocks of pixels) but single pixels at different locations instead. Rendering something like a font requires a lot of pixel i/o so this takes a lot of time. It's especially slow because many pixels get written twice (eg. cleared with a background color first, then the text on-top and maybe some third time for anti-aliasing). Doing the same in a pixmap is a lot faster because the pixmap is located in the microcontrollers RAM which is very fast to access. Further factors that will increase performance are the fact that each pixel gets just set once in the display controller (because we know what the end-result must look like) and also the fact that almost all external display controllers allow burst-writes where a continuous block of pixels can be transfered very quickly.

There's an article on the wiki explaining pixmaps including a demo. You want to use the 'virtual display' method: http://wiki.ugfx.org/index.php?title=Pixmaps

You could furthermore increase the performance by not re-writing the date each time as it won't change. If you really want to get everything out of your hardware then you could even split the time string into two piceses: one that contains the hours and minutes and once that only contains the seconds. This would further minimize the area that needs to be rerendered and redrawn.

Hope that makes sense.

~ Tectu

Link to comment
Share on other sites

  • 3 weeks later...

Good morning and happy new year!

Due to other jobs, I had to delay the speed up of screen's refresh until now. I tried to use pixmaps but unfortunately the gdispCreatePixmap fails because chHeapAlloc of chibios seems to return 0. I have external SRAM initialized to handle the graphics (but the size of the ram is quite big so I assume I can use part of it for other things). May can I use this ram to handle the heap that holds the pixmap? The screen resolution is 640x480 and I don't have enough internal sram on stm-f429 to keep the pixmap.

Does anyone know how to initialize heap of chibios from a certain address?

from a past discussion i found


static MemoryHeap ext_heap
chHeapInit(&ext_heap, (void*)0x60000000, 10240);

How ugfx use the external sram? If I put the base address of heap far away from the size of ugfx screen buffer (> 640x480x4 for example) could it work?

thanks in advance!

Link to comment
Share on other sites

with chibios 3 the call is a little different, I've tried


static struct memory_heap ext_heap;
chHeapObjectInit(&ext_heap, (void*)(SRAM_BANK_ADDR+8*1024*1024), 1024*1024);//307200

where SRAM_BANK_ADDR is 0x64000000 and my external memory is 16 MByte wide (pSram), so I've allocated a heap at half the size with 1Mbyte. The call


uint16_t *pData = NULL;
pData = (uint16_t *)chHeapAlloc(&ext_heap,512*1024);

seems to work fine.

Now the question is, how can I tell ugfx to use this kind of heap instead the default one when it try to allocate a pixmap?

I know that Tectu has suggested pixmap if I got only small portion but the most trouble I got is when I change the screen from one page with another one and I have to erase/redraw all the screen. So I would like to use a pixmap large as the main screen to implement a sort of double buffer.

As the question I forgot to answer, I have a stm32-f429 uP with lcos controller A913 made by kopin (which I configure when system start through i2c command) to control a screen made also by kopin.

Thanks

Link to comment
Share on other sites

last update:

even with pixmap (I've modified a little the ugfx source to be able to use a custom heap when request a new pixmap), when i had to redraw completely the screen, I'm suffering with a scroll issue (it seems that the screen is refreshed starting from the first line till the end very slowly), the


gdispBlitArea(0, 0, swidth, sheight, surface);

seems to have no influence at all on the overall performance. Maybe because both frame buffers are on the same external psram?

Plus the system seems to be overloaded, with the pixmap, I got timing problem with other threads (they runs too slow) and so I'm thinking to drop use of a pixmap (at least large as the whole screen).

What I'm doing is


gdispGFillArea(pix,0, 0, swidth, sheight,Black);//on screen change
//update of 2-3 lines of text
gdispGFillStringBox(pix,0, 0, swidth, fheight1, _date, curr_font, Black, White, justifyCenter);
gdispGFillStringBox(pix,0, fheight1+5, swidth, fheight1, _time, curr_font, Black, White, justifyCenter);
//update of some gif if needed
gdispGImageDraw(pix,&myImage, 0, (3*fheight1+5), 100, 100, 0, 0);
gdispBlitArea(0, 0, swidth, sheight, surface);

Once it is completely redrawn, the changes of what is needed are barely acceptable.

Link to comment
Share on other sites

I got an acceptable result, using a pixmap 1 row width and height as my font's height and placing it inside the screen (as Tectu has suggested)

but even when I clear the screen with


gdispFillArea(0, 0, swidth, sheight/2,Black);
gdispFillArea(0, sheight/2, swidth, sheight/2,Black);

I'm suffering the ugly effect of scrolling from top to bottom of the black pixels. I had to split in two the fill area, because I got a better results if I do like that, instead of doing it on 1 call (I wonder why...)

What could be the bottleneck? my cpu is running at 168MHz but the ram unfortunately is not working on burst mode. But beside the complete change of the screen, the image left untouched is clear (if I start a cycle that use write over the flash nor shared on FMC bus, the image became blurred and it is not readable anymore, so I think the speed of the ram is acceptable to refresh the screen)

Link to comment
Share on other sites

If I understand correctly what is going on it sounds like you are having bus contention issues with your framebuffer.

It sounds from the text above that you are using the sym32ltdc driver or the framebuffer driver. Both of these rely on a section of RAM being dual accessed by the cpu and the display refresh controller. The symptoms you describe indicate that all the RAM bandwidth is being used by the refresh controller leaving little available bamdwidth for the cpu.

The hint to thinking this is the problem is the line by line drawing behaviour when simply clearing the screen. This indicates a very slow drawing speed as even simple SPI controllers can draw without this sort of vertical line behaviour.

If so there are only three things you can do to fix the problem:

  • Increase the bandwidth available by changing the RAM and/or the FMSC settings to access it.
  • Reduce the bandwidth of the refresh controller by reducing the screen size or lowering the refresh rate of the screen.
  • Most refresh mechanisms replicate a TV like scan pattern. If so you can put a test for being in the vertical blanking interval before you do any drawing. Whilst this actually slows the cpu access it makes drawing happen between frames so it is less noticeable.

Using pixmap that uses the same overstressed RAM will actually make things worse as you have already seen.

Link to comment
Share on other sites

Hi inmarket,

thanks for the reply!

I've used the example provided from ugfx for stm32F429-discovery, modifying the code to implement the new kopin controller (for the initial setup and the change of backlight level), I also have changed the ram management because I've got a pSram instead of sdram connected through FMC (the FMC is shared between pSram and nor flash implemented by a single chip device S71VS256RD0 made by spansion).

I can't change the ram nor the display resolution, but I can try to reduce the refresh rate (I hope I can also redraw the screen between frames, but I wonder how to do it, do I have to ask the controller or is there something inside ugfx where I can ask the status of the refreshing?)

Thanks

Link to comment
Share on other sites

Try other strategies first before trying to sync drawing to the frame as it slows down the amout of drawing that can happen..

If you do need to implement it then the simplest method is to change the driver drawing routines so that they poll the controller register that indicates when the refresh is in the vertical blanking period before they actually start drawing.

As this is driver specific there is no api support needed in ugfx. It is just part of the driver implementation.

Link to comment
Share on other sites

Ok, thanks.

One question, how is the refresh of the image handled by ugfx? what I mean is, if I want to reduce the refresh rate,do I have to modify some parameters in ugfx or is something that involves also the parameters on the display controller? (or both?)

As an example, once I've drawn a new image, is ugfx with some thread that takes care to redraw the image xxx times per seconds? or it is completely detached from ugfx?

Link to comment
Share on other sites

Nothing in uGFX is being redrawn periodically. When using a plain gdispImage you have to redraw the image yourself when it needs to be redrawn. When you are using the ImageBox widget the image will automatically be redrawn if it needs to, eg. if something covered it and moved or when the visibility changed.

In either way, there are no periodic redraws.

~ Tectu

Link to comment
Share on other sites

The refresh of the display is handled by the display controller and is therefore totally incapsulated within the driver. Altering the display refresh rate is done by changing the initialization sequence for the controller.

There is nothing required in ugfx itself to refresh the display. That is actually the whole point in having a display controller - it handles all the refresh for you once you have initialised it.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...