(原)關於sdl在部分機器上做視頻顯示,改變顯示窗口大小會崩潰


今天測試人員反應,之前做的視頻繪圖顯示,會在她機器上,會出現崩潰現象,最后我在她機器上對代碼進行跟蹤,發現在某種情況,確實會崩潰。

最主要的原因是,視頻顯示窗口變成非活動窗口的時候,sdl內部會循環消息處理,當處理WM_WINDOWPOSCHANGED消息的時候,就會出現崩潰,崩潰的代碼在,D3D_UpdateViewport函數內部的IDirect3DDevice9_SetViewport函數。

當初我為了解決這個問題,覺得是sdl內部接管了窗口的消息處理函數引起的,因為實際上我們這里也沒用到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 {
 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 {
13 //SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
14 }
15 #endif

結果是,崩潰的問題看似解決了,在她那台機器和其他機器上也不會出現崩潰,但有一個其他的問題引入了,就是sdl內部不能響應事件處理函數,這樣當我們從視頻顯示畫面變為全屏的時候,出現了一個問題,全屏的時候,畫面質量很差,線條和邊界畫面出現明顯的鋸齒現象。所以最后此方法沒行通,只能再找解決辦法:

分析sdl內部消息的源碼:

  1 ///////////////SDL消息分析//////////////////////////
  2 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)//這個函數是SDL接管windows窗口消息的函數
  3 {
  4 ...
  5         case WM_WINDOWPOSCHANGED://會觸發這個消息
  6         {
  7             RECT rect;
  8             int x, y;
  9             int w, h;
 10 
 11             if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
 12                 break;
 13             }
 14             ClientToScreen(hwnd, (LPPOINT) & rect);
 15             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
 16 
 17             WIN_UpdateClipCursor(data->window);
 18 
 19             x = rect.left;
 20             y = rect.top;
 21             //這里先發送窗口移動消息,移動x,y的坐標位置
 22             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
 23 
 24             w = rect.right - rect.left;
 25             h = rect.bottom - rect.top;
 26             //然后這里發送尺寸修改消息,修改顯示窗口的w,h
 27             //屏蔽掉這個消息之后,全屏會出現鋸齒,視頻渲染效果很差
 28             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,h);//發送這個事件
 29         }
 30         break;
 31 ...
 32 }
 33     
 34 ////////////////////////////////////////////////////
 35 int SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1,int data2)
 36 {
 37     case SDL_WINDOWEVENT_MOVED:        //處理
 38         if (SDL_WINDOWPOS_ISUNDEFINED(data1) ||
 39             SDL_WINDOWPOS_ISUNDEFINED(data2)) {
 40             return 0;
 41         }
 42         if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
 43             window->windowed.x = data1;
 44             window->windowed.y = data2;
 45         }
 46         if (data1 == window->x && data2 == window->y) {
 47             return 0;
 48         }
 49         window->x = data1;
 50         window->y = data2;
 51         break;
 52     case SDL_WINDOWEVENT_RESIZED://處理
 53         if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
 54             window->windowed.w = data1;
 55             window->windowed.h = data2;
 56         }
 57         if (data1 == window->w && data2 == window->h) {
 58             return 0;
 59         }
 60         window->w = data1;
 61         window->h = data2;
 62         SDL_OnWindowResized(window);//進入這個事件處理會崩潰-lhp
 63             {//注意這個函數里面也是發送一個窗口大小改變的消息
 64                 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);//發送改變消息-LHP
 65             }
 66         break;
 67         /////////////////Break出來以后////////////////////////
 68     if (SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE) {
 69         SDL_Event event;
 70         event.type = SDL_WINDOWEVENT;
 71         event.window.event = windowevent;
 72         event.window.data1 = data1;
 73         event.window.data2 = data2;
 74         event.window.windowID = window->id;
 75 
 76         /* Fixes queue overflow with resize events that aren't processed */
 77         if (windowevent == SDL_WINDOWEVENT_RESIZED) {//2)然后觸發這個消息事件
 78             SDL_FilterEvents(RemovePendingResizedEvents, &event);
 79         }
 80         if (windowevent == SDL_WINDOWEVENT_SIZE_CHANGED) {//3)最后觸發這個消息事件
 81             SDL_FilterEvents(RemovePendingSizeChangedEvents, &event);
 82         }
 83         if (windowevent == SDL_WINDOWEVENT_MOVED) {//1)首先觸發這個消息事件
 84             SDL_FilterEvents(RemovePendingMoveEvents, &event);
 85         }
 86 
 87         posted = (SDL_PushEvent(&event) > 0);
 88     }
 89 }    
 90 
 91 //////////////////////////////////////
 92 //上面的分析是消息的觸發,下面看看消息捕捉以后消息的處理分析    
 93 //SDL的渲染事件watch函數用於捕捉事件
 94 static int SDL_RendererEventWatch(void *userdata, SDL_Event *event)
 95 {
 96     SDL_Renderer *renderer = (SDL_Renderer *)userdata;
 97         if (event->type == SDL_WINDOWEVENT) {
 98         SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
 99         if (window == renderer->window) {
100             if (renderer->WindowEvent) {
101                 renderer->WindowEvent(renderer, &event->window);
102                 //這個函數的內部實現源碼如下:
103                         static void D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
104                         {
105                             D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
106 
107                             if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
108                                 data->updateSize = SDL_TRUE;
109                             }
110                         }
111             }
112 
113             if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
114                 if (renderer->logical_w) {
115                     UpdateLogicalSize(renderer);
116                 } else {
117                     /* Window was resized, reset viewport */
118                     int w, h;
119 
120                     if (renderer->GetOutputSize) {
121                         renderer->GetOutputSize(renderer, &w, &h);
122                     } else {
123                         SDL_GetWindowSize(renderer->window, &w, &h);
124                     }
125 
126                     if (renderer->target) {
127                         renderer->viewport_backup.x = 0;
128                         renderer->viewport_backup.y = 0;
129                         renderer->viewport_backup.w = w;
130                         renderer->viewport_backup.h = h;
131                     } else {
132                         renderer->viewport.x = 0;
133                         renderer->viewport.y = 0;
134                         renderer->viewport.w = w;
135                         renderer->viewport.h = h;
136                         //這個函數會導致崩潰,在部分機器上,設置視區區域
137                         //最后我把這個地方的這個函數給注釋掉了。
138                         //modefy by lhp -20150805
139                         //renderer->UpdateViewport(renderer);//崩潰的地方-LHP
140                     }
141                 }
142             } 
143         }
144         }
145 
146 }
147 //updateViewport
148 static int D3D_UpdateViewport(SDL_Renderer * renderer)
149 {
150     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
151 
152     viewport.X = renderer->viewport.x;
153     viewport.Y = renderer->viewport.y;
154     viewport.Width = renderer->viewport.w;
155     viewport.Height = renderer->viewport.h;
156     viewport.MinZ = 0.0f;
157     viewport.MaxZ = 1.0f;
158     //這里是跟蹤的時候,調用崩潰的函數,在部分機器上,當窗口視區改變大小的時候,這個函數會崩潰
159     IDirect3DDevice9_SetViewport(data->device, &viewport);
160 
161 }
162     
163 
164 
165 
166 
167 
168 
169 
170     

當時想從D3D_UpdateViewport函數入手,但發現我改的幾個版本出來的效果,依然會崩潰,例如加clear,getviewport函數看會失敗不,等等操作函數,都無用,沒辦法,只有在消息函數里面處理,把更新顯示視區的函數給屏蔽掉。(這個地方做修改也是影響最小的屏蔽,因為這個地方是針對SDL_WINDOWEVENT_SIZE_CHANGED這個事件。)

 

轉載請注明出處:http://www.cnblogs.com/lihaiping/p/4704836.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM