From 668328a697aaed3a7863c8c7e099e99471774bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Wed, 6 May 2009 19:36:08 +0200 Subject: [PATCH] wined3d: Work around a bad crash in fglrx. --- dlls/wined3d/context.c | 10 ++++------ dlls/wined3d/directx.c | 38 +++++++++++++++++++++++++++++++++++++- dlls/wined3d/state.c | 15 +++++++++++++-- dlls/wined3d/wined3d_gl.h | 1 + 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index a510d2e125b..2c6703f3603 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -895,12 +895,10 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar } } - if(GL_SUPPORT(ARB_POINT_SPRITE)) { - for(s = 0; s < GL_LIMITS(textures); s++) { - GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s)); - glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); - checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"); - } + for(s = 0; s < GL_LIMITS(point_sprite_units); s++) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s)); + glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); + checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"); } LEAVE_GL(); diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 61927fcaea3..d1f851abd1a 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1014,7 +1014,11 @@ static BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { /* GL_ARB_half_float_vertex is a subset of GL_NV_half_float */ gl_info->supported[ARB_HALF_FLOAT_VERTEX] = TRUE; } - + if(gl_info->supported[ARB_POINT_SPRITE]) { + gl_info->max_point_sprite_units = gl_info->max_textures; + } else { + gl_info->max_point_sprite_units = 0; + } } checkGLcall("extension detection\n"); @@ -4031,6 +4035,13 @@ static BOOL match_apple_nonr500ati(const WineD3D_GL_Info *gl_info) { return TRUE; } +static BOOL match_fglrx(const WineD3D_GL_Info *gl_info) { + if(gl_info->gl_vendor != VENDOR_ATI) return FALSE; + if(match_apple(gl_info)) return FALSE; + if(strstr(gl_info->gl_renderer, "DRI")) return FALSE; /* Filter out Mesa DRI drivers */ + return TRUE; +} + static void quirk_arb_constants(WineD3D_GL_Info *gl_info) { TRACE_(d3d_caps)("Using ARB vs constant limit(=%u) for GLSL\n", gl_info->vs_arb_constantsF); gl_info->vs_glsl_constantsF = gl_info->vs_arb_constantsF; @@ -4048,6 +4059,26 @@ static void quirk_apple_glsl_constants(WineD3D_GL_Info *gl_info) { gl_info->reserved_glsl_constants = max(gl_info->reserved_glsl_constants, 12); } +/* fglrx crashes with a very bad kernel panic if GL_POINT_SPRITE_ARB is set to GL_COORD_REPLACE_ARB + * on more than one texture unit. This means that the d3d9 visual point size test will cause a + * kernel panic on any machine running fglrx 9.3(latest that supports r300 to r500 cards). This + * quirk only enables point sprites on the first texture unit. This keeps point sprites working in + * most games, but avoids the crash + * + * A more sophisticated way would be to find all units that need texture coordinates and enable + * point sprites for one if only one is found, and software emulate point sprites in drawStridedSlow + * if more than one unit needs texture coordinates(This requires software ffp and vertex shaders though) + * + * Note that disabling the extension entirely does not gain predictability because there is no point + * sprite capability flag in d3d, so the potential rendering bugs are the same if we disable the extension. + */ +static void quirk_one_point_sprite(WineD3D_GL_Info *gl_info) { + if(gl_info->supported[ARB_POINT_SPRITE]) { + TRACE("Limiting point sprites to one texture unit\n"); + gl_info->max_point_sprite_units = 1; + } +} + static void quirk_ati_dx9(WineD3D_GL_Info *gl_info) { quirk_arb_constants(gl_info); @@ -4146,6 +4177,11 @@ struct driver_quirk quirk_table[] = { match_apple_nonr500ati, quirk_texcoord_w, "Init texcoord .w for Apple ATI >= r600 GPU driver" + }, + { + match_fglrx, + quirk_one_point_sprite, + "Fglrx point sprite crash workaround" } }; diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index b1fbadf5d11..ad1593c7196 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1503,14 +1503,25 @@ static void state_lastpixel(DWORD state, IWineD3DStateBlockImpl *stateblock, Win } static void state_pointsprite_w(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + BOOL warned = FALSE; /* TODO: NV_POINT_SPRITE */ - if (stateblock->renderState[WINED3DRS_POINTSPRITEENABLE]) { - TRACE("Point sprites not supported\n"); + if (!warned && stateblock->renderState[WINED3DRS_POINTSPRITEENABLE]) { + /* A FIXME, not a WARN because point sprites should be software emulated if not supported by HW */ + FIXME("Point sprites not supported\n"); + warned = TRUE; } } static void state_pointsprite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { if (stateblock->renderState[WINED3DRS_POINTSPRITEENABLE]) { + BOOL warned = FALSE; + if(GL_LIMITS(point_sprite_units) < GL_LIMITS(textures) && !warned) { + if(use_ps(stateblock) || stateblock->lowest_disabled_stage > GL_LIMITS(point_sprite_units)) { + FIXME("The app uses point sprite texture coordinates on more units than supported by the driver\n"); + warned = TRUE; + } + } + glEnable(GL_POINT_SPRITE_ARB); checkGLcall("glEnable(GL_POINT_SPRITE_ARB)"); } else { diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index 20723910bf7..1a9c9251899 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -3933,6 +3933,7 @@ typedef struct _WineD3D_GL_Info { UINT max_texture_size; UINT max_texture3d_size; float max_pointsize, max_pointsizemin; + UINT max_point_sprite_units; UINT max_blends; UINT max_anisotropy; UINT max_glsl_varyings;