Hi All,
Over the past week I've been working on refactoring how the OSG handles
OpenGL extensions. My motivation for this work are:
Simplify how OpenGL extensions are set up, so it takes less code
Reduced the CPU overhead of calling OpenGL extensions
Reduce both the code base and the library size
Provide a more coherent scheme for setting up extensions
(it had become inconsistent over the years)
Remove proliferation of static containers that had previously
characterised the extensions setup
All laudable goals I'm sure you'd agree, but... while I have achieved all
of these goals with what I've checked into svn/trunk over the past few days
there isn't something I haven't been able to avoid - changing the API's
associated with set up and getting extensions.
For most users I don't expect any build issues with these API changes but
for those whose application specifically get OpenGL extensions via the old
Extension classes like GL2Extensions then you may see build errors that
will required local changes to keep things compiling.
The new scheme is pretty straight forward so changing things to keep things
compiling shouldn't be difficult, often you'll end up with the same or less
code required to do the job.
The main changes are:
osg::State now has a local container that hold Extension objects,
this replaces the old static ones that used to live with StateAttribute
subclasses etc.
To get the Extension objects from the osg::State object you use form:
MyExtensionObject* mso = state->get<MyExtensionObject>();
If no MyExtensionObject has been used before then osg::State will construct
one for you, assign it to its local container then return it. Future calls
will then return that original MyExtensionObject.
To implement a custom extension object you simply used the form:
struct MyExtensionObject : public osg::Referenced
{
MyExtensionObject(unsigned int contextID)
{
osg::setGLExtensionFuncPtr(glNewGLFunction,
"glNewGLFunction");
}
void (GL_APIENTRY * glNewGLFunction)(GLsizei n, const GLenum
*bufs);
};
If you then want to invoke the GL extension you'd used;
MyExtensionObject* mso = state->get<MyExtensionObject>();
if (mso->glNewGLFunction!=0) glNewGLFunction(n, bufs);
This is far far simpler than it used to, taking a quarter as much code than
the old convoluted scheme ;-)
The new scheme is pretty lightweight making it easier to have lots of local
Extension objects, but for performance I feel that it's better for us to
group all the most commonly used OpenGL extensions into a single extensions
object so that can all sit together in the cache. This new class is call
GLExtensions and there is a fast track implementation for it assigned to
the osg::State as soon as a GraphicsContext::makeCurrent() is called. To
get this extension object you use exactly the same calling convention:
GLExtensions* ext = state->get<GLExtensions>();
Previous we had a GL2Extensions that partially had this role - originally
for GL2 related extensions, however, over the years more and post GL2
functionality has been pushed into it. Often contributors don't really
know where things should go, and to be honest it was no exactly clear to me
either - a good marker that something was amiss with the old approach and
the reason why I've undertaken this refactor.
All the old GL2Extensions functionality has now been put into the
GLExtensions class, along with all the local Extension functionality that
used to sit with various StateAttribute classes. With pulling all of these
functionality out of the StateAttributes the individual headers get smaller
and more straight forward to read/maintain. Unfortunately if your code
directly got one of these local Extension classes you'll find your build
broken, in which case you'll need to just use the
state->get<GLExtensions>() usage mentioned above.
There are certain places in the OSG code base where extensions are needed
by the appropriate osg::State for the current graphics context isn't
available, for this case the old static access methods used to be used, so
I've had to maintain these for GLExtensions object, so you'll now get them
via static GLExtensions* GLExtensions::Get(contextID, createFlag); method
in the same way that GL2Extensions::Get(..) used to be used. I'm not
entirely happy with this old bit of design living on but for now haven't
come up with a reason alternative that doesn't require refactoring more OSG
code than I'm prepared to do right now.
Another change I have made is to move the #define that used to be in
GL2Extensions header into a new GLDefines header. This GLDefines header is
included by the GLExtensions header so most applications won't need to
include it directly.
--
These changes are now part of OSG svn/trunk, and will be part of OSG-3.3.3
dev release that I'll tag this week. The total line count include/osg
directory is now actually smaller in 3.3.3 than 3.3.2 despite introduction
of several new classes and associated new OpenGL functionality. The
libosg.so is also 5% smaller in 3.3.3 and 3.3.2.
Smaller, easier to use, easier to extend, easier to maintain and faster.
But please be patient the build breakages :-)
If you see build/runtime errors let me know right away via this thread and
I'll provide guidance on how to resolve them as they appear.
Cheers,
Robert.
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org