[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[E-devel] Benchmark: Brute force copy from GL pbuffer to image as data



Sorry for lack of response. Illness and loss of internet connection. This
conversation is modem powered.

As I mentioned a little while ago, I wanted to benchmark the speed at
which an OpenGL rendering into a buffer can be moved out of video memory,
into the system memory and then back into an Evas Image and rendered to
the screen.

Would anybody be surprised if I said that it really isn't fast... ahem.
Just had to try. Pseudo code of a main loop:

1) Render frame to a PBuffer
2) Get the data using glReadPixels
3) Put the frame back into an image using evas_object_image_data_set

Compile as a C++ program:

gcc bench_gl_evas.cpp -o bench_gl_evas `ecore-config --libs --cflags`
`evas-config --libs --cflags` -lGL -lGLU -lstdc++

Regards Rene Jensen



------ bench_gl_evas.cpp -----------------------

#include <iostream>
#include <fstream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>

#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Evas.h>

static const int    PBUFFER_WIDTH = 512;
static const int    PBUFFER_HEIGHT = 512;
struct Vertex
{
    float tu, tv;
    float x, y, z;
};
Vertex g_cubeVertices[] =
{
    { 0.0f,0.0f, -1.0f,-1.0f, 1.0f },
    { 1.0f,0.0f,  1.0f,-1.0f, 1.0f },
    { 1.0f,1.0f,  1.0f, 1.0f, 1.0f },
    { 0.0f,1.0f, -1.0f, 1.0f, 1.0f },
    { 1.0f,0.0f, -1.0f,-1.0f,-1.0f },
    { 1.0f,1.0f, -1.0f, 1.0f,-1.0f },
    { 0.0f,1.0f,  1.0f, 1.0f,-1.0f },
    { 0.0f,0.0f,  1.0f,-1.0f,-1.0f },
    { 0.0f,1.0f, -1.0f, 1.0f,-1.0f },
    { 0.0f,0.0f, -1.0f, 1.0f, 1.0f },
    { 1.0f,0.0f,  1.0f, 1.0f, 1.0f },
    { 1.0f,1.0f,  1.0f, 1.0f,-1.0f },
    { 1.0f,1.0f, -1.0f,-1.0f,-1.0f },
    { 0.0f,1.0f,  1.0f,-1.0f,-1.0f },
    { 0.0f,0.0f,  1.0f,-1.0f, 1.0f },
    { 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
    { 1.0f,0.0f,  1.0f,-1.0f,-1.0f },
    { 1.0f,1.0f,  1.0f, 1.0f,-1.0f },
    { 0.0f,1.0f,  1.0f, 1.0f, 1.0f },
    { 0.0f,0.0f,  1.0f,-1.0f, 1.0f },
    { 0.0f,0.0f, -1.0f,-1.0f,-1.0f },
    { 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
    { 1.0f,1.0f, -1.0f, 1.0f, 1.0f },
    { 0.0f,1.0f, -1.0f, 1.0f,-1.0f }
};

// This class is simply a fancy way of rendering a scene and getting it
//  as an ARGB array of integers
//
class RenderNode
{
public:
    unsigned long*        data;
    Display*            display;
    GLXPbuffer            pbuffer;
    GLXContext            pbufferContext;

    void init ()
    {
        // Open the X display
        display = XOpenDisplay(0);
        if (! display)
            throw "Can't open X display";

        int nItems;
        int attrib[] =
        {
            GLX_DOUBLEBUFFER,  False,
            GLX_RED_SIZE,      1,
            GLX_GREEN_SIZE,    1,
            GLX_BLUE_SIZE,     1,
            GLX_DEPTH_SIZE,    1,
            GLX_RENDER_TYPE,   GLX_RGBA_BIT,
            GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
            None
        };

        int pbufAttrib[] =
        {
            GLX_PBUFFER_WIDTH, PBUFFER_WIDTH,
            GLX_PBUFFER_HEIGHT, PBUFFER_HEIGHT,
            GLX_LARGEST_PBUFFER, False,
            None
        };

        GLXFBConfig *fbconfig = glXChooseFBConfig (
            display, DefaultScreen(display),
            attrib, &nItems);

        if (fbconfig == 0)
            throw "Can't choose fbconfig";

        pbuffer = glXCreatePbuffer (
            display, fbconfig[0], pbufAttrib);
        XVisualInfo* visinfo = glXGetVisualFromFBConfig(
            display, fbconfig[0] );
        if (! visinfo)
            throw "Error: init - Couldn't get wanted visual";

        pbufferContext = glXCreateNewContext(display, fbconfig[0],
            GLX_RGBA_TYPE, NULL, GL_TRUE);
        if (! pbufferContext)
            throw "Can't make pbuffer context";

        XFree( fbconfig );
        XFree( visinfo );

        data = new unsigned long[PBUFFER_WIDTH*PBUFFER_HEIGHT];
    }

    void render ()
    {
        if (! glXMakeContextCurrent(
                display, pbuffer, pbuffer, pbufferContext))
            throw "Can't make context current";
        static float time = 20.0;
        time += 0.1;

        glClearColor( 0,0,0, 1.0f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 45.0f,
            PBUFFER_WIDTH / PBUFFER_HEIGHT, 0.1f, 10.0f );

        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        glTranslatef( 0.0f, 0.0f, -5.0f );
        glRotatef( time, 1.0f, 0.0f, 0.0f );
        glRotatef( time, 0.0f, 1.0f, 0.0f );

        glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
        glDrawArrays( GL_QUADS, 0, 24 );

        glFlush();

        glReadPixels (0,0, PBUFFER_WIDTH, PBUFFER_HEIGHT,
            GL_BGRA, GL_UNSIGNED_BYTE, data);
    }
};




Ecore_Evas *ee;
Evas *evas;
Evas_Object *bg;
RenderNode* renderNode;

// This timer callback will transfer the data in the renderNode to
//  an image and then refresh the Evas to make the changed image visible.
int timer_cb (void *data)
{
    renderNode->render();
    evas_object_image_data_set (
        (Evas_Object*)bg, renderNode->data);
    evas_object_image_data_update_add (bg, 0,0,
        PBUFFER_WIDTH, PBUFFER_HEIGHT);

    return 1;
}

int main(int argc, const char** argv)
{
    renderNode = new RenderNode();
    renderNode->init();

    ecore_init();
    ecore_app_args_set(argc, argv);
    if (!ecore_evas_init()) return -1;
    ee = ecore_evas_software_x11_new(NULL, 0, 0, 0,
        PBUFFER_WIDTH, PBUFFER_HEIGHT);
    if (!ee) return -1;

    ecore_evas_title_set(ee, "EE Test");
    ecore_evas_show(ee);
    evas = ecore_evas_get(ee);

    bg = evas_object_image_add(evas);
    evas_object_image_size_set (bg, PBUFFER_WIDTH,PBUFFER_HEIGHT);
    evas_object_move(bg, 0, 0);
    evas_object_resize(bg, PBUFFER_WIDTH, PBUFFER_HEIGHT);
    evas_object_layer_set(bg, 0);
    evas_object_color_set(bg, 255, 255, 220, 255);
    evas_object_show(bg);
    evas_object_image_data_set (bg, renderNode->data);
    evas_object_image_size_set (bg, PBUFFER_WIDTH,PBUFFER_HEIGHT);
    evas_object_image_fill_set (bg, 0,0,PBUFFER_WIDTH, PBUFFER_HEIGHT);
    ecore_timer_add(0.01, timer_cb, bg);

    ecore_main_loop_begin();

    //while (true)
    //{
        //ecore_main_loop_iterate();
        //renderNode->render();
        //evas_object_image_data_set (bg, renderNode->data);
        //evas_object_image_data_update_add (
        //    bg, 0,0,PBUFFER_WIDTH, PBUFFER_HEIGHT);
    //}


    return 0;
}