zoukankan      html  css  js  c++  java
  • (原)关于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

  • 相关阅读:
    P3391 【模板】文艺平衡树(Splay)
    P4198 楼房重建
    P1491 集合位置
    P3957 跳房子
    P4016 负载平衡问题
    bzoj1077: [SCOI2008]天平 差分约束
    bzoj1151: [CTSC2007]动物园zoo 状压dp
    bzoj1076: [SCOI2008]奖励关 状压dp
    bzoj1226: [SDOI2009]学校食堂Dining 状压dp
    bzoj1879: [Sdoi2009]Bill的挑战 状压dp
  • 原文地址:https://www.cnblogs.com/lihaiping/p/4704836.html
Copyright © 2011-2022 走看看