Rendering Qt to OgreTexture efficiently

Problems building or running the engine, queries about how to use features etc.
Post Reply
Stefan
Gnoblar
Posts: 2
Joined: Sat Dec 16, 2017 12:32 pm

Rendering Qt to OgreTexture efficiently

Post by Stefan » Fri Jan 19, 2018 10:56 am

Hey,

I'm rendering Qt (both QWidgets and QML though QML is very experimental because focus isn't working [it's not working for either but for QWidgets it can easily be faked]) into a OGRE Texture.
The application structure is Qt -> Ogre -> Qt. It is a qt application which contains a view in which OGRE is rendered and I'm rendering into OGRE.
However, my current approach involves rendering into a QFramebufferObject, converting the fbo into a QImage and finally copying the image's contents into the texture.
Which is, as you can imagine, very slow. The rendering alone takes around 5ms whereas the copying takes around 20ms.

Can I somehow render directly into the texture?
Or, alternatively, skip the toImage step and copy the content of the QFramebufferObject directly to the texture without creating a QImage first?

Here's my current code for reference, maybe you spot another performance killer in there.

The rendering code:

Code: Select all

  makeCurrent();
  // Have to compare size because geometry compares instances which would always create a new fbo
  if ( geometry_.size() != view_->geometry().size())
  {
    geometry_ = view_->geometry();
    createFbo();

    paint_device_->setSize( geometry_.size());
  }
  geometry_.moveTopLeft(view_->mapToGlobal(QPoint(0, 0)));
  fbo_->bind();
  context_->functions()->glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  for ( int i = 0; i < overlays_.size(); ++i )
  {
    auto overlay = overlays_[i];
    if ( !overlay->isVisible()) continue;
    if ( overlay->geometry().topLeft() != geometry_.topLeft() || overlay->geometry().size() != geometry_.size() )
    {
      overlays_[i]->setGeometry( geometry_ );
    }

    overlays_[i]->render( this );
  }

  fbo_->release();
  QImage image = fbo_->toImage().convertToFormat( QImage::Format_ARGB32 );
  doneCurrent();

  // Create or resize texture if necessary
  if ( texture_.isNull() || texture_->getWidth() != width || texture_->getHeight() != height )
  {
    if ( !texture_.isNull())
    {
      Ogre::TextureManager::getSingleton().remove( texture_->getName());
      material_->getTechnique( 0 )->getPass( 0 )->removeAllTextureUnitStates();
    }

    texture_ = Ogre::TextureManager::getSingleton().createManual(
      "NAME",
      Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
      Ogre::TEX_TYPE_2D,
      width,
      height,
      0,
      Ogre::PF_A8R8G8B8,
      Ogre::TU_DEFAULT
    );


    material_->getTechnique( 0 )->getPass( 0 )->createTextureUnitState( texture_->getName());
    material_->getTechnique( 0 )->getPass( 0 )->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
  }

  Ogre::HardwarePixelBufferSharedPtr buffer = texture_->getBuffer();
  buffer->lock( Ogre::HardwareBuffer::HBL_DISCARD );
  
  const Ogre::PixelBox &pixel_box = buffer->getCurrentLock();
  auto data = static_cast<Ogre::uint8 *>(pixel_box.data);
  memcpy( data, image.bits(), image.byteCount());
  
  buffer->unlock();
  ogre_overlay_->show();
paint_device_ is a QOpenGLPaintDevice
context_ is a QOpenGLContext using a QOffscreenSurface with a depth buffer size of 16 and a stencil buffer size of 8.
makeCurrent() simply makes the context current with the surface (and saves the informations necessary to restore the context of OGRE afterwards).
doneCurrent() calls doneCurrent() on the context and makes OGRE's context current again.

The createFbo method:

Code: Select all

void createFbo()
{
  // clean up
  delete fbo_;

  QOpenGLFramebufferObjectFormat format;
  format.setSamples( 16 );
  format.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
  fbo_ = new QOpenGLFramebufferObject( geometry_.size(), format );
}
How the individual overlays/widgets are rendered:

Code: Select all

  QPainter painter( renderer->paintDevice());
  widget_->render( &painter );
Thank you for reading until here!
Best,
Stefan
0 x

paroj
OGRE Team Member
OGRE Team Member
Posts: 567
Joined: Sun Mar 30, 2014 2:51 pm
x 81
Contact:

Re: Rendering Qt to OgreTexture efficiently

Post by paroj » Fri Jan 19, 2018 11:57 am

without knowing Qt good enough, to provide an useful answer: are you aware of the cutexture project?
https://bitbucket.org/ogreaddons/cutexture

I guess this problem must be solved there as wel..
0 x

Stefan
Gnoblar
Posts: 2
Joined: Sat Dec 16, 2017 12:32 pm

Re: Rendering Qt to OgreTexture efficiently

Post by Stefan » Fri Jan 19, 2018 12:35 pm

I've stumbled over it some time ago but totally forgot about it.
Thank you for the link!
I took a look at their code and they are creating a QImage wrapping the data of the texture and use this QImage to render the widgets directly into the texture.
I might try that approach for qwidgets but unfortunately this will most probably not work for QML (because QML requires OpenGL for rendering).

Update: I've used that approach as an alternative and it works great! Went down from 30ms to 10ms.
A method that works using OpenGL and hence works for both QWidgets and QML would be great though.
0 x

Post Reply