今天測試人員反應,之前做的視頻繪圖顯示,會在她機器上,會出現崩潰現象,最后我在她機器上對代碼進行跟蹤,發現在某種情況,確實會崩潰。
最主要的原因是,視頻顯示窗口變成非活動窗口的時候,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