[英]OpenGL flickering/damaged with window resize and DWM active
我有一個wxWidgets應用程序,它有許多子opengl窗口。 我正在使用自己的GL畫布類,而不是wx類。 Windows共享他們的OpenGL上下文。 我不認為它是wxwidgets的事實在這里真的很重要。
opengl窗口是窗口的子窗口,它們是彼此的兄弟,包含在選項卡控件中。 MDI樣式界面的種類,但它不是MDI窗口..每個窗口都可以單獨調整大小。 除非啟用Aero且DWM處於活動狀態,否則所有工作都很可愛。
調整任何窗口的大小(甚至不是opengl窗口)會導致所有opengl窗口偶爾閃爍,其中包含一個陳舊的后備存儲視圖,其中包含屏幕上那個非opengl的垃圾。 這僅在啟用Aero時發生。
我很確定這是DWM實際上沒有在其繪圖表面后備存儲上的opengl內容,並且窗口沒有在正確的時刻重新繪制。
我已經嘗試了很多東西來解決這個問題,我確實有一個解決方案,但它不是很好,並且需要將帶有glReadPixels的幀緩沖區讀入DIB,然后在我的onPaint例程中將其blitting到paint DC。 這種解決方法僅在DWM處於活動狀態時才啟用,但我根本不必這樣做,因為它會稍微損害性能(但在功能強大的系統上也不會太糟糕 - 場景是相對簡單的3d圖形)。 也不推薦混合使用GDI和opengl,但這種方法令人驚訝。 我現在可以忍受它,但我寧願不必。 如果我想截取子窗口的截圖,我仍然需要在WM_PRINT中執行此操作,我沒有看到解決方法。
有誰知道更好的解決方案嗎?
在有人要求之前我肯定會做以下事情:
我試過了:
禁用DWM不是一種選擇。
據我所知,如果你在OpenGL上使用Direct3D,這甚至是一個問題 ,雖然我沒有測試過它,因為它代表了很多工作。
這是一個遠景,但我自己剛剛解決了同樣的問題。
由於我們正在繪制圍繞我們的OpenGL窗口的無標題組框的輪廓(即,制作一個漂亮的小邊框),因此我們正在進行遠視部分,這可能無法描述您的情況。
我們發現導致問題的是:
我們一直在使用RoundRect()調用(使用HOLLOW_BRUSH)來繪制組框的輪廓。 將其更改為MoveToEx()和LineTo()調用以確保只繪制線條,並且在組框內沒有任何操作,這使得GDI不會嘗試意外地重新繪制控件的整個內容。 失效邏輯可能存在差異(或者我們在裝載預期的空心刷時有某種錯誤)。 我們還在調查。
-Noel
我的應用程序只有一個OpenGL窗口(主窗口),但我在窗口調整大小時遇到了一些令人討厭的DWM撕裂問題,我想知道其中一個解決方案是否適合你。
首先,我發現在窗口調整大小期間,至少有兩個不同的壞人想要在你有機會自己更新窗口之前修改你的客戶區來“幫助”你,創造閃爍。
第一個壞人可以追溯到SetWindowPos()
內部的一個XP / Vista / 7 BitBlt
,Windows在窗口大小調整期間內部執行,並且可以通過涉及攔截WM_NCCALCSIZE
或涉及攔截WM_WINDOWPOSCHANGING
其他技巧來消除。
在Windows 8/10中,我們仍然存在這個問題,但我們有一個新的壞人,即Aero DWM.exe窗口管理器,當他認為你“更新”屏幕后,他會做自己不同類型的BitBlt
。
我懷疑你看到的垃圾像素可能實際上是一個故意的,非常非常糟糕的嘗試,DWM在等待你畫畫時填寫“可接受”的東西。 我發現當DWM點擊新客戶區時,DWM會擴展舊客戶區數據的邊緣像素,這是瘋狂的。
不幸的是,我不知道有任何100%的解決方案可以阻止DWM這樣做,但我確實有一個定時黑客可以大大降低它的頻率。
有關WM_NCCALCSIZE
/ WM_WINDOWPOSCHANGING
黑客的源代碼以及DWM計時黑客,請參閱:
如何在調整窗口大小時平滑丑陋的抖動/閃爍/跳躍,特別是拖動左/上邊框(Win 7-10; bg,bitblt和DWM)?
嗯,也許你遇到了同樣的問題:如果你使用“新”MFC,它將使用Tabs和Window Spliter創建和應用。
拆分器有一些邏輯(我猜測在透明窗口周圍的某處並為分割繪制XOR行)導致這種行為。 刪除拆分器以確認它可以解決您的問題。 如果您需要拆分功能 - 請放入不同的拆分器。
Tabs允許對接並再次拆分具有相同問題的窗口 - 刪除/替換。
祝你好運,伊戈爾
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.