[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: