2017-08-16 54 views
0

我有一個問題,我無法修復,因爲一週後,我希望有人能夠經歷過這一點。Windows窗體上的SharpDX - 最小化屏幕時的競爭條件

我正在使用SharpDX與Windows窗體項目,基本上有一個窗體與一個圖片框和一些面板。

當我縮放或翻譯圖像時,典型的Swapchain.Present(1,PresentFlags.None)效果很好。然而,我得到這種奇怪的情況,當我最小化屏幕並重新打開它時,所有交換鏈內容都被隱藏起來,就像它已被刪除一樣。但是,我知道它沒有,這可能是GDI刷新和SharpDX之間的競爭條件。

所以,我試圖在每個控件中覆蓋WndProc(Message m)並處理它的paint和eraseBackground事件。這不起作用。當我調試時,Windows消息總是有時會不同,所以很難弄清楚什麼是錯的。

如果有人在Windows窗體上混合SharpDX(或directX)時遇到過這種情況,我真的很想回答。

這裏是我如何處理我的SharpDX DeviceContext

Public Overrides Sub Resize(Width As Integer, Height As Integer) 
     If m_SwapChain IsNot Nothing Then 
     If m_BackBuffer IsNot Nothing Then 
      m_BackBuffer.Dispose() 
     End If 
     If m_2DDeviceContext IsNot Nothing Then 
      m_2DDeviceContext.Dispose() 
     End If 
     If m_2DTarget IsNot Nothing Then 
      m_2DTarget.Dispose() 
     End If 

     m_SwapChain.ResizeBuffers(2, Width, Height, Format.B8G8R8A8_UNorm, SwapChainFlags.GdiCompatible) 

     m_BackBuffer = m_SwapChain.GetBackBuffer(Of Surface)(0) 

     m_2DDeviceContext = New SharpDX.Direct2D1.DeviceContext(m_2DDevice, SharpDX.Direct2D1.DeviceContextOptions.EnableMultithreadedOptimizations) 

     m_2DTarget = New SharpDX.Direct2D1.Bitmap(m_2DDeviceContext, m_BackBuffer, m_Properties) 
     m_2DDeviceContext.AntialiasMode = AntialiasMode.PerPrimitive 

     m_2DDeviceContext.Target = m_2DTarget 

     CType(m_Context, GPUDrawingContext).DeviceContext = m_2DDeviceContext 
     End If 

    End Sub 

編輯resize事件: 嘗試很多東西之後,我意識到這是怎麼回事權當我打電話base.Wndproc(M),其中m = WM_PAINT。

我不能忽略油漆消息,因爲如果我這樣做,我的控件仍然無效,它會將新的WM_PAINT添加到事件隊列並將我發送到無限循環。我真的無法做base.Wndproc(m),因爲這是我的交換鏈隱藏的地方。

他們是否有辦法處理(忽略)這個事件消息而不讓它回到循環中,因爲SharpDX不需要這個函數,因爲它是控件上的繪圖層。

+0

你能表現出一定的代碼(你特意如何處理調整大小事件) ?否則,很難猜測發生了什麼。 – catflier

+0

我編輯了我的帖子,添加了如何處理來自SharpDX的deviceContext的大小調整,但我不確定這是否是您想要查看的內容。 (我不認爲這是來自它) – Kayn

+0

我確實記得最小化時將大小設置爲0的情況(並且嘗試創建任意大小爲零的交換鏈當然會帶來各種問題)。我會首先檢查這種情況(而不是在該場景中重建交換鏈)。 – catflier

回答

1

當您只是想調整交換鏈的大小時,您不必重新創建DeviceContext。也許這是你的問題的第一個原因,因爲交換鏈是用不同的DeviceContext創建的而不是backbuffer。 對我來說,這是在C#中工作:

首先添加eventhandlers到控件的resize事件。無需重寫WM_PAINT:

form.ResizeBegin += (o, e) => { 
    formHeight = ((Form)o).Height; 
    formWidth = ((Form)o).Width; 
}; 
form.ResizeBegin += (o, e) => { 
    isResizing = true; 
}; 
form.ResizeEnd += (o, e) => { 
    isResizing = false; 
    HandleResize(o, e); 
}; 
form.SizeChanged += HandleResize; 

與此我可以保存控件的舊大小進行比較。我只是在調整大小完成後調整交換鏈的大小,而不是爲每個事件調整大小(例如調整窗口大小時)。此外,我只會重新調整,如果控制未最小化:

private void HandleResize(object sender, System.EventArgs e) { 
    Form f = (Form)sender; 
    if ((f.ClientSize.Width != formWidth || f.ClientSize.Height != formHeight) 
     && !isResizing 
     && !(f.WindowState == FormWindowState.Minimized)) { 
     formWidth = f.ClientSize.Width; 
     formHeight = f.ClientSize.Height; 

     DoResize(formWidth, formHeight); 
    } 
} 

最後DoResize是以下(渲染目標是我的自定義類):

private void DoResize(int width, int height) { 
    renderTarget.Dispose(); 
    swapChain.ResizeBuffers(1, width, height, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch); 
    using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0)) { 
     //recreate the rendertarget with the new backbuffer 
     renderTarget.Resize(width, height, resource); 
    } 
}