2017-08-16 6 views
0

J'ai un problème que je ne pourrais pas résoudre depuis une semaine, j'espère que quelqu'un aurait pu l'expérimenter. J'utilise SharpDX avec un projet de formulaire Windows, il y a essentiellement un formulaire avec une image et un panneau dessus.SharpDX sous Windows - Condition de course lors de la minimisation de l'écran

La caractéristique Swapchain.Present (1, PresentFlags.None) fonctionne bien lorsque j'effectue un zoom ou une translation de l'image. Cependant, j'ai cette situation étrange où quand je minimise mon écran et le rouvre, tout le contenu de swapchain est caché comme s'il avait été effacé. Cependant, je sais que ce n'est pas le cas et c'est probablement une condition de concurrence entre le rafraîchissement de GDI et SharpDX. J'ai donc essayé de surcharger WndProc (Message m) dans chaque contrôle et de gérer son événement paint et eraseBackground. Cela ne fonctionne pas. Quand je débogue, le message de Windows est toujours différent de temps en temps, donc il est assez difficile de comprendre ce qui pourrait être faux.

Si quelqu'un a déjà rencontré ce comportement lors du mixage de SharpDX (ou DirectX) sous Windows, j'aimerais vraiment avoir une réponse.

Voici comment je gère l'événement resize de mon 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 

EDIT: Après avoir essayé des choses beaucoup, je me rends compte qu'il se passait juste quand je l'appelle base.Wndproc (m) où m = WM_PAINT.

Je ne peux pas ignorer le message de peinture parce que si je le fais, mon contrôle est toujours invalidé et il va ajouter un nouveau WM_PAINT à la file d'attente des événements et m'envoyer dans une boucle infinie. Je ne peux vraiment pas faire base.Wndproc (m) parce que c'est là que ma swapchain se cache.

Est-ce que c'est leur façon de gérer (ignorer) ce message d'événement sans avoir de retour dans la boucle, car SharpDX ne nécessite pas cette fonction puisqu'il s'agit d'une couche de peinture sur le contrôle.

+0

Pouvez-vous montrer un peu de code (spécialement la façon dont vous gérez redimensionner les événements) ? Sinon, il sera difficile de deviner ce qui se passe. – catflier

+0

J'ai modifié mon post pour ajouter comment je gère le redimensionnement du deviceContext de SharpDX, mais je ne suis pas sûr si c'est ce que vous vouliez voir. (Je ne pense pas que cela en vienne) – Kayn

+0

Je me souviens de cas où la minimisation consistait à mettre des tailles à 0 (et essayer de créer swapchain avec n'importe quel composant de taille de zéro apporte évidemment toutes sortes de problèmes).Je voudrais d'abord vérifier ce cas (et ne pas reconstruire swapchain dans ce scénario). – catflier

Répondre

1

Lorsque vous voulez juste redimensionner la swapchain, vous n'avez pas besoin de recréer le DeviceContext. Peut-être voici la première cause de votre problème, car la swapchain a été créée avec un DeviceContext différent de celui du backbuffer. Pour moi, cela fonctionne en C#:

d'ajouter des gestionnaires d'événement aux événements de redimensionnement du contrôle. Pas besoin de remplacer le 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; 

avec ceci je peux sauvegarder l'ancienne taille du contrôle pour comparaison. Et je ne fais que redimensionner la swapchain après que le redimensionnement soit terminé et non pour chaque événement (comme lors du redimensionnement d'une fenêtre). Aussi je ne redimensionner si le contrôle ne soit pas réduite au minimum:

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); 
    } 
} 

Enfin DoResize suit (RenderTarget est ma classe personnalisée):

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); 
    } 
}