0

I have the following code below, where I am trying to launch two threads, so that I can render multiple transformations of my model at once.

const int renderWidth = 640;
const int renderHeight = 480;

class Renderer{
public:
    Renderer(){

    }

    void startOnThread(){
        // OpenGL - Initialization
        std::cout << "Initializing.." << std::endl;
        char *myargv [1];
        int myargc=1;
        myargv[0]=strdup ("Window");
        glutInit(&myargc, myargv);
        glutInitDisplayMode(GLUT_DOUBLE); // glEndList();Enable double buffered mode
        glutInitWindowSize(renderWidth, renderHeight);   // Set the window's initial width & height
        glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
        glutCreateWindow("Window");          // Create window with the given title
        glutHideWindow();
        glewInit();

        glEnable(GL_LIGHTING);
        glEnable( GL_DEPTH_TEST );
        glShadeModel( GL_SMOOTH );
        glEnable( GL_CULL_FACE );
        glClearColor( 1, 1, 1, 1 );
    }

    cv::Mat draw(Eigen::MatrixXf mV, Eigen::MatrixXf mF){
        struct Vertex{
          GLfloat position[3];
          GLfloat normal[3];
          GLfloat texcoord[2];
        };
        std::vector<Vertex> vertexdata;

        // Iterate v
        for(int i=0; i<mV.rows(); i++){
            Vertex v;
            for(int j=0; j<mV.cols(); j++){
                v.position[j] = mV(i,j);
            }
            vertexdata.push_back(v);
        }

        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glEnable(GL_LIGHTING);
        glShadeModel( GL_SMOOTH );
        glEnable( GL_TEXTURE_2D );

        glViewport( 0, 0, (float)renderWidth/1, (float)renderHeight/1. );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 60, (float)renderWidth/(float)renderHeight, 0.1, 10000. );
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();

        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
        glPushMatrix();
        glTranslatef(0,-0.5,-0.5);
        for(int i=0; i<mF.rows(); i++){
            glBegin(GL_POLYGON);
            glVertex3fv((const GLfloat*)&vertexdata[mF(i,0)].position);
            glVertex3fv((const GLfloat*)&vertexdata[mF(i,1)].position);
            glVertex3fv((const GLfloat*)&vertexdata[mF(i,2)].position);
            glEnd();
        }
        glPopMatrix();

        // Read buffer test
        std::vector<std::uint8_t> data(renderWidth*renderHeight*4);
        glReadBuffer(GL_BACK);
        glReadPixels(0,0,renderWidth,renderHeight,GL_BGRA,GL_UNSIGNED_BYTE,&data[0]);
        cv::Mat m(cv::Size(renderWidth, renderHeight),CV_8UC4, &data[0]);
        cv::flip(m, m, -1);

        glutSwapBuffers();
        glutPostRedisplay();
        glutMainLoopEvent();

        return m.clone();
    }

    /*
     * Launch 100 threads externally, where each thread starts a renderer, and runs in loop waiting
     *
     */

};

void thread_worker(const SMPL& smpl){
    Renderer r;
    r.startOnThread();

    while(1){
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }


}

int test(){

    SMPL smpl;
    smpl.loadModelFromJSONFile(std::string(CMAKE_CURRENT_SOURCE_DIR) + "/model.json");
    std::cout.setstate(std::ios_base::failbit);
    smpl.updateModel();
    std::cout.clear();

    const int num_threads = 2;
    std::thread t[num_threads];

    //Launch a group of threads
    for (int i = 0; i < num_threads; ++i) {
        t[i] = std::thread(thread_worker, smpl);
    }

    std::cout << "Launched from the main\n";

    //Join the threads with the main thread
    for (int i = 0; i < num_threads; ++i) {
        t[i].join();
    }
}

Unfortunately, running this code causes a crash,

Initializing..
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
test: ../../src/xcb_io.c:179: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted (core dumped)

I understand that I need to render off screen somehow. However, setting up frame buffer objects, would still require that I call glutInitWindow..which would still cause the crash. How would I solve this

Spektre
  • 49,595
  • 11
  • 110
  • 380
raaj
  • 2,869
  • 4
  • 38
  • 58
  • see [What is the proper OpenGL initialisation on Intel HD 3000?](https://stackoverflow.com/q/19099162/2521214) still unsolved, You need to use `wglMakeCurrent(hdc,hrc);` (or equivalent if not on windows) in each thread. If on **IntelHD** you will most likely soon face problems like I do. Why do you need to do this in separate threads? You can render to texture by [FBO](https://stackoverflow.com/a/43930271/2521214) or by [glReadPixels](https://stackoverflow.com/a/43654398/2521214) (if on **IntelHD** because that is another thing they can not do even if they seems to look like the can ...) – Spektre Feb 17 '18 at 08:10
  • I do not have such an API – raaj Feb 17 '18 at 19:19
  • Also, is there a way i can avoid glutInitWindow? I tried using FBO but if i dont call that it still crashes – raaj Feb 17 '18 at 19:25
  • 4
    I suppose a good question to ask would be why you want to render on different threads at all? All of your GL commands will be serialised into command queues down at the driver level in any case, so nothing will be gained in terms of performance at least. – Robinson Feb 17 '18 at 19:38
  • Because my rendering runs 10 times faster. Launching 10 GL windows and rendering to them is 10 times faster. I can visibily see that my GPU utilization goes from 4% to 40% – raaj Feb 17 '18 at 22:35
  • No it is not raaj. OpenGL doesn't draw on your thread, it draws asynchronously from your application. Each opengl function call is put into a queue and then each function will be called sequentially in the order they appeared in the queue no matter what you will not be rendering faster with multiple rendering threads. As a metter of fact it is likely to be slower. – Makogan Feb 17 '18 at 22:36
  • Fine, then why is looping through each iteration and calling the draw function slower. What other alternative do you have to render different models at once. It may be asynchronous, but forcing multiple threads increases the throughput to the gpu – raaj Feb 17 '18 at 22:42
  • @raaj 1. the speed issue is 99% on your code side most likely your rendering and stuff waits for something like timer, refresh/repaint event or whatever. If you measure the GPU time you would see what Makogan writes about. 2. That API I used is OpenGL. GLUT is just a support lib using it too so you must have it otherwise you are not using OpenGL at all. And the code I showed is the init of OpenGL without GLUT. The only thing that can change are functions with `wgl` prefix (they are OS dependent). 3. FBO is extension so you need wrangler like GLEW or register it on your own before use... – Spektre Feb 18 '18 at 08:29
  • @raaj but as I see `glewinit()` in your code then you should have all the extension you got at your disposal available and also the GL API. So what API you do not have? You can also check your GL implementation if it supports FBO via extension string [Determine Intel HD Graphics Card Version](https://stackoverflow.com/a/35826975/2521214). FBO is pretty commonly implemented even Intel got it (it just do not work but is not crashing). So if it crashes either you got not initiated its function pointer accessing `0000:0000` or passing wrong data to it ... – Spektre Feb 18 '18 at 08:34
  • 1
    Your issue is not OpenGL here (not yet at leat, it will be later), but GLUT, which simply does not put the xlib into thread-safe mode. There is no way to use GLUT in a multi-threaded way wihtout modifying the GLUT implementation itself. – derhass Feb 18 '18 at 13:48

0 Answers0