Au début, mon code configurait l'environnement SDL et a procédé à mettre à jour le contexte OpenGL, sans effectuer de traitement SDL_Event. Cela provoque la fenêtre, tant qu'elle était ouverte, apparaître à Windows ne répond pas. La fenêtre scintille un peu. La barre de titre obtiendrait "(ne répondant pas)" l'a annoncée et en cliquant à l'intérieur de la fenêtre, il devient grisé, car Windows le fait par défaut sur des fenêtres non réactives. Toutefois, dans cet état (même comme et après qu'il devienne grisé), l'écran OpenGL continue de mettre à jour et d'animer, et voici le kicker, il ne le fait même pas pendant que la fenêtre est traînée em>. Clairement, dans ce cas, l'application ne manipule pas les événements de Windows correctement, ce qui oblige les fenêtres à penser qu'il est dans un état suspendu. Mais il est évident que l'OpenGL continue de rendre. Maintenant, je fais une seule modification au code, qui correspond à ces trois lignes placées dans un endroit approprié à l'intérieur de la boucle (qui fait également le dessin OpenGL): p> Tout cela fait est de rincer la file d'attente de messages à l'aide de SDL. P> Le comportement est que Windows ne pense plus qu'il "ne répond pas" et qu'il ne se griette pas. Pas de scintillement. Tout semble courir à la mer. Mais une fois que je clique et faites glisser la barre de titre pour faire glisser la fenêtre, le rendu est bloqué. Je n'ai pas débuté pour être sûr, mais je soupçonne que SDL_Pollevent Blocks pour la durée de la traînée de la fenêtre. P> Y a-t-il un moyen autour de cela? C'est intéressant car une partie du comportement exposé par omet de gérer les événements em> est la preuve que ce que je veux est possible en théorie. P> mise à jour: j'ai trouvé ce fil: Le verdict semble être que cela revient à certains choix que Microsoft a fait pour nous ... Il est essentiellement coincé dans defwindowproc () code> jusqu'à ce que la souris soit libérée. Il serait très désordonné de pirater une solution pour cela et je pourrais peut-être faire un travail autour d'un autre fil. Mais je ne veux même pas commencer à penser à jongler un contexte opengl de plusieurs threads, si c'est même quelque chose que possible. P> p>
5 Réponses :
Je propose que vous avez créé 2 threads: p>
De cette façon, votre contexte OpenGL serait manipulé à partir d'un seul fil. Toute la solution a un impact minimum sur l'architecture de votre application. P>
Merci pour votre réponse, je vais chercher cela.
FYI Soyez prudent - OpenGL n'est pas un fil sûr. Je ne sais pas comment SDL gère les événements assez bien pour dire si des événements sont assez étroitement liés au contexte OpenGL pour causer des problèmes.
Ce n'est pas une bonne solution car le rendu dépend du résultat de la manipulation des événements. Avoir deux threads de tâches non parallélisables n'aide pas.
@imallett Vous n'avez pas besoin d'OpenGL pour être en sécurité, puisque vous faites toujours des appels OpenGL à partir d'un seul fil.
@philix Bien sûr, vous auriez besoin de synchroniser correctement les deux threads. Vous pouvez utiliser une serrure en lecture-écriture, le verrou de lecture étant principalement maintenu par votre thread OpenGL, tandis que le verrouillage de l'écriture n'est parfois que détenu par la boucle d'événement. Si j'ai un peu de temps, je pourrais écrire du code pour le démontrer.
@ user1202136 Le verrouillage serait principalement sérialisé les deux tâches. Une idée plus propre serait de gérer asynchroneusement les événements.
@ user1202136 Je n'ai pas dit que c'était impossible i>, juste que l'on devrait Soyez prudent i>. Après avoir écrit ma propre couche de fenêtrage, je peux vous dire qu'il y a des problèmes subtils ici. Par exemple, est l'API WGL / GLX pour lier une partie de contexte de OpenGL ou fait-il partie du système de fenêtres? Le rappel d'entrée du système de fenêtrage est-il par cadre ou par contexte (gardant à l'esprit que les contextes de l'appareil! = Contents de rendez-vous! = Contextes matériels)? [a continué]
La question sous-jacente de l'OP est que sous Windows, en faisant glisser les cadres, comme dimensionnez la fenêtre et bloque d'autres événements d'entrée. Pour maintenir le rendu et la réactivité, il faut redessiner le cadre alors qu'il est glissé (pouvant être obtenu en appelant directement à partir du rappel d'entrée ou à l'aide d'un fil) .¶ Votre solution fonctionnera (de même que A +1 pour vous ramener à 0, pour correspondre à l'autre réponse de threading), mais je pense que la question soulevée par @philix est importante. Néanmoins, presque tous les autres systèmes de fenêtres font quelque chose comme ça en interne (Gah), en utilisant un minuteur + fil pour invoquer le rendu.
De nombreuses procédures de Windows exécutent une boucle de message distincte jusqu'à ce qu'un certain événement se produise, vous ne devriez donc pas compter sur votre boucle principale pour faire le dessin. Si possible, la logique d'application et le rendu doivent toujours être traités dans un fil séparé. P>
Votre fil principal (qui ne gère que le traitement des messages) n'a pas besoin de context GL. Vous n'avez donc pas besoin de vous inquiéter de partage. P>
Quelques partenaires de contournement qui fonctionne pour moi - ajoutez un filtre d'événements pour sdl_windowevent_size_changeed Event et effectuez un cadre StripViewPort et Structure supplémentaires.
int SDLApp::eventFilter(void* pthis, const SDL_Event *event) { if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { SDLApp* app = (SDLApp*)pthis; // Note: NULL rectangle is the entire window SDL_RenderSetViewport(app->renderer_, NULL); app->DrawFrame(); } return 1; } ... SDL_SetEventFilter((SDL_EventFilter)SDLApp::eventFilter, this);
J'ai eu un problème similaire dans lequel il gèlerait la lecture vidéo lorsque la fenêtre a été glissée ou redimensionnée. La solution que j'ai trouvée était de reproduire un fil séparé pour le rendu et d'utiliser le fil principal pour l'entrée.
Exemple: P>
DWORD RenderThread(SDL_Window* window) { //Rendering stuff here... } int main() { SDL_Init(SDL_INIT_EVERYTHING); SDL_Window* window = SDL_CreateWindow("Title Here", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, h, w, SDL_WINDOW_RESIZABLE); HANDLE hRenderThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RenderThread, window, 0, NULL); SDL_Event event; while (1) { SDL_PollEvent(&event); switch (event.type) { //Event handling here... } } }
Cette question est vieille, mais la solution que j'utilise ne semble pas être mentionnée nulle part ailleurs, alors c'est ici.
J'ai eu mon inspiration de Cette réponse, et il n'utilise pas de threads supplémentaires. p> Bien sûr, si votre fonction de rendu doit conserver Etat (par exemple, si vous utilisez OOP), utilisez le paramètre Void * code> de
evendwatch (vide *, sdl_event *) code> pour transmettre l'état. P> p>
Il convient de noter que les manutentionnaires Eventwatch fonctionnent sur le fil qui invoque l'événement, plutôt que le fil principal. Cela pourrait conduire à des problèmes car SDL s'attend à ce que le rendu effectué sur le thread principal, de sorte que votre appel à rendu code> pourrait être invalide.
Il peut s'agir d'un bug dans SDL: bugzilla.libsdl.org/show_bug.cgi?id = 2077