On Fri, 25 May 2001, Stefan Seefeld wrote:
> > This is because it runs in SYNC mode, i.e. it assumes that there is an
> > automatic flush. There are helpers (mansync) available that will take care
> > for regular flushing in sync mode.
>
> Interesting. Could you write a little summary of those things ? While people
> will certainly make their way through the source code, I think it would help
> a *lot* if there were any design documents, or essays outlining such basic
> ideas. Just write up some text, I'm sure somebody will collect all these and
> make a nice document with it.
A lot of the helper libs that come with LibGGI have very little documentation,
this is true, and have no presence in the web docs. We should work to fix
this.
The SYNC/ASYNC mode feature is documented in the ggiSetFlags/ggiFlush
manpage.
Using the mansync helper would essentially just start a thread that calls
ggiFlush at certain intervals, so it is easy enough to understand that.
It is a helper used a lot in these types of situations, where a target
that does not have a natural ability to operate in sync mode uses it
to emulate sync mode as per that above manpage.
The other method I mentioned to you on IRC wouldn't use a thread but
requires some wizardry. Basically it abuses the mechanism we use to
make sure that a graphics accelerator chip is done drawing before drawing
ourselves with direct MMIO into the framebuffer, so we don't get drawn
over by a running graphics accel command, or worse lock up the chip on
some crummy cards. I'll now explain that, but you might want to offer
both modes for the ipc target, because while the mansync uses a thread
and may be slow enough to be visible to the user, it will probably
have some advantages.
All basic libggi drawing operations are routed through the GGI
API functions contained in libggi/ggi/stubs.c, which calls the
function which is loaded on the respective hook in the opdraw
structure for that visual. When a visual is first initialized, or
when a mode is set (which can change bitdepth), a renderer is
loaded into this opdraw structure. The code that does that is in
the visual.c file in the libggi/default subdirectory belonging to
the loaded renderer.
Most of these renderers have two redundant sets of pixel functions,
the "a" functions contained in pixela.c and the regular functions
contained in pixel.c. All of the other primitives for stuff
that draws more than one pixel are in fact "a" functions. The
detailed reasons for this I won't go into right now because they
are beside the point. Essentially what's important is that if you
set the vis->needidleaccel flag in the ipc target when a new
visual is created, all the functions including the pixel functions
will be "a" functions, and will call the macro PREPARE_FB before
writing/reading data to/from the shm.
This PREPARE_FB macro is in include/ggi/internal/ggi-dl.h
and it does this: if (vis->accelactive) { LIBGGIIdleAccel(vis); }
So you can put anything you want in display-ipc's IdleAccel function,
which is the hook vis->opdisplay->idleaccel, and it will be called
before each and every drawing operation as long as the vis->accelactive
flag is not cleared. If your IdleAccel function does not clear
vis->accelactive, it will always be called. That could be a bit
(actually very) wasteful, but would be a hard guarantee of serialization.
But there are more options, since you are primarily concerned simply
with write access from the visual/read access from Berlin, or whatever
else is serving the shm buffer to the screen, and the shm uses all default
rendering functions which have completed altering the shm memory
before they return, you could play tricks by keeping the
visual structure in an IPC SHM itself, and putting values in
vis->accelactive as needed from either side, using a semaphore
to arbitrate write access to it. That way, Berlin could decide
when the client should start/stop calling IdleAccel and thusly
when the flushes should occur.
(Note to Andy: we could grow the use of idleaccel a bit to
do tile-based dirty region management, if we did something to
push some of the values manipulated by the LIBGGICLIP* macros
onto an internally kept stack, such that they could be accessed
by the idleaccel function.)
--
Brian