title: Draw QGLWdiget contents to FBO
body: <p>I have a <code>QGraphicsScene</code> + <code>QGraphicsView</code> setup that uses a <code>QGLWidget</code> to draw the contents.</p>
  
  <p>I've also made some fragment shaders to add a displacement map and bloom effect to the scene. If I make a <code>QPainter</code> object with a <code>QFramebufferObject</code> as the device and call the render function of the graphics scene on the <code>QPainter</code> object the scene gets rendered to the FBO and I can then use it to make the compositing. This however this has the disadvantage that it uses software rendering and it eats up a lot of resources.</p>
  
  <p>Unfortunately when I try to set a FBO as the current render target and leave the <code>QGLWidget</code> to draw on the FBO, the FBO comes out blank (and by blank I mean the color of the <code>glClearColor</code> call)</p>
  
  <p>So my question is basically, is there a way to get the contents of a <code>QGLWidget</code> on a FBO, or is there any other way of implementing post processing shaders in a <code>QGLWidget</code></p>
  
  <p>Here are the relevant parts of my current code</p>
  
  <pre><code>void MyWindow::SwitchRenderContext(RenderType type)
  {
      m_renderType = type;
      m_renderArea-&gt;SetRenderType(type);
      switch(type)
      {
      case RenderType_Software:
          m_view.setViewport(NULL);
          layout()-&gt;removeWidget(&amp;m_view);
          layout()-&gt;addWidget(m_renderArea);
          m_view.m_renderWidget = NULL;
          break;
      case RenderType_OpenGL:
          m_view.setViewport(m_renderArea);
          m_view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
          layout()-&gt;addWidget(m_renderArea);
          m_view.m_renderWidget = m_renderArea;
          break;
      }
  }
  
  void MyGlWidget::initializeGL()
  {
      m_initialized = true;
      if(m_dispFbo == NULL)
          m_dispFbo = new QGLFramebufferObject(width(), height());
      if(m_bufFbo == NULL)
          m_bufFbo = new QGLFramebufferObject(width(), height());
      if(m_fbo == NULL)
          m_fbo = new QGLFramebufferObject(width(), height());
  
      static const float vertex[] = {
          -1.0f,  1.0f, 0.0f, 1.0f,
          1.0f,  1.0f, 0.0f, 1.0f,
          -1.0f, -1.0f, 0.0f, 1.0f,
          1.0f, 1.0f, 0.0f, 1.0f,
          1.0f, -1.0f, 0.0f, 1.0f,
          -1.0f, -1.0f, 0.0f, 1.0f,
      };
  
      //initialize vbo
      if(!m_vbo.isCreated())
      {
          m_vboEnabled = m_vbo.create();
          if(m_vboEnabled)
          {
              m_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
              m_vbo.bind();
              m_vbo.allocate(vertex, sizeof(vertex) );
              m_vbo.release();
          }
          glEnable(GL_TEXTURE_2D);
      }
      glViewport(0, 0, width(), height());
      m_shadersEnabled = initializeShaders();
  }
  
  void MyGlWidget::SetRenderType(RenderType type)
  {
      m_renderType = type;
  }
  
  void MyGlWidget::DoHardwarePaint()
  {
      m_fbo-&gt;release();
      QPainter dispPainter(m_dispFbo);
      m_dispScene-&gt;RenderScene(&amp;dispPainter);
      dispPainter.end();
  
      DrawShaders();
  
      m_fbo-&gt;bind();
  }
  
  void MyGlWidget::DoSoftwarePaint()
  {
      if(!m_shadersEnabled || !m_vboEnabled)
      {
          QPainter painter(this);
          m_scene-&gt;render(&amp;painter);
          return;
      }
  
      QPainter dispPainter(m_dispFbo);
      m_dispScene-&gt;RenderScene(&amp;dispPainter);
      dispPainter.end();
  
      QPainter painter(m_fbo);
      m_scene-&gt;render(&amp;painter);
      painter.end();
  
      DrawShaders();
      update();
  
  }
  
  void MyGlWidget::DrawShaders()
  {
      m_vbo.bind();
      m_bufFbo-&gt;bind();
      glDisable(GL_DEPTH_TEST);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, m_fbo-&gt;texture());
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D, m_dispFbo-&gt;texture());
  
      m_displaceShader.bind();
      m_displaceShader.enableAttributeArray("in_verts");
      m_displaceShader.setAttributeBuffer( "in_verts", GL_FLOAT, 0, 4);
      m_displaceShader.setUniformValue("inCol", 0);
      m_displaceShader.setUniformValue("inDisplace", 1);
      glDrawArrays(GL_TRIANGLES, 0, m_vbo.size());
  
      m_bufFbo-&gt;release();
  
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, m_bufFbo-&gt;texture());
  
      m_bloomShader.bind();
      m_bloomShader.enableAttributeArray("in_verts");
      m_bloomShader.setAttributeBuffer( "in_verts", GL_FLOAT, 0, 4);
      m_bloomShader.setUniformValue("inCol", 0);
      m_bloomShader.setUniformValueArray("offsets", offsets, 8, 2);
      glDrawArrays(GL_TRIANGLES, 0, m_vbo.size());
  
      m_bloomShader.disableAttributeArray("in_verts");
      m_bloomShader.release();
  
      m_vbo.release();
      glEnable(GL_DEPTH_TEST);
  }
  
  void MyGlWidget::paintGL()
  {
      if(!m_vboEnabled &amp;&amp; m_renderType == RenderType_OpenGL)
          return;
  
      if(m_renderType == RenderType_Software)
      {
          DoSoftwarePaint();
          return;
      }
  
      DoHardwarePaint();
  }
  </code></pre>