From 22319c7f9ede57d8f6a7ed7939b9b620ff2d4943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Tue, 18 Jun 2013 16:17:19 +0200 Subject: [PATCH] wined3d: Work around broken FFP fog with ARB shaders. --- dlls/wined3d/arb_program_shader.c | 49 ++++++++++++-- dlls/wined3d/directx.c | 105 ++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 148 insertions(+), 7 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 3082ba45f64..8984e91ea84 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -278,6 +278,7 @@ struct shader_arb_ctx_priv BOOL muted; unsigned int num_loops, loop_depth, num_ifcs; int aL; + BOOL custom_linear_fog; unsigned int vs_clipplanes; BOOL footer_written; @@ -1160,7 +1161,8 @@ static void shader_arb_get_register_name(const struct wined3d_shader_instruction break; case WINED3DSPR_COLOROUT: - if (ctx->cur_ps_args->super.srgb_correction && !reg->idx[0].offset) + if ((ctx->cur_ps_args->super.srgb_correction || ctx->custom_linear_fog) + && !reg->idx[0].offset) { strcpy(register_name, "TMP_COLOR"); } @@ -3559,6 +3561,14 @@ static void init_ps_input(const struct wined3d_shader *shader, } } +static void arbfp_add_linear_fog(struct wined3d_shader_buffer *buffer, + const char *fragcolor, const char *tmp) +{ + shader_addline(buffer, "SUB %s.x, state.fog.params.z, fragment.fogcoord.x;\n", tmp); + shader_addline(buffer, "MUL_SAT %s.x, %s.x, state.fog.params.w;\n", tmp, tmp); + shader_addline(buffer, "LRP %s.rgb, %s.x, %s, state.fog.color;\n", fragcolor, tmp, fragcolor); +} + /* Context activation is done by the caller. */ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, const struct wined3d_gl_info *gl_info, struct wined3d_shader_buffer *buffer, @@ -3622,6 +3632,7 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, priv_ctx.cur_np2fixup_info = &compiled->np2fixup_info; init_ps_input(shader, args, &priv_ctx); list_init(&priv_ctx.control_frames); + priv_ctx.custom_linear_fog = FALSE; /* Avoid enabling NV_fragment_program* if we do not need it. * @@ -3674,6 +3685,11 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, case WINED3D_FFP_PS_FOG_OFF: break; case WINED3D_FFP_PS_FOG_LINEAR: + if (gl_info->quirks & WINED3D_QUIRK_BROKEN_ARB_FOG) + { + priv_ctx.custom_linear_fog = TRUE; + break; + } shader_addline(buffer, "OPTION ARB_fog_linear;\n"); break; case WINED3D_FFP_PS_FOG_EXP: @@ -3703,7 +3719,7 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, } else { - if (args->super.srgb_correction) + if (args->super.srgb_correction || priv_ctx.custom_linear_fog) { if (shader->u.ps.color0_mov) { @@ -3854,6 +3870,9 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, priv_ctx.target_version >= NV2); } + if (priv_ctx.custom_linear_fog) + arbfp_add_linear_fog(buffer, fragcolor, "TA"); + if(strcmp(fragcolor, "result.color")) { shader_addline(buffer, "MOV result.color, %s;\n", fragcolor); } @@ -6147,6 +6166,7 @@ static GLuint gen_arbfp_ffp_shader(const struct ffp_frag_settings *settings, con BOOL op_equal; const char *final_combiner_src = "ret"; GLint pos; + BOOL custom_linear_fog = FALSE; /* Find out which textures are read */ for (stage = 0; stage < MAX_TEXTURES; ++stage) @@ -6219,7 +6239,15 @@ static GLuint gen_arbfp_ffp_shader(const struct ffp_frag_settings *settings, con switch (settings->fog) { case WINED3D_FFP_PS_FOG_OFF: break; - case WINED3D_FFP_PS_FOG_LINEAR: shader_addline(&buffer, "OPTION ARB_fog_linear;\n"); break; + case WINED3D_FFP_PS_FOG_LINEAR: + if (gl_info->quirks & WINED3D_QUIRK_BROKEN_ARB_FOG) + { + custom_linear_fog = TRUE; + break; + } + shader_addline(&buffer, "OPTION ARB_fog_linear;\n"); + break; + case WINED3D_FFP_PS_FOG_EXP: shader_addline(&buffer, "OPTION ARB_fog_exp;\n"); break; case WINED3D_FFP_PS_FOG_EXP2: shader_addline(&buffer, "OPTION ARB_fog_exp2;\n"); break; default: FIXME("Unexpected fog setting %d\n", settings->fog); @@ -6384,12 +6412,19 @@ static GLuint gen_arbfp_ffp_shader(const struct ffp_frag_settings *settings, con } } - if(settings->sRGB_write) { + if (settings->sRGB_write || custom_linear_fog) + { shader_addline(&buffer, "MAD ret, fragment.color.secondary, specular_enable, %s;\n", final_combiner_src); - arbfp_add_sRGB_correction(&buffer, "ret", "arg0", "arg1", "arg2", "tempreg", FALSE); + if (settings->sRGB_write) + arbfp_add_sRGB_correction(&buffer, "ret", "arg0", "arg1", "arg2", "tempreg", FALSE); + if (custom_linear_fog) + arbfp_add_linear_fog(&buffer, "ret", "arg0"); shader_addline(&buffer, "MOV result.color, ret;\n"); - } else { - shader_addline(&buffer, "MAD result.color, fragment.color.secondary, specular_enable, %s;\n", final_combiner_src); + } + else + { + shader_addline(&buffer, "MAD result.color, fragment.color.secondary, specular_enable, %s;\n", + final_combiner_src); } /* Footer */ diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 760fa34f392..83208527a40 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -791,6 +791,101 @@ static BOOL match_r200(const struct wined3d_gl_info *gl_info, const char *gl_ren return FALSE; } +static BOOL match_broken_arb_fog(const struct wined3d_gl_info *gl_info, const char *gl_renderer, + enum wined3d_gl_vendor gl_vendor, enum wined3d_pci_vendor card_vendor, enum wined3d_pci_device device) +{ + DWORD data[4]; + GLuint tex, fbo; + GLenum status; + float color[4] = {0.0f, 1.0f, 0.0f, 0.0f}; + GLuint prog; + GLint err_pos; + static const char *program_code = + "!!ARBfp1.0\n" + "OPTION ARB_fog_linear;\n" + "MOV result.color, {1.0, 0.0, 0.0, 0.0};\n" + "END\n"; + + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) + return FALSE; + if (!gl_info->supported[ARB_FRAGMENT_PROGRAM]) + return FALSE; + + gl_info->gl_ops.gl.p_glGenTextures(1, &tex); + gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, tex); + gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + checkGLcall("glTexImage2D"); + + gl_info->fbo_ops.glGenFramebuffers(1, &fbo); + gl_info->fbo_ops.glBindFramebuffer(GL_FRAMEBUFFER, fbo); + gl_info->fbo_ops.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + checkGLcall("glFramebufferTexture2D"); + + status = gl_info->fbo_ops.glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) ERR("FBO status %#x\n", status); + checkGLcall("glCheckFramebufferStatus"); + + gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 1.0f, 0.0f); + gl_info->gl_ops.gl.p_glClear(GL_COLOR_BUFFER_BIT); + checkGLcall("glClear"); + gl_info->gl_ops.gl.p_glViewport(0, 0, 4, 1); + checkGLcall("glViewport"); + + gl_info->gl_ops.gl.p_glEnable(GL_FOG); + gl_info->gl_ops.gl.p_glFogf(GL_FOG_START, 0.5f); + gl_info->gl_ops.gl.p_glFogf(GL_FOG_END, 0.5f); + gl_info->gl_ops.gl.p_glFogi(GL_FOG_MODE, GL_LINEAR); + gl_info->gl_ops.gl.p_glHint(GL_FOG_HINT, GL_NICEST); + gl_info->gl_ops.gl.p_glFogfv(GL_FOG_COLOR, color); + checkGLcall("fog setup"); + + GL_EXTCALL(glGenProgramsARB(1, &prog)); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog)); + GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program_code), program_code)); + gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); + checkGLcall("Test fragment program setup"); + + gl_info->gl_ops.gl.p_glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err_pos); + if (err_pos != -1) + { + const char *error_str; + error_str = (const char *)gl_info->gl_ops.gl.p_glGetString(GL_PROGRAM_ERROR_STRING_ARB); + FIXME("Fog test program error at position %d: %s\n\n", err_pos, debugstr_a(error_str)); + } + + gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP); + gl_info->gl_ops.gl.p_glVertex3f(-1.0f, -1.0f, 0.0f); + gl_info->gl_ops.gl.p_glVertex3f( 1.0f, -1.0f, 1.0f); + gl_info->gl_ops.gl.p_glVertex3f(-1.0f, 1.0f, 0.0f); + gl_info->gl_ops.gl.p_glVertex3f( 1.0f, 1.0f, 1.0f); + gl_info->gl_ops.gl.p_glEnd(); + checkGLcall("ARBfp fog test draw"); + + gl_info->gl_ops.gl.p_glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + checkGLcall("glGetTexImage"); + data[0] &= 0x00ffffff; + data[1] &= 0x00ffffff; + data[2] &= 0x00ffffff; + data[3] &= 0x00ffffff; + + gl_info->fbo_ops.glBindFramebuffer(GL_FRAMEBUFFER, 0); + gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, 0); + + gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo); + gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex); + gl_info->gl_ops.gl.p_glDisable(GL_FOG); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0)); + gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_PROGRAM_ARB); + GL_EXTCALL(glDeleteProgramsARB(1, &prog)); + checkGLcall("ARBfp fog test teardown"); + + TRACE("Fog test data: %08x %08x %08x %08x\n", data[0], data[1], data[2], data[3]); + return data[0] != 0x00ff0000 || data[3] != 0x0000ff00; +} + static void quirk_apple_glsl_constants(struct wined3d_gl_info *gl_info) { /* MacOS needs uniforms for relative addressing offsets. This can accumulate to quite a few uniforms. @@ -914,6 +1009,11 @@ static void quirk_r200_constants(struct wined3d_gl_info *gl_info) gl_info->reserved_arb_constants = max(gl_info->reserved_arb_constants, 1); } +static void quirk_broken_arb_fog(struct wined3d_gl_info *gl_info) +{ + gl_info->quirks |= WINED3D_QUIRK_BROKEN_ARB_FOG; +} + struct driver_quirk { BOOL (*match)(const struct wined3d_gl_info *gl_info, const char *gl_renderer, @@ -999,6 +1099,11 @@ static const struct driver_quirk quirk_table[] = quirk_r200_constants, "r200 vertex shader constants" }, + { + match_broken_arb_fog, + quirk_broken_arb_fog, + "ARBfp fogstart == fogend workaround" + }, }; /* Certain applications (Steam) complain if we report an outdated driver version. In general, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 1ed258731a3..dca0d616926 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -62,6 +62,7 @@ #define WINED3D_QUIRK_BROKEN_RGBA16 0x00000040 #define WINED3D_QUIRK_INFO_LOG_SPAM 0x00000080 #define WINED3D_QUIRK_LIMITED_TEX_FILTERING 0x00000100 +#define WINED3D_QUIRK_BROKEN_ARB_FOG 0x00000200 /* Texture format fixups */