On Tue, 27 Feb 2001, Christoph Egger wrote:
> In this example, you request a 640x480x8-resolution, a waitretrace
> from libmisc and a sprite-pointer from libovl (instead of libBSE).
Yeah, I should've used BSE, but it was just an example. The
example you provided was perfect for the simple usage case.
> OK so far - this is the ideomatic case how an application should be
> written. Now I try to explain, why threads are needed to do this:
>
> At first libgalloc gets a request from libovl/libblit for a
> sprite-pointer. Then it gets a request libbuf for an alpha-buffer and
> then for a stencil-buffer.
>
> These basically are three things libgalloc has to get out of the
> target in the best way.
> To make libgalloc able to handle this, it has to start a own thread
> to not lock the main process until it tries to use the resources,
> which are not allocated at this time. During this time libgalloc
> tries to get the best combination of the three requests out of the
> target. When this is done, then its thread finishes and pass the
> information back to libbuf and libovl/libblit, where a waiting thread
> inside of their own allocation-function initializes the resources and
> passes them back to libxmi and libbse and exits. Then the
> main-process will be unlocked and it continues until exiting.
>
> I hope I am clear enough. If you are not sure you got me right, then
> ask.
I see what you're saying, which is that you want to have your cake and
eat it too :). Originally I wasn't intending for the "simple" interface
to deal with thoroughly squeezing the target for multiple features at all.
The features would be "allocated" right then when the simple form of the
function was called, and whether or not they can be fully initialized,
before they are used, they are considered already allocated.
If another request for a different feature comes along after that
point, and the feature before it had already consumed the resources
even if it was not initialized yet, too bad -- an alloc is an alloc.
Under the simple interface there is no attempt made to downsize already
allocated features to make room.
If the user wants more sophisticated behaviore, they should use the
more sophisticated API. Sophisticated behavior from a dumbed down
API usually only results in having to write reams of documentation
explaining the subtle ways of the API, which ends up defeating the
purpose of a simple API.
The complex form I showed would not need threads but should be threadsafe.
If the program is running and cannot take the time to go through the allocation
process syncronously, then the user would themselves clone another thread to
do it. Cloning a thread inside a library should only be done if it is
absolutely necessary, and libraries should be written to be functional
where threads are not available whenever possible.
> > > LibGalloc just checks, if the resources are available or not and
> > > allocate them if possible.
> >
> > Yes, but it knows how to figure out how to get the resources out of the
> > target.
>
> Yes and no. That's a bit crufty, because there are some broken
> targets like the X one.
We shouldn't break the API for the sake of a broken target. We should
make an effort to make the API flexible, but not bend over backwards.
> Have a look at the source, how libovl allocates the
> sprite-pointer/cursor:
>
> It does nothing but setting a flag at allocation time to indicate
> itself later, that the caller want to have one. Then when the caller
> set the image of the sprite it will be allocated, because the
> allocation function XCreatePixmapCursor() requires an image as a
> parameter.
I don't program with X much and I'm not familiar with the way
the X cursor works, so I don't know what the best solution
here would be. But if the cursor feature does not affect any other
feature, then LibGAlloc should not be called at all -- LibGAlloc
is only for cases where features from different extensions interfere
with each other or with the main mode.
I don't rmember what Marcus said when you asked, but I recall disagreeing
with it. IMO when you get the X cursor, fill the cursor with black
and hide it (supposing the cursor can be loaded again later from
a bitmap). If you have to allocate a bitmap to load the black
in -- then allocate it, load the black from it, and destroy it.
The general rule of thumb here is that if the "check" succeeds,
so must the "set", unless there is a bug. IIRC the only exception
we make to this rule is if the overhead of allocating structures
during the set operation runs OOM, because trying to figure the
memory usage out ahead of time would be a major pain.
--
Brian