Fix crash when other app prevent us to recreate the primary DirectDraw surface (fix #542)

This commit is contained in:
David Capello 2014-11-24 20:24:28 -03:00
parent 80501899ca
commit 2de3f7caff
3 changed files with 50 additions and 26 deletions

View File

@ -307,34 +307,41 @@ void gfx_directx_destroy_surface(DDRAW_SURFACE *surf)
int gfx_directx_restore_surface(DDRAW_SURFACE *surf)
{
LPDIRECTDRAWSURFACE2 new_id;
int type = (surf->flags & DDRAW_SURFACE_TYPE_MASK);
HRESULT hr;
hr = IDirectDrawSurface2_Restore(surf->id);
if (FAILED(hr)) {
LPDIRECTDRAWSURFACE2 new_id;
if (surf->id != 0) {
hr = IDirectDrawSurface2_Restore(surf->id);
if (SUCCEEDED(hr))
return 0; /* We were able to restore the surface successfully */
hr = IDirectDrawSurface2_Release(surf->id);
if (FAILED(hr))
return -1;
hr = IDirectDrawSurface2_Release(surf->id);
if (FAILED(hr))
return -1;
}
new_id = create_directdraw2_surface(
surf->w, surf->h, ddpixel_format, type, 0);
if (!new_id) {
surf->id = 0;
return -1;
}
/* In this case, the surface must be recreated because:
1) We weren't able to restore it with IDirectDrawSurface2_Restore()
2) We weren't able to re-create it in a previous
gfx_directx_restore_surface() call
*/
new_id = create_directdraw2_surface(
surf->w, surf->h, ddpixel_format, type, 0);
if (!new_id) {
surf->id = 0;
return -1;
}
surf->id = new_id;
surf->id = new_id;
if (type == DDRAW_SURFACE_PRIMARY) {
hr = IDirectDrawSurface_SetClipper(surf->id, ddclipper);
if (FAILED(hr))
return -1;
}
}
if (type == DDRAW_SURFACE_PRIMARY) {
hr = IDirectDrawSurface_SetClipper(surf->id, ddclipper);
if (FAILED(hr))
return -1;
}
return 0;
return 0;
}

View File

@ -207,8 +207,10 @@ static void paint_win(RECT *rect)
/* we may have lost the DirectDraw surfaces
* (e.g after the monitor has gone to low power)
*/
if (IDirectDrawSurface2_IsLost(gfx_directx_primary_surface->id) == DDERR_SURFACELOST)
if (gfx_directx_primary_surface->id == 0 ||
IDirectDrawSurface2_IsLost(gfx_directx_primary_surface->id) == DDERR_SURFACELOST) {
switch_in_win();
}
/* clip the rectangle */
rect->right = MIN(rect->right, gfx_directx_win.w);
@ -249,9 +251,14 @@ static void update_matching_window(RECT *rect)
ClientToScreen(allegro_wnd, &dest_rect.p);
ClientToScreen(allegro_wnd, &dest_rect.p + 1);
/* blit offscreen backbuffer to the window */
IDirectDrawSurface2_Blt(gfx_directx_primary_surface->id, &dest_rect.r,
offscreen_surface->id, rect, 0, NULL);
/* Blit offscreen backbuffer to the window.
The ID can be 0 when the primary surface is lost and we weren't
able to restore & recreate it in gfx_directx_restore_surface().
*/
if (gfx_directx_primary_surface->id != 0) {
IDirectDrawSurface2_Blt(gfx_directx_primary_surface->id, &dest_rect.r,
offscreen_surface->id, rect, 0, NULL);
}
_exit_gfx_critical();
}
@ -372,8 +379,10 @@ static void update_colorconv_window(RECT *rect)
if (direct) {
/* blit directly to the primary surface without clipping */
ddsurf_blit_ex(gfx_directx_primary_surface->id, &dest_rect.r,
offscreen_surface->id, &src_rect);
if (gfx_directx_primary_surface->id != 0) {
ddsurf_blit_ex(gfx_directx_primary_surface->id, &dest_rect.r,
offscreen_surface->id, &src_rect);
}
}
else {
/* blit to the window using GDI */

View File

@ -10,6 +10,8 @@
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintwin.h"
#include "wddraw.h"
#ifndef ALLEGRO_WINDOWS
#error something is wrong with the makefile
#endif
@ -333,6 +335,12 @@ void _al_win_mouse_handle_move(HWND hwnd, int x, int y)
{
_enter_critical();
/* Try to restore the primary surface as soon as possible if we
have lost it and were not able to recreate it */
if (gfx_directx_primary_surface && gfx_directx_primary_surface->id == 0) {
restore_all_ddraw_surfaces();
}
_mouse_x = CLAMP(mouse_minx, x, mouse_maxx);
_mouse_y = CLAMP(mouse_miny, y, mouse_maxy);