1. 程式人生 > >SDL除錯心得(MFC SDL 視窗放大後 畫面卡死)

SDL除錯心得(MFC SDL 視窗放大後 畫面卡死)

同一個視窗控制代碼在多次使用SDL_CreateWindowFrom和SDL_DestroyWindow以後,發現程式執行正常,但視訊顯示不出來的問題。

第一次將Hwnd傳遞給SDL_CreateWindowFrom,建立一個顯示視窗給SDL,隨後在不使用的時候,呼叫SDL_DestroyWindow,將剛剛建立的顯示視窗銷燬,釋放顯示相關資源之後,然後在再次使用SDL_CreateWindowFrom的時候,將同一個控制代碼傳遞給SDL_CreateWindowFrom,返回成功,後續的操作也全部正常進行,但視訊在視窗上始終顯示不出來。

對於其中的原因,我找了好久,後面從SDL的原始碼中才慢慢推測並懷疑一些問題,SDL原始碼如下:

複製程式碼
 1 void
 2 SDL_DestroyWindow(SDL_Window * window)
 3 {
 4     SDL_VideoDisplay *display;
 5 
 6     CHECK_WINDOW_MAGIC(window, );
 7 
 8     /* Restore video mode, etc. */
 9     SDL_HideWindow(window);/*注意這個地方哦*/
10 
11     /* Make sure this window no longer has focus */
12     if (SDL_GetKeyboardFocus() == window) {
13 SDL_SetKeyboardFocus(NULL); 14 } 15 if (SDL_GetMouseFocus() == window) { 16 SDL_SetMouseFocus(NULL); 17 } 18 19 /* make no context current if this is the current context window. */ 20 if (window->flags & SDL_WINDOW_OPENGL) { 21 if (_this->current_glwin == window) {
22 SDL_GL_MakeCurrent(window, NULL); 23 } 24 } 25 26 if (window->surface) { 27 window->surface->flags &= ~SDL_DONTFREE; 28 SDL_FreeSurface(window->surface); 29 } 30 if (_this->DestroyWindowFramebuffer) { 31 _this->DestroyWindowFramebuffer(_this, window); 32 } 33 if (_this->DestroyWindow) { 34 _this->DestroyWindow(_this, window); 35 } 36 if (window->flags & SDL_WINDOW_OPENGL) { 37 SDL_GL_UnloadLibrary(); 38 } 39 40 display = SDL_GetDisplayForWindow(window); 41 if (display->fullscreen_window == window) { 42 display->fullscreen_window = NULL; 43 } 44 45 /* Now invalidate magic */ 46 window->magic = NULL; 47 48 /* Free memory associated with the window */ 49 SDL_free(window->title); 50 SDL_FreeSurface(window->icon); 51 SDL_free(window->gamma); 52 while (window->data) { 53 SDL_WindowUserData *data = window->data; 54 55 window->data = data->next; 56 SDL_free(data->name); 57 SDL_free(data); 58 } 59 60 /* Unlink the window from the list */ 61 if (window->next) { 62 window->next->prev = window->prev; 63 } 64 if (window->prev) { 65 window->prev->next = window->next; 66 } else { 67 _this->windows = window->next; 68 } 69 70 SDL_free(window); 71 }
複製程式碼

從上面的程式碼,我開始懷疑是不是在呼叫SDL_DestroyWindow以後,SDL將視窗給隱藏了,導致在上面顯示視訊的時候,始終顯示不出來的問題。

於是我在自己的測試程式碼中加入如下語句,在呼叫SDL_DestroyWindow以後,我一句:

vDisplay.ShowWindow(SW_SHOWNORMAL);//想顯示視窗給顯示出來,show出來
其中vDisplay對應於顯示的視窗控制元件物件。

 在測試的專案程式碼中加入這行程式碼以後,就完美的解決了專案的問題。

=============================================================

問題2:

當我在MFC的UI訊息相應函式中建立顯示視窗的一些相關資源,在後臺建立的單獨執行緒,用於重新整理和更新顯示資料,然後在UI的關閉訊息響應中釋放和銷燬SDL視窗相關資源。

問題來了,當我使用全屏的時候,出現了後臺更新資料執行緒一直報錯:

複製程式碼
 1     if(o_pSdlHelper->SDL_RenderClear(pDispContext->pStruOut->pRender)<0)
 2     {
 3         char outstr[200]={0};
 4         const char *pbuf=o_pSdlHelper->SDL_GetError();
 5         _snprintf(outstr,sizeof(outstr),"%s \n",pbuf);//這裡出錯資訊為:Reset(): INVALIDCALL
 6         OutputDebugStringA(outstr);
 7         memset(outstr,0,sizeof(outstr));
 8 
 9         return PCI_MC_UNKNOWN_ERR;
10     }
複製程式碼

這就讓我奇怪了,之前我全屏的時候,沒有錯誤啊,現在為什麼有錯?而且顯示視窗畫面也沒有顯示重新整理了!!

於是我想了下和之前的程式碼有什麼不同,唯一的不同在於,我呼叫建立視窗和建立渲染,紋理等等這些操作等資源放在了和更新資料的同一個執行緒中,沒辦法,不知道原因,只有改回原來的程式碼,將建立的程式碼從UI訊息響應中調入和後臺重新整理資料同一個執行緒中。結果奇怪的是,居然這樣全屏操作能執行?

見鬼了,這是啥原因?

//這個原因,還有待查證相關資料和SDL原始碼才能知道。暫時解決了,但不知道原因何在。

=========================================

最近使用sdl老是出現莫名其妙的錯誤,後面從sdl原始碼中知道:

https://bugzilla.libsdl.org/show_bug.cgi?id=1995

/////////////////////////////////////////////////////////////////////////////////////////

sdl做視訊顯示的時候,在不斷調整視窗大小的時候,會出現sdl崩潰,後面跟蹤發現崩潰在sdl的windowsizechange訊息,render->updateview這個函式上.

不過這個崩潰,貌似也只是會在部分機器上崩潰,具體原因還不得而知,但目前我的解決方法是sdl的訊息響應處理函式給註釋掉了:

複製程式碼
 1 #ifdef GWLP_WNDPROC
 2 data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
 3 if (data->wndproc == WIN_WindowProc) {
 4 data->wndproc = NULL;
 5 } else {//modefy by lhp-20150720
 6 //SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
 7 }
 8 #else
 9 data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
10 if (data->wndproc == WIN_WindowProc) {
11 data->wndproc = NULL;
12 } else {//modefy by lhp-20150720-註釋這個sdl訊息接管函式
13 //SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
14 }
15 #endif
複製程式碼