[haiku-development] Re: app_server compositing

  • From: Joseph Groover <looncraz@xxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Thu, 22 Mar 2012 19:18:59 -0500

On 3/22/2012 16:55, Axel Dörfler wrote:
On 22.03.2012 01:36, Joseph Groover wrote:

You cannot use realloc() - but you can just use the existing backend for bitmaps. IIRC they are already aligned to some size, so you won't have to switch buffers too often when a window is resized. And even if, resizing is not happening that often.

You have to use a memory backend where it is save for the client to mess with everything, ie. the app_server must remain running even if all the client does is to fill all memory it gets with 'bee4'.


At first I didn't get why I couldn't modify MallocBuffer into a ResizingBuffer, allocate the memory with malloc(BytesPerRow() * fHeight) and realloc on resize.

So much so that I already created it (completely untested)...

I did realize, of course, that the bitmap data would be worthless after realloc, but the same is true of swapping to a new buffer while resizing - or so I told myself ;-) Until I realized that the client determines what gets redrawn during / after a resize :") I copy out the old buffer to a new one, and redirect the Window's Painter to the new buffer, mark the old buffer for deletion and only delete it once the new buffer is Painted into the back buffer (so that the old buffer is around in case the data is needed before the resize draw completes on the client side).

Or I am just totally missing something...

As such, I'd think it prudent to expose my current plans for the CompositeEngine to scrutiny:

I've been working on morphing CAFE::RenderEngine into CompositeEngine (the header anyway.. the actual code is by no means compatible - RenderEngine is part of a managed framework with ThreadGroups and timing mechanisms and the like...) so I have a nice starting point...

CompositeEngine will have an explicit constructor, a global gCompositeEngine pointer, and will instantiate itself (no reliance on order). It provides a listener interface and the common stuff of course.. plus:

One thread/core for rendering into the back-buffer (invalidating modified areas and painting the updates into the back-buffer). One master control thread (task assigner, tells which threads to handle which areas, coordinates state). One back-to-front copy thread, looping on a schedule based on performance_mode:
        STOP_PERFORMANCE_MODE         = 0,    // screen off, low power mode
SLOW_PERFORMANCE_MODE = 5, // <= 5fps, target 5 fps - clock / caret MILD_PERFORMANCE_MODE = 15, // mild motion in multiple locations HIGH_PERFORMANCE_MODE = 30, // moderate motion, video, etc... FULL_PERFORMANCE_MODE = 60, // high motion (window dragging/resizing) SYNC_PERFORMANCE_MODE = 120, // update at refresh rate - up to 120hz WILD_PERFORMANCE_MODE = 1000 // update as fast as possible - up to 1000fps // must be set as an override

As you can see the modes are target frame rates, most of the time updates will only need to happen a few times a second. The thread will schedule an update check based on the performance mode and only copy to front when an update is required (naturally).

Performance modes can be set by request (from ServerWindow based on Invalidate() rate) or in response to certain scenarios (when a resize or move begins, we enter FULL_PERFORMANCE_MODE or SYNC_PERFORMANCE_MODE and drop down in stages towards SLOW_PERFORMANCE_MODE, reducing the dirty region check rate - we escalate upwards quickly, down "slowly" because the update check itself is a very minimal test, but there MAY be a lock contention issue if we check too often which could cause schedule violations).

The purpose of all that is to help have updates batched. The master control thread orchestrates the back-buffer update (via the (hopefully)multiple threads) right after the front buffer is updated and the back-to-front copy thread must wait until the master control threads releases its hold on the back-buffer. The clients, naturally, update at-will as they do now. A client must be complete with their drawing in order for an update to occur for them. To give the best possible chance of that being the case the back-render threads will skip over updates including locked windows, adding them to the end of the update queue the control thread is servicing permitting more tries to gain a lock on the buffer to copy it into the back-buffer before the next scheduled back-to-front copy. The control thread will stop servicing updates as quickly as possible once the back-to-front copy thread has requested read access to the back-buffer, it will begin servicing them again after the back-to-front copy has completed.

Once that is all working, I will investigate the possible need to give certain updates priority (since it will just be a matter of sorting the update queue. I will also look into merging updates and providing a double-buffering facility to the full window (not an individual BView as in Dano)... but that is a low priority.

Please let me know if I'm messing up somewhere in the theory ;-)

I'm off to give each Window a buffer to pass to their Painter... not sure of the state of test_app_server... if you have any hints, PLEASE let me know ;-) Otherwise I'll be running two instances of VMware - one on each monitor, one for testing, one for developing... both running Haiku of course - will have to try on real hardware later when I build a few test machines.

--The loon

Other related posts: