(原)关于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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架