c++ - 将 QOpenGLWidget 子类转换为使用 Metal 而不是 OpenGL 的子类是否可行?

标签 c++ macos qt opengl metal

背景:我有一个 Qt/C++ 应用程序,目前运行在(并部署在)MacOS/X、Windows 和 Linux 上。在应用程序的一个窗口中有几十个需要经常更新(即 20Hz 或更快)的音频表的 View ,因此我使用 QOpenGLWidget 实现了该 View 。和一些简单的 OpenGL 例程(参见下面的示例代码)。

一切正常,但是 Apple 最近 deprecated OpenGL并希望所有开发人员将他们的应用程序转换为 Apple 自己的“Metal”API;这意味着最终任何使用 OpenGL 的程序都将停止在 MacOS/X 上运行。

如果必须的话,我不介意在我的代码中做一些#ifdef-magic 来支持一个单独的 MacOS/X API,但是不清楚是否编码到 Metal目前实际上可以在 Qt 中完成。如果 Metal-inside-Qt 是可能的,那么正确的使用方法是什么?如果不是,我是否应该等待 Qt 的 future 发布版本提供更好的 Metal 支持(例如 Qt 5.12 ?),而不是浪费时间尝试让 Metal 在我当前的 Qt 版本 (5.11.2) 中工作?

// OpenGL meters view implementation (simplified for readability)
class GLMetersCanvas : public QOpenGLWidget
{  
public:
   GLMetersCanvas( [...] );

   virtual void initializeGL()
   {  
      glDisable(GL_TEXTURE_2D);
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_COLOR_MATERIAL);
      glDisable(GL_LIGHTING);
      glClearColor(0, 0, 0, 0);
   }

   virtual void resizeGL(int w, int h)
   {  
      glViewport(0, 0, w, h);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0, w, 0, h, -1, 1);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
   }

   virtual void paintGL()
   {  
      const float meterWidth = [...];
      const float top        = [...];

      glClear(GL_COLOR_BUFFER_BIT);
      glBegin(GL_QUADS);

      float x = 0.0f;
      for (int i=0; i<numMeters; i++)
      {
         const float y = _meterHeight[i];

         glColor3f(_meterColorRed[i], _meterColorGreen[i], _meterColorBlue[i]);
         glVertex2f(x,            top);
         glVertex2f(x+meterWidth, top);
         glVertex2f(x+meterWidth, y);
         glVertex2f(x,            y);

         x += meterWidth;
      }
      glEnd();
   }
};

最佳答案

是的,可以做你想做的事。由于您发布的代码使用了非常旧的 OpenGL 已弃用功能,因此它可能不会是一个直接的过渡。此外,您最好只使用 CoreGraphics 来绘制您正在做的简单绘图。 (它看起来像正在绘制许多纯色的四边形。这在 CoreGraphics 中非常简单且相当有效。)Metal 似乎对这项工作有点过分。也就是说,这里有一些想法。

Metal 本质上是一种 Objective-C API,因此您需要将 Metal 代码包装在某种包装器中。有多种方法可以编写这样的包装器。您可以制作一个 Objective-C 类来绘制并从您的 C++/Qt 类中调用它。 (您需要将您的 Qt 类放入一个 .mm 文件中,以便编译器将其视为 Objective-C++ 来调用 Objective-C 代码。)或者您可以使您的 Qt 类成为一个抽象类,它具有指向做真正工作的类。在 Windows 和 Linux 上,它可以指向一个执行 OpenGL 绘图的对象。在 macOS 上,它将指向使用 Metal 进行绘图的 Objective-C++ 类。

This example of mixing OpenGL and Metal可能有助于理解两者的相似之处和不同之处。与在 OpenGL 中设置状态和进行绘图调用的上下文不同,在 Metal 中,您创建一个包含绘图命令的命令缓冲区,然后提交它们进行绘制。与更现代的 OpenGL 编程一样,您拥有顶点数组并将顶点和片段着色器应用于每个几何体,在 Metal 中,您还将提交顶点并使用片段和顶点着色器进行绘制。

老实说,这听起来工作量很大。 (但这当然是可能的。)如果您在 CoreGraphics 中完成它,它将看起来像这样:

   virtual void paintCG()
   {  
      const float meterWidth = [...];
      const float top        = [...];

      CGRect backgroundRect = CGRectMake(...);
      CGContextClearRect(ctx, backgroundRect);

      float x = 0.0f;
      for (int i=0; i<numMeters; i++)
      {
         const float y = _meterHeight[i];

         CGContextSetRGBFillColor(ctx, _meterColorRed[i], _meterColorGreen[i], _meterColorBlue[i]);
         CGRect meterRect = CGRectMake(x, y, meterWidth, _meterHeight[i]);
         CGContextFillRect(ctx, meterRect);

         x += meterWidth;
      }
      glEnd();
   }

它只需要你有一个 CGContextRef,我相信你可以从你正在绘制的任何窗口中获得它。如果窗口是 NSWindow,那么您可以调用:

 NSGraphicsContext* nsContext = [window graphicsContext];
 CGContextRef ctx = nsContext.CGContext;

在这种情况下,这似乎比使用 Metal 更容易编写和维护。

关于c++ - 将 QOpenGLWidget 子类转换为使用 Metal 而不是 OpenGL 的子类是否可行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52978165/

相关文章:

c++ - Monotouch : Adding . 资源,gcc 错误

c++ - 具有两个索引(或复合索引)的容器

qt - QML ListView、SwipeView 等 - 避免与其他 UI 组件重叠

c++ - 使用位操作优化检查

c++ - 在链表C++的末尾插入时出现段错误

macos - OSX 上的 bash : How to determine if network file (AFP) is in use?

macos - 为您的 Mac/Cocoa 应用程序下载安装并重新启动更新

.net - 为什么我在 mono 上收到此消息? "warning FS0191: Could not determine highest installed framework version...".NET”

qt - 如何在 Qt 中模拟消息总线?

c++ - 将 QWidget 映射到变量