LibGAlloc Libraries and ulilities
=================================

Graphics feature allocation extension for GGI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 7 libgalloc

Description
-----------


`LibGAlloc` defines a standardized system which can be used to check
for the presence of graphics target features, and to resolve resource
conflicts between the features.


It provides both a simple, ad-hoc interface and a more powerful, but
more complex, interface to its internals.  Its main reason for
existing is to become the bridge between the offshoot KGI project's
graphics drivers, LibGGI, and LibGGI extensions.


For example, LibGAlloc can tell an application or an extension library
how to set the main video mode in such a way that a Z-buffer is
available, if the target supports it.  It can also reserve the
graphics RAM needed for that Z-buffer, so that if another extension
wishes to know how much RAM is available for 3D textures, it does not
have to interface directly to the extension that owns the Z-buffer to
find out how much it ate.


LibGAlloc consists of a main library (`libgalloc.so`) and a multitude
of dynamic drivers. At runtime, the library loads the necessary
drivers taking hints from the graphics device if necessary.


LibGAlloc has been designed after years of thought and discussion on
the shortfalls of modern graphics libraries, and of LibGGI itself.  We
believe LibGAlloc will open the door to LibGGI finally becoming
everything that it was originally intended to be.



Introduction to LibGAlloc usage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 7 libgalloc-usage

Synopsis
--------

There are a few ways to use LibGAlloc; This chapter describes how to use
the simplest forms of the API.  LibGAlloc is a LibGGI extension, so in
order to use it from an application you must `ggiGAInit()` the
extension and `ggiGAAttach()` it to at least one open LibGGI
visual.  If you are writing an extension that uses LibGAlloc, you should
make sure that LibGAlloc is initialized and attached to the visual when
your extension is attached.  That way, the user does not have to attach
LibGAlloc themselves. Of course, you should also clean up by using
`ggiGADetach()` and `ggiGAExit()` where appropriate.  Internal LibGAlloc
counters should take care of multiple calls to init/attach so it is safe
not to worry about that.


Overview of typical LibGAlloc usage
-----------------------------------

There are two ways to go about using LibGAlloc.  The recommended way
is to try to set up all the requests for resources before attempting
to activate the resources.  The other way is to activate resources as
you need them -- this is not recommended because LibGAlloc may not be
able to organize the resources efficiently in this mode of operation,
however it is supported to allow less sophisticated applications to be
written in an intuitive way.  There are occasions where it is
necessary to allocate and deallocate resources after other resources
have already been set up, so support for this second mode of operation
is not an afterthought and can be expected to be coded with as high a
quality as the recommended mode; it is an essential part of LibGAlloc
even if it is not recommended.


Before we get into the differences in the way LibGAlloc application code 
is written versus regular LibGGI application code, we will look at the 
the way LibGGI applications set a video mode and the way LibGAlloc 
applications do, so that we are familiar with the functions.  A normal 
LibGGI Application would set a mode like this (we have removed the error 
checking to keep the examples simple.)  You should refer to the LibGGI 
documentation if you are new to LibGGI, to understand the below listing.

::

        ggi_visual_t vis;
	ggi_mode mode;

        ggiInit();                 /* Start up LibGGI */
        vis = ggiOpen(NULL);       /* Open the default display */

	ggiCheckSimpleMode(vis, 640, 480, 640, 480, &mode);
	ggiSetMode(vis, &mode);

        /* We can now draw on the visual. */


The same code using LibGAlloc's recommended interface would look like
this::

        ggi_visual_t vis;
	ggiGA_resource_list reqlist;
	ggiGA_resource_handle mode;

        ggiInit();
        vis = ggiOpen(NULL);
	ggiGAAttach(vis, NULL);

	ggiGAAddSimpleMode(vis, &reqlist, 640, 480, 640, 480, &mode);
	ggiGACheck(vis, reqlist, NULL);
	ggiGASet(vis, reqlist, NULL);

        /* We can now draw on the visual. */


In the above listing, we see that we have an additional step.  The
function `ggiGAAddSimpleMode` is a lot like
`ggiSetSimpleMode`, except that it puts a request for a video
mode into a request list, rather than checking/setting it right away.  There 
are also ggiGAAdd* functions that look like the other ggiSet* functions.  
The variable `reqlist` is what is then checked and set.
It is sort of the same thing as the variable `mode` in the first
listing, but it is much more powerful.  To see why, we need to bring
another extension into the picture.


An extension that uses LibGAlloc will provide one or more *Add* functions
of its own.  Suppose we have an extension that renders a dancing gerbil
of any size on the screen, LibGerbil, which was written to take advantage
of video cards with hardware accelerated dancing gerbils, and emulate them
for people who are unfortunate enough to own a video card that does not.  
In addition to the API functions which move and position the dancing
gerbil, LibGerbil would also provide a function GerbilAdd, which would add
a request for a dancing gerbil to the reqlist variable, (If the gerbil was
emulated, it would just pretend to add it.)  It would look like this::

        ggi_visual_t vis;
	ggiGA_resource_list reqlist;
	ggiGA_resource_handle gerbilres;
	gerbil_t gerry;

        ggiInit();
        vis = ggiOpen(NULL);
	GerbilAttach(vis, NULL); /* This attaches LibGAlloc automatically */

	ggiGAAddSimpleMode(vis, &reqlist, 640, 480, 640, GGI_AUTO, NULL);
	GerbilAdd(&reqlist, &gerbilres);

	ggiGACheck(vis, reqlist, NULL);
	ggiGASet(vis, reqlist, NULL);

	gerry = GerbilActivate(reqlist, gerbilres);
	GerbilSize(gerry, 50, 100);
	GerbilPosition(gerry, 100, 100);
	GerbilShow(gerry);
	GerbilBreakDance(gerry);
	sleep(200);
	GerbilBoogie(gerry);


Now, let us show you how that would look in the not-so-recommended
*ad hoc* interface.  The Gerbil extension would supply a function
GerbilCreate.  This function would be called to instantly create a
dancing gerbil after the video mode had already been set::


        ggi_visual_t vis;
	ggi_mode mode;
	gerbil_t gerry;
        ggiGA_request_list reqlist = NULL;

        ggiInit();
        vis = ggiOpen(NULL);
	GerbilAttach(vis, reqlist); /* will attach LibGAlloc if not attached */
	ggiCheckSimpleMode(vis, 640, 480, 640, GGI_AUTO, &mode);
	ggiSetMode(vis, &mode);

	gerry = GerbilCreate();
	GerbilSize(gerry, 50, 100);
	GerbilPosition(gerry, 100, 100);
	GerbilShow(gerry);
	GerbilTango(gerry);
	sleep(200);
	GerbilMacarena(gerry);	


So, you're saying to yourself now that this last one looks a lot easier to
use and simpler, right?  Well, it is.  Consider, though, what happens if
the Gerbil uses video RAM.  In that case, the ggiSetMode call in the last
example might eat all of the available video ram, and GerbilCreate will
fail because there will be none left over.  This last example cannot be
rewritten to fix this problem, but the one before it can::

        ggi_visual_t vis;
	ggiGA_resource_list reqlist;
	ggiGA_resource_handle gerbilres;
	gerbil_t gerry;

        ggiInit();
        vis = ggiOpen(NULL);
	GerbilAttach(vis); /* will attach LibGAlloc if not attached */

	GerbilAdd(&reqlist, gerbilres);
	ggiGAAddSimpleMode(vis, &reqlist, 640, 480, 640, GGI_AUTO, NULL);

	ggiGACheck(vis, reqlist, NULL);
	ggiGASet(vis, reqlist, NULL);

	gerry = GerbilActivate(reqlist, gerbilres);
	GerbilSize(gerry, 50, 100);
	GerbilPosition(gerry, 100, 100);
	GerbilShow(gerry);
	GerbilUTTauntPelvic(gerry);
	sleep(200);
	GerbilBellyDance(gerry);


All we had to do was put the request for the dancing gerbil first in the
list.  That way, the gerbil gets the video RAM that it needs, and the main
mode uses up the rest of the RAM.  By using a request list and the
recommended LibGAlloc API, we can do a lot of wheeling and dealing to get
the most out of our display targets.

Tips and Tricks
---------------

Special handling of "mode resources"
""""""""""""""""""""""""""""""""""""

To LibGAlloc, the main video mode is just another feature to be negotiated
along with the rest -- but there are two things that do make it special.  
The first is that LibGAlloc provides the `ggiGAAddMode` function, instead of
leaving that up to an extension like it does with all other resources.  
The second is that since it is a given that there can be only one
*main video mode*, you are allowed to call `ggiGAAddMode` several times to
prioritize the main video mode among the features.  That is to say, when
you `ggiGACheck` or `ggiGASet` a request list, LibGAlloc will process the
modes you requested in the order they appear in the list, discarding the
last mode that was requested in favor of the next successful mode and
adjusting all the features to fit the new mode.  So, for example, you can
guarantee yourself a 640x480 main video mode by calling ggiGAAddMode first
to put a 640x480 mode first in the request list, then you can add some
requests for features, and after them you can add a request for 800x600,
and then ask for more features, and so on.

There is a way to do this for other resources, as well, and it is
called a *tag*, but that is an advanced feature, left for discussion
later in another chapter.


Tips for handling request and result lists
""""""""""""""""""""""""""""""""""""""""""

The external API tries to keep you safe from doing anything that will
cause unexpected results, but there are a couple of places where some
caution is in order, and, if you decide to use any of the *gray ops*, you
must have a good understanding of how request and result lists relate to
each other.


First, you should take care with your ggiGA_resource_list variables to
always initialize them to NULL when they are first created, and to call
ggiGAEmptyList on them before reusing them after that.  If you put a
previously used ggiGA_resource_list as the :p:`*result` parameter of
ggiGACheck, ggiGASet, or ggiGAGet, LibGAlloc will not empty the list
automatically and memory may be leaked.


Second, you must understand that the only functions that ever alter the
contents of the :p:`reqlist` parameter are the Release and Add functions
(either ggiGARelease/ggiGAAdd* or the equivalent functions supplied by an
extension.)  ggiGASet and ggiGACheck will leave :p:`reqlist` completely
untouched.  So, if you are wondering how to find what values ggiGACheck is
suggesting, you must use the :p:`reslist` parameter to get a result list.  


Third, handles you got by calling LibGGIAdd on reqlist only have a meaning
when they are used with reqlist.  Once you have a result list, you must get
a new handle from the result list in order to see the results.
Transferring handles is done through the function ggiGAHandle, which will
find a matching result handle for a request handle. You can replace all
your request handles with result handles like so::

    reshandle3 = ggiGAHandle(reslist, reqlist, reqhandle3);

... and then empty the request list.  Or, you can hang on to the
request list and handles and use ggiGAHandle to get temporary result
handles which you can use and discard as you need.

Fourth, just remember that your request handles are only valid so long
as you have the request list they were created with, that result
handles are only valid so long as you have the result list you got
them from, and that once you alter a request list, you can no longer
use it to get result handles from any previously generated result
lists.  To transfer a result handle correctly, the reslist must have
been gotten from the reqlist with ggiGACheck or ggiGAGet and/or
ggiGASet, and the handle must be transferred before the reqlist is
altered.  (By *altering the reqlist*, we mean adding any resources to
it or using it to release in-use resources.  Altering the properties
of individual resources will not confuse ggiGAHandle.)


Similarly, you should not call ggiGARelease on a request list that
has been altered since it was created by an API call.  It is strongly
advised to be sure your handles and lists are valid before calling 
ggiGARelease or ggiGASet, since these affect the running visual.


We said above that when you call ggiGACheck, you can get suggestions
in the result list.  These can take two forms.  One is when any
properties were set to GGI_AUTO or some other default setting in which
case the defaults are now replaced with probed values.  The other is
when the properties failed to fit, and LibGAlloc found some
alternative properties that do not meet the limits you asked for, but
would work.  You can tell if a resource has failed by calling
ggiGAIsFailed on the result handle -- however you should know that
only the first failed resource is flagged by ggiGACheck, and once it
has failed, the resource stays flagged failed until it succeeds, which
will not be until all the resources above it in the list succeed.  In
any case, though, you can tell whether LibGAlloc has made suggestions
by using the function ggiGAIsModified.


You can take the results list and feed it back into ggiGACheck after
modifying properties.  Request and result lists are really no
different.  However, when a call to ggiGASet is successful, the result
list is different in one small way -- all the resources in that list
are actually allocated and LibGAlloc assumes that they are *in use*.
If you change or add to this list and feed it back into ggiCheckMode
then only those changes that do not affect the *in use* resources will
succeed.


Once resources are in use, the ggiGARelease command can be used to
free them; it is usually not called directly but is called by an
extension library function named something like GerbilRelease instead,
so that other things can be deallocated along with the resource. When
ggiGARelease is (successfully) called, the resource will be deleted
from the request list, the handle passed will be set to NULL, and any
other handle to that resource will become invalid.
