| Summary: | The member 'updateSize' in structure 'D3D_RenderData' will be failed in multi-thread. | ||
|---|---|---|---|
| Product: | SDL | Reporter: | elite_jwp <elite_jwp> |
| Component: | render | Assignee: | Sam Lantinga <slouken> |
| Status: | NEW --- | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | ||
| Version: | 2.0.12 | ||
| Hardware: | x86_64 | ||
| OS: | Windows 10 | ||
| Attachments: |
bug's description
modified bug report snapshot of wrong scene |
||
Created attachment 4315 [details]
modified bug report
Created attachment 4316 [details]
snapshot of wrong scene
|
Created attachment 4314 [details] bug's description For the text format's reason, this report can also be found in attachment file. In my project, a window was created by 'SDL_CreateWindowFrom' in main-thread and rendered in another sub-thread. I used d3d as the render's driver and met a issue which can cause the video area wrong when adjusting the window's size. A snapshot of that scene was shown in attachment file. So I study the codes and try to fix it: When adjusting the window's size, the render will be notified by 'SDL_RendererEventWatch' and it will further call 'D3D_WindowEvent' in which a member named 'updateSize' of D3D_RenderData is set to SDL_TRUE. In SDL_render.c: static int SDLCALL SDL_RendererEventWatch(void *userdata, SDL_Event *event) { SDL_Renderer *renderer = (SDL_Renderer *)userdata; if (event->type == SDL_WINDOWEVENT) { SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); if (window == renderer->window) { if (renderer->WindowEvent) { // here call 'D3D_WindowEvent' renderer->WindowEvent(renderer, &event->window); } ... } } ... return 0; } In SDL_render_d3d.c: static void D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { data->updateSize = SDL_TRUE; } } The member 'updateSize' is used in 'SDL_render_d3d.c:D3D_ActivateRenderer()' to reset d3d device context after the window was adjusted. In SDL_render_d3d.c: static int D3D_ActivateRenderer(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; HRESULT result; if (data->updateSize) { SDL_Window *window = renderer->window; int w, h; Uint32 window_flags = SDL_GetWindowFlags(window); SDL_GetWindowSize(window, &w, &h); data->pparams.BackBufferWidth = w; data->pparams.BackBufferHeight = h; ... if (D3D_Reset(renderer) < 0) { return -1; } data->updateSize = SDL_FALSE; } ... return 0; } So, here exists a problem when adjusting the window's size twice in a small interval time. The pseudo code and the excuting schedule were shown as: main-thread sub-thread (WIN_WindowProc-->SDL_PushEvent-->SDL_RendererEventWatch) (rendering operations) first adjusting to size_1: SDL_RendererEventWatch() { D3D_WindowEvent() { renderer->driverdata->updateSize = SDL_TRUE; } } D3D_ActivateRenderer() { if (data->updateSize) { ... second adjusting to size_2: D3D_Reset(renderer); SDL_RendererEventWatch() { ... D3D_WindowEvent() { ... renderer->driverdata->updateSize = SDL_TRUE; ... } ... } ... ... ... data->updateSize = SDL_FALSE; } ... return 0; } In above excuting schedule, the second adjusting to size_2 was wrongly ignored as the member 'updateSize' was reset to 'SDL_FALSE' in 'D3D_ActivateRenderer' which was excuted in sub-thread. In according to that, I give a suggestion: 1) don't use the member 'updateSize'; 2) modify 'D3D_ActivateRenderer()' as below: static int D3D_ActivateRenderer(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; HRESULT result; SDL_Window *window = renderer->window; int w, h; SDL_GetWindowSize(window, &w, &h); // here compare the new window's size and the device's back buffer's size. if (w != data->pparams.BackBufferWidth || h != data->pparams.BackBufferHeight) { Uint32 window_flags = SDL_GetWindowFlags(window); data->pparams.BackBufferWidth = w; data->pparams.BackBufferHeight = h; if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { SDL_DisplayMode fullscreen_mode; SDL_GetWindowDisplayMode(window, &fullscreen_mode); data->pparams.Windowed = FALSE; data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format); data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate; } else { data->pparams.Windowed = TRUE; data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; data->pparams.FullScreen_RefreshRateInHz = 0; } if (D3D_Reset(renderer) < 0) { return -1; } } if (data->beginScene) { result = IDirect3DDevice9_BeginScene(data->device); if (result == D3DERR_DEVICELOST) { if (D3D_Reset(renderer) < 0) { return -1; } result = IDirect3DDevice9_BeginScene(data->device); } if (FAILED(result)) { return D3D_SetError("BeginScene()", result); } data->beginScene = SDL_FALSE; } return 0; }