背景:我有一个Qt / C ++应用程序,该应用程序当前在MacOS / X,Windows和Linux上运行(并部署在MacOS / X,Windows和Linux上)。在应用程序的一个窗口中,有几十个需要经常更新的音频表的视图(即,以20Hz或更快的速度),因此我使用QOpenGLWidget和一些简单的OpenGL例程实现了该视图(请参见下面的示例代码)
一切正常,但是Apple最近deprecated OpenGL希望所有开发人员将其应用程序转换为Apple自己的“ Metal” API;暗示最终所有使用OpenGL的程序都将停止在MacOS / X上运行。
如果需要的话,我不介意在代码中进行一点#ifdef
-魔术操作来支持单独的MacOS / X API,但是尚不清楚是否可以对Metal进行编码目前在Qt中。如果可以在Metal-inside-Qt中使用,什么是正确的方法?如果不是,我是否应该等待具有更好的Metal支持(例如Qt 5.12?)的Qt的将来版本,而不是浪费时间试图使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();
}
};
答案 0 :(得分:2)
是的,可以做您想做的事。由于您发布的代码使用了非常老的OpenGL不推荐使用的功能,因此这可能不是一个简单的过渡。另外,对于正在执行的简单绘图,仅使用CoreGraphics可能会更好。 (看起来像是绘制了许多单色的四边形。在CoreGraphics中这是非常容易且相当有效的。)金属对于这项工作似乎有些过头了。也就是说,这里有一些想法。
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容易编写和维护。