如何在MacOS上使用QGLFormat更改OpenGL版本



我在Mac上使用PyOpenGL。默认情况下,将使用OpenGL 2.1。然而,根据我的研究和OpenGL扩展查看器,我应该能够使用OpenGL 4.1。我正试图将一个QGLFormat传递给我的QGLWidget,就像我在这里的许多线程上看到的那样,但上下文版本没有改变。如果我试图强迫它,它告诉我上下文是无效的。我已经做了很多实验——这里有一个非常简单的例子来说明我的问题:

from PyQt4 import QtGui, QtCore, QtOpenGL
import sys
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
glFormat = QtOpenGL.QGLFormat()
glFormat.setVersion(4,1)
glFormat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glFormat.setSampleBuffers(True)
glFormat.setDefaultFormat(glFormat)
print("Format version: " + str(glFormat.majorVersion()))
myW = QtOpenGL.QGLWidget(glFormat)
print ("Widget context valid: " + str(myW.context().isValid()))
print ("Widget format version: " + str(myW.format().majorVersion()))
print ("Widget context format version: " + str(myW.context().format().majorVersion()))
myW.context().setFormat(glFormat)
print ("Forced format valid: " + str(myW.context().isValid()))
print ("Forced format version: " + str(myW.format().majorVersion()))
myW.show()
sys.exit(app.exec_())

这是输出:

Format version: 4
Widget context valid: True
Widget format version: 1
Widget context format version: 1
Forced format valid: False
Forced format version: 4

知道我的问题在哪里吗?我做错什么了吗?我使用的是macOS Sierra 10.12.6版本。我使用Qt版本4.8.7、sip版本4.19.3和pyqt版本4.12,以防相关。以下是OpenGL扩展查看器告诉我的内容。

如有任何帮助,我们将不胜感激!

编辑

我在这里发现了类似的C++问题。我不知道如何将解决方案翻译成PyQt,但我会研究一下:在OS X上更改Qt 4.8.6中QGLWidgets的OpenGL上下文版本。

编辑3

我在尝试(的第二个版本)@ekhumuro提供的补丁时得到了以下输出:

patching file qpy/QtOpenGL/core_profile_attributes.mm
patching file qpy/QtOpenGL/qpyopengl.pro
patching file sip/QtOpenGL/qgl.sip
patch unexpectedly ends in middle of line
Hunk #3 FAILED at 493.
1 out of 3 hunks FAILED -- saving rejects to file sip/QtOpenGL/qgl.sip.rej

qpyopeng.pro现在已正确修补,但对于qgl.sip,它仍然失败。

更新

以下是qgl.sip的拒绝文件的内容:

***************
*** 478,481 ****
%ModuleHeaderCode
#include <qpyopengl_api.h>
--- 493,498 ----
%ModuleHeaderCode
#include <qpyopengl_api.h>
+ typedef struct GDevice** GDHandle;
+ void* select_3_2_mac_visual();

出于好奇,我运行了configure-ng.py并尝试编译。我得到以下错误:

[...]/PyQt4_gpl_mac-4.12.1/sip/QtOpenGL/qgl.sip:269:5: error: 'virtual' can only appear on non-static member functions
virtual void* chooseMacVisual(GDHandle handle)
^
[...]/PyQt4_gpl_mac-4.12.1/sip/QtOpenGL/qgl.sip:271:16: error: use of undeclared identifier 'select_3_2_mac_visual'
return select_3_2_mac_visual();
^
[...]/PyQt4_gpl_mac-4.12.1/sip/QtOpenGL/qgl.sip:269:44: warning: unused parameter 'handle' [-Wunused-parameter]
virtual void* chooseMacVisual(GDHandle handle)

值得一提的是,在我的Windows 10笔记本电脑上运行代码会产生以下输出:

Format version: 4
Widget context valid: True
Widget format version: 4
Widget context format version: 4
Forced format valid: False
Forced format version: 4

因此,我怀疑您的问题实际上可能不是特定于平台的问题,而是您的myW.context().setFormat(glFormat)调用的问题。有趣的是,我看了一下QGLWidget的PyQt文档,它似乎在setFormat()中丢失了,这非常没有帮助!

相反,查看相应的C++文档,看起来setFormat()实际上可以从QGLWidget本身或其子QGLContext对象调用。由于您是从QGLContext调用它,因此上下文被重置,使其无效。解决方案是在设置格式后调用myW.context().create(),从而使用新参数创建一个有效的格式对象!这种修改看起来是这样的:

from PyQt4 import QtGui, QtCore, QtOpenGL
import sys
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
glFormat = QtOpenGL.QGLFormat()
glFormat.setVersion(4,1)
glFormat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glFormat.setSampleBuffers(True)
glFormat.setDefaultFormat(glFormat)
print("Format version: " + str(glFormat.majorVersion()))
myW = QtOpenGL.QGLWidget(glFormat)
print ("Widget context valid: " + str(myW.context().isValid()))
print ("Widget format version: " + str(myW.format().majorVersion()))
print ("Widget context format version: " + str(myW.context().format().majorVersion()))
myW.context().setFormat(glFormat)
myW.context().create()
print ("Forced format valid: " + str(myW.context().isValid()))
print ("Forced format version: " + str(myW.format().majorVersion()))
myW.show()
sys.exit(app.exec_())

另一种选择是只调用QGLWidget级别的setFormat()会自动创建一个新上下文,结果如下:

from PyQt4 import QtGui, QtCore, QtOpenGL
import sys
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
glFormat = QtOpenGL.QGLFormat()
glFormat.setVersion(4,1)
glFormat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glFormat.setSampleBuffers(True)
glFormat.setDefaultFormat(glFormat)
print("Format version: " + str(glFormat.majorVersion()))
myW = QtOpenGL.QGLWidget(glFormat)
print ("Widget context valid: " + str(myW.context().isValid()))
print ("Widget format version: " + str(myW.format().majorVersion()))
print ("Widget context format version: " + str(myW.context().format().majorVersion()))
myW.setFormat(glFormat)
print ("Forced format valid: " + str(myW.context().isValid()))
print ("Forced format version: " + str(myW.format().majorVersion()))
myW.show()
sys.exit(app.exec_())

话虽如此,所有这些都是猜测,因为我没有Mac可以在上面测试这段代码如果这能帮你解决问题,请告诉我,并希望它能有所帮助!

要回答有关将Mac特定解决方案转换为Python的特定问题:这不可能直接执行,因为PyQt绑定不包装虚拟方法,请选择MacVisual。没有这一点,就没有办法重新实现它,因为Qt看不到任何PyQt没有预定义为虚拟的Python方法。

因此,让它工作的唯一方法是修补PyQt4并重新编译它。幸运的是,有人已经这样做了,并在这里提供了代码:

  • https://github.com/prideout/coregl-python

但是,构建指令并不完全清楚,而且是针对PyQt-4.9.4的。所以我准备了一个diff,它应该更容易使用。我没有试图编译它,因为我没有访问Mac系统的权限。

要应用补丁,请将最新的PyQt4 OSX源代码和cd解压缩到目录中。然后复制下面的diff并将其保存为macgl.diff,然后运行以下命令:

patch -Np1 -i macgl.diff

然后,您可以使用以下说明编译您的补丁PyQt4:

  • 安装PyQt4

更新

我之前认为针对PyQt-4.9.4的差异会完全适用于所有较新的PyQt4版本,但我错了。我试图用下面修改的diff来弥补这一点,该diff已适用于PyQt-4.12.1 mac源代码。

区别在于:

diff -Naur c/qpy/QtOpenGL/core_profile_attributes.mm d/qpy/QtOpenGL/core_profile_attributes.mm
--- c/qpy/QtOpenGL/core_profile_attributes.mm   1970-01-01 01:00:00.000000000 +0100
+++ d/qpy/QtOpenGL/core_profile_attributes.mm   2017-10-22 20:11:53.000000000 +0100
@@ -0,0 +1,22 @@
+#include <QGLContext>
+ 
+ 
+void* select_3_2_mac_visual()
+{
+    static const int Max = 40;
+    NSOpenGLPixelFormatAttribute attribs[Max];
+    int cnt = 0;
+   
+    attribs[cnt++] = NSOpenGLPFAOpenGLProfile;
+    attribs[cnt++] = NSOpenGLProfileVersion3_2Core;
+   
+    attribs[cnt++] = NSOpenGLPFADoubleBuffer;
+   
+    attribs[cnt++] = NSOpenGLPFADepthSize;
+    attribs[cnt++] = (NSOpenGLPixelFormatAttribute)16;
+   
+    attribs[cnt] = 0;
+    Q_ASSERT(cnt < Max);
+   
+    return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+}
diff -Naur c/qpy/QtOpenGL/qpyopengl.pro d/qpy/QtOpenGL/qpyopengl.pro
--- c/qpy/QtOpenGL/qpyopengl.pro    2017-06-30 09:47:26.000000000 +0100
+++ d/qpy/QtOpenGL/qpyopengl.pro    2017-10-31 17:07:37.694805459 +0000
@@ -24,6 +24,11 @@
TARGET      = qpyopengl
TEMPLATE    = lib
+mac {
+     OBJECTIVE_SOURCES  +=  core_profile_attributes.mm
+     LIBS += -framework Foundation -framework Cocoa
+ }
+
SOURCES   = 
qpyopengl_attribute_array.cpp 
qpyopengl_uniform_value_array.cpp
diff -Naur c/sip/QtOpenGL/qgl.sip d/sip/QtOpenGL/qgl.sip
--- c/sip/QtOpenGL/qgl.sip  2017-06-30 09:47:26.000000000 +0100
+++ d/sip/QtOpenGL/qgl.sip  2017-10-31 17:30:26.025295693 +0000
@@ -20,6 +20,14 @@
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

+%ModuleCode
+#include <qgl.h>
+
+typedef struct GDevice** GDHandle;
+void* select_3_2_mac_visual();
+
+%End
+
namespace QGL
{
%TypeHeaderCode
@@ -257,6 +265,13 @@
%End
%End
+%TypeCode
+    virtual void* chooseMacVisual(GDHandle handle)
+    {
+        return select_3_2_mac_visual();
+    }
+%End
+
public:
void deleteTexture(GLuint tx_id);
static void setTextureCacheLimit(int size);
@@ -478,4 +493,6 @@
%ModuleHeaderCode
#include <qpyopengl_api.h>
+typedef struct GDevice** GDHandle;
+void* select_3_2_mac_visual();
%End

相关内容

  • 没有找到相关文章

最新更新