2017-10-19 44 views
2

我在Mac上使用PyOpenGL。默認情況下,使用OpenGL 2.1。但是,根據我的研究和OpenGL Extension Viewer,我應該可以使用OpenGL 4.1。 我試圖將一個QGLFormat傳遞給我的QGLWidget,正如我在這裏看到的許多線程所做的那樣,但上下文版本不會改變。如果我試圖強制它,它會告訴我上下文無效。 我一直在嘗試了很多 - 這裏是一個非常簡單的例子,說明我的問題:如何在MacOS上使用QGLFormat更改OpenGL版本?

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,以防相關。 這是what OpenGL Extension Viewer tells me

任何幫助將不勝感激!

編輯

我發現什麼看起來像一個類似的問題與C++在這裏。我不知道如何翻譯解決方案到PyQt,但我會研究這個: Changing the OpenGL Context Version for QGLWidgets in Qt 4.8.6 on OS X

編輯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(); 

出於好奇,我跑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) 
+0

你需要創建在OSX上_forward-compatible_上下文。 – derhass

+0

@derhass:你能更具體嗎? – Elensil

回答

1

對於什麼是值得的,在我的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)通話。有趣的是,我看了一下PyQt documentation for QGLWidget,它似乎缺少了setFormat(),這非常無益!

展望而不是在相應的C++文檔,它看起來像setFormat()實際上可以從要麼QGLWidget itself叫,否則孩子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_()) 

另一種方法是隻是調用setFormat()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.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。讓我知道這是否解決了你的問題,並希望它有幫助!

+1

謝謝!至少,我知道爲什麼上下文變得無效,多虧了你。實際上,我已經嘗試在窗口小部件級別調用setFormat(),但它不會改變任何內容:也就是說,上下文是有效的,但版本保持爲1.這就是爲什麼我直接嘗試上下文。 :( 我也嘗試了你的第一個建議,但我得到了同樣的結果:我最終得到了有效的上下文,但仍然是錯誤的OpenGL版本。 – Elensil

+0

@Elensil看看你在問題編輯中添加的鏈接。如果升級到PyQt5不是一個選項(這可能會解決您的問題),它看起來像你需要以某種方式翻譯該C++選項。有很多選項(ctypes,cython或C擴展),但最簡單的可能是首先使用ctypes。希望增加一個賞金將帶來一些關注這個問題,因爲我不能真正測試任何東西,沒有一個Mac哈哈...... – CodeSurgeon

+0

我試着用PyQt5,它修復了這個問題。這是一個備份解決方案,但將我的應用程序升級到PyQt5將需要大量工作。 主要是因爲混合中引入了一些遺留的OpenGL,當我切換到PyQt5時不再有效。 我不是最初的開發者,而且我對OpenGL及其不同版本的知識有限。另一方面,我想爲我的用戶安裝一些易於安裝的東西。下載和運行補丁程序可能會阻礙不止一些補丁程序。 :( – Elensil

1

要回答關於翻譯的Mac專用的解決方案成Python的具體問題:這是不可能做到直接,因爲PyQt的綁定不裹虛方法chooseMacVisual。沒有這個,就沒有辦法重新實現它,因爲Qt無法看到PyQt沒有預先定義爲虛擬的任何Python方法。

因此,唯一可行的方法是修補PyQt4並重新編譯它。幸運的是,有人已經做到了這一點,並在這裏提供的代碼:

然而,構建指令不是完全清楚,以及旨在PyQt的-4.9.4。所以我準備了一個比較容易處理的差異。我沒有試圖編譯它,因爲我無法訪問Mac系統。

要應用修補程序,請將latest PyQt4 OSX sources和cd解壓到目錄中。然後複製DIFF下方並保存爲macgl.diff,並運行此命令:

patch -Np1 -i macgl.diff 

然後,您可以編譯使用說明您的修補PyQt4的如下所示:

更新

我以前認爲差異對PyQt-4.9.4將適用於所有新版PyQt4版本,但我錯了。我試圖用下面修改過的差異來修正這個問題,它已被修改爲PyQt-4.12.1 mac source code

這裏是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 
+0

這看起來不錯,謝謝你的徹底答案!我無法對此進行測試,因此希望OP能夠回覆並驗證它是否適用於較新版本的PyQt4。 – CodeSurgeon

+1

@CodeSurgeon。看起來我們都在這個黑暗中,但希望這個補丁仍然會工作... – ekhumoro

+0

@ekhumoro 感謝您的答案,這看起來很有希望! 我已經離開了一段時間,剛剛回到這個問題。 要清楚,你的補丁完全取代你提供的coregl-python鏈接,對嗎? 我試過了你的指示,但我收到一條錯誤信息(請參閱我在問題中的第二個編輯)。任何想法是什麼導致這個? 不幸的是,我只是盲目地按照你的指示在這裏,我沒有太多的幫助。 – Elensil