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

Python 如何在MacOS上使用QGLFormat更改OpenGL版本?,python,macos,opengl,pyqt4,qglwidget,Python,Macos,Opengl,Pyqt4,Qglwidget,我正在Mac上使用PyOpenGL。默认情况下,使用OpenGL 2.1。然而,根据我的研究和OpenGL Extension Viewer,我应该能够使用OpenGL 4.1。 我正在尝试将QGLFormat传递给我的QGLWidget,正如我在这里的许多线程上看到的那样,但是上下文版本没有改变。如果我试图强迫它,它告诉我上下文是无效的。 我已经做了很多实验——下面是一个非常简单的例子,说明了我的问题: from PyQt4 import QtGui, QtCore, QtOpenGL imp

我正在Mac上使用PyOpenGL。默认情况下,使用OpenGL 2.1。然而,根据我的研究和OpenGL Extension Viewer,我应该能够使用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。 这是

任何帮助都将不胜感激

编辑

我发现这里的C++看起来类似问题。我不确定如何将解决方案转换为PyQt,但我将研究以下内容:

编辑3

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

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
qpyopengl.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();

值得一提的是,在我的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)
调用有关。有趣的是,我查看了,setFormat()似乎缺少了它,这是非常没有帮助的

相反,查看相应的C++文档,它看起来像是
setFormat()
实际上可以从调用,或者从它的子对象调用。由于您是从
QGLContext
调用它,结果表明该上下文是reset,使其无效。解决方案是在设置格式后调用
myW.context().create()
,从而使用新参数创建一个有效的format对象!该修改如下所示:

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绑定没有包装虚拟方法。没有这一点,就无法重新实现它,因为Qt无法看到PyQt没有预定义为虚拟的任何Python方法

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

但是,构建说明并不完全清楚,它是针对PyQt-4.9.4的。因此,我准备了一个比较容易使用的diff。我没有尝试编译它,因为我没有访问Mac系统的权限

要应用修补程序,请将、和cd解压缩到目录中。然后复制下面的差异并将其保存为
macgl.diff
,然后运行以下命令:

patch -Np1 -i macgl.diff
然后,您可以使用以下说明编译修补的PyQt4:

更新

我以前认为,与PyQt-4.9.4的差异将完全适用于所有较新的PyQt4版本,但我错了。我已经尝试用下面修改过的diff来纠正这一点,该diff已被改编为

以下是区别:

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
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 @@
+#包括
+ 
+ 
+void*选择_3_2_mac_visual()
+{
+静态常数int Max=40;
+NSOpenGLPixelFormatAttribute属性属性[Max];
+int-cnt=0;
+   
+attribs[cnt++]=NSOpenGLPFAOpenGLProfile;
+属性[cnt++]=NSOpenGLProfileVersion3_2核心;
+   
+attribs[cnt++]=NSOpenGLPFADoubleBuffer;
+   
+attribs[cnt++]=NSOpenGLPFADepthSize;
+属性[cnt++]=(NSOpenGLPixelFormatAttribute)16;
+   
+attribs[cnt]=0;
+Q_断言(cnt
谢谢!至少我知道
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