metalangle icon indicating copy to clipboard operation
metalangle copied to clipboard

Mixing Qt 6 metal implementation with MetalAngle

Open demiantres opened this issue 3 years ago • 7 comments

Hi,

I am currently investigating means for converting a big OpenGL ES 2 based project from Qt 5 to Qt 6 for iOS without sticking with OpenGL. Qt 6 offers a native Metal layer implementation in conjunction with Qt 3D. But this would require to completely rewrite my project from scratch for Qt 3D.

MetalAngle seems to be a perfect solution for my problem. Basically Qt creates the Metal surface for its components (i.e. the Qml user interface). My own code keeps to use OpenGL together with the MetalAngle wrapper. Is this possible, or is it necessary to create all surface initialization stuff with MetalAngle?

Thanks,

demiantres avatar Jul 07 '21 14:07 demiantres

Could you give an example of how you currently use OpenGL with Qt? So that I can give a concrete advice. There are multiple ways to use MetalANGLE, depending on your use cases.

  • You could pass CALayer, CAMetalLayer created by Qt to low level EGL API layer to create a MetalANGLE context.
  • Or you could create a shared Metal texture that both Qt and MetalANGLE can draw to.

kakashidinho avatar Jul 07 '21 16:07 kakashidinho

My OpenGL pipeline also draws to frame buffers so I think a single texture drawing approach will not work.

The CAMetalLayer can be accessed as follows: CAMetalLayer* layer = static_cast<CAMetalLayer*>([UIApplication sharedApplication].keyWindow.rootViewController.view.layer);

The current OpenGL implementation looks like this:


void draw()
{
	//This all happens in the OpenGL context:

	drawQmlSceneGraph(); // Draws all Qml elements such as the user interface
	
	// Custom GL drawing
	glViewPort(...);
	
	// Example functions used in the project
	glClearColor(...);
	
	glBindVertexBuffer(...);
	glUseProgram(...);
	glBindFramebuffer(...);
	
}

demiantres avatar Jul 08 '21 05:07 demiantres

Will do some researches on what can be done in Qt 6.

kakashidinho avatar Jul 08 '21 18:07 kakashidinho

For now, the easiest method you can do is creating a metal texture to be shared between Metal & MetalANGLE's GL context. Then in your draw() function:

  • Draw to shared texture using MetalANGLE's GL commands. You can keep your old GL code here.
  • drawQmlSceneGraph().
  • Use Qt's Metal to blit the shared texture to Qt's screen/default framebuffer.

I can share the detailed sample code later.

kakashidinho avatar Jul 08 '21 18:07 kakashidinho

I created an example of mixing MetalANGLE with Qt's Metal here https://github.com/kakashidinho/qml-metalangle/blob/master/metaltextureimport/metaltextureimport.mm#L430 From repo https://github.com/kakashidinho/qml-metalangle

It is based on Qt's metaltextureimport example where a custom Metal texture is displayed on the screen. This texture was originally rendered by Qt's Metal but in my example, I draw to it using MetalANGLE's GL commands. You will need few extra glue code to make the mixing work though (mostly a shared semaphore (shared event in Metal term) needs to be used to synchronize between two worlds). More details can be seen in the example's code.

drawing

kakashidinho avatar Jul 15 '21 07:07 kakashidinho

Thanks a lot for the example 👍. I will try to adapt it to my project and post the result here then.

demiantres avatar Jul 15 '21 08:07 demiantres

I want to achieve something similar. I have existing code that passes framebuffer from Qt to be rendered. Should I start from the same example or could it maybe be done even in a simpler way?

ntadej avatar Mar 03 '22 21:03 ntadej