[cairo] Performance OpenGL backend
Ralf
mock at cipsoft.com
Tue Feb 23 03:19:48 PST 2010
Of course, here is how I did it:
First I took the boilerplate code for creating a gl surface, and
modified it to use
my own GLXContext, my own Display*, and my own Window*.
All of these are created when Ogre3D initilises, so these are the
get....Someting calls in the code below.
Also, so far I did not make any effort in cleaning things up correctly
(or error handling), so don't check the code for this.
All changes I made to cairo code are in cairo-gl-surface.c (and in the
header of course)
You will notice the last parameter TextureID in the signature of the
function: this is actually the fbo texture
handle created completely by Ogre (as a rendertarget).
You will also notice the call to cairo_gl_surface_create inside the
function, which also passes this
TextureID to cairo. I made a little adjustment to the original cairo
code to actually use this TextureID, when given.
(see also code below).
Secondly, whenever I want to start calling cairo drawing functions, I
have to save the whole rendering context of Ogre,
and select the cairo fbo target again into the gl context.
I wrote a new small function for cairo to do this. (see also code below).
As soon as cairo finishes its drawings, I further use this texture
inside Ogre for following render passes.
Hope this sheds some light on how this seems to work with Ogre (or any
other render engine, I guess).
This might as well be not a really elegant way to integrate this into
Ogre, 'cause there are many expensive
graphics card context switches happening at the moment. But so far I did
not find anything better ;-)
If you need more info, please let me know.
Ralf
This is the function to create the surface (with all original code
commented out):
static cairo_surface_t * _cairo_boilerplate_gl_create_surface (const
char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
// cairo_boilerplate_mode_t mode,
int id,
void **closure,
unsigned int TextureID)
{
int rgba_attribs[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
int rgb_attribs[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
XVisualInfo *visinfo;
GLXContext ctx;
gl_target_closure_t *gltc;
cairo_surface_t *surface;
Display *dpy;
gltc = (gl_target_closure_t *) calloc (1, sizeof
(gl_target_closure_t));
*closure = gltc;
if (width == 0)
width = 1;
if (height == 0)
height = 1;
// dpy = XOpenDisplay (NULL);
// gltc->dpy = dpy;
// if (!gltc->dpy) {
// fprintf (stderr, "Failed to open display: %s\n",
XDisplayName(0));
// free (gltc);
// return NULL;
// }
//
//
// if (content == CAIRO_CONTENT_COLOR)
// visinfo = glXChooseVisual (dpy, DefaultScreen (dpy),
rgb_attribs);
// else
// visinfo = glXChooseVisual (dpy, DefaultScreen (dpy),
rgba_attribs);
//
// if (visinfo == NULL) {
// fprintf (stderr, "Failed to create RGB, double-buffered
visual\n");
// XCloseDisplay (dpy);
// free (gltc);
// return NULL;
// }
// ctx = glXCreateContext (dpy, visinfo, NULL, True);
// get these variables from Ogre
ctx = (GLXContext)g_RenderSystem->getMainGLContext();
dpy = (Display*)g_RenderSystem->getMainGLDisplay();
Window* win = (Window*)g_pRenderWindow->getXWindow();
PRINT(3, "----------->GLXContext is %x.", ctx);
// XFree (visinfo);
gltc->ctx = ctx;
gltc->device = cairo_glx_device_create (dpy, ctx, win);
gltc->surface = surface = cairo_gl_surface_create (gltc->device,
content,
ceil (width),
ceil (height),
TextureID);
// if (cairo_surface_status (surface))
// _cairo_boilerplate_gl_cleanup (gltc);
return surface;
}
This is how I call it:
//////////////////////////////////////////
///// test of the new cairo opengl backend
mObject = NULL;
void* closure;
m_pSurface =
_cairo_boilerplate_gl_create_surface("CairoGL",
CAIRO_CONTENT_COLOR_ALPHA,
m_TexWidth, m_TexHeight,
m_TexWidth + 1, m_TexHeight + 1,
0,
&closure,
m_TexturePtr->getGLID()); // m_TexturePtr is a smart pointer
to an Ogre texture
This is the change in _cairo_gl_surface_create_scratch to use the given
TextureID:
/* Create the texture used to store the surface's data. */
if (TextureID == 0) {
glGenTextures (1, &surface->tex);
printf("_cairo_gl_surface_create_scratch creating own texture,
texture id %d \n", surface->tex);
} else {
surface->tex = TextureID;
printf("_cairo_gl_surface_create_scratch using texture id %d \n",
TextureID);
}
This is the little function I write for cairo to set the cairo texture
active:
cairo_status_t
cairo_gl_set_surface_active (cairo_surface_t *abstract_surface)
{
cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
cairo_status_t status;
return status; // would be: check for OpenGL errors
// return _cairo_gl_surface_clear(surface);
}
On 02/22/2010 05:39 PM, Eric Anholt wrote:
> On Wed, 17 Feb 2010 17:17:02 +0000, Chris Wilson<chris at chris-wilson.co.uk> wrote:
>
>> On Wed, 17 Feb 2010 12:23:48 +0100, Ralf<mock at cipsoft.com> wrote:
>>
>>> So can that actually be the case where the opengl backend is slower,
>>> when rendering many curves which
>>> only fill a few pixels in the final picture or am I using the backend in
>>> the wrong way ?
>>>
>> No, just the common delusion that OpenGL is a panacea for all ills. In
>> this case we currently create scan-lines on the CPU and then emit a vertex
>> buffer containing all the opacities to be composited. Depending on the
>> overhead and speed of the GPU, it is easily conceivable that simply using
>> the CPU on local memory will be faster than the offload. Of course, we
>> wish to improve our algorithms for the more advanced GPUs, so please note
>> that the OpenGL backend is a work in progress.
>>
>> If you can share your experience on how you integrated cairo-gl with
>> Ogre3D, that will be great - and help us reflect on the gl backend api
>> before it is frozen. Similarly, if you can profile the bottlenecks on the
>> -image and -gl (and other backends) that will be very useful as well. One
>> technique you can use is to record an application trace using cairo-trace,
>> and submit it for inclusion in cairo-traces so that we can tune cairo for
>> your workload.
>>
>> I hope you are having fun with Cairo, and together we can make it better!
>> :)
>>
> Second on "we're interested in how you did the integration" -- it's the
> big thing I haven't figured out how to handle yet. Any experience you
> can offer from your experiments would be useful.
>
--
Ralf Mock - Senior Programmer
CipSoft GmbH, Gabelsbergerstraße 11, 93047 Regensburg, Germany
Fon: +49 941 630828-0, Fax: +49 941 630828-20
Management: Stephan Börzsönyi, Guido Lübke, Ulrich Schlott, Stephan Vogler
Register: Amtsgericht Regensburg, HRB 8295
USt-IdNr: DE216262082
More information about the cairo
mailing list