-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Am 2013-06-18 12:53, schrieb Henri Verbeet: > (And that one is only supported by Mesa anyway, so there should be > no reason to not just fix the driver instead.) Well, in theory. In practice I'd need the register documentation. I had a very quick look at the mesa code, and it isn't as simple as removing something like "if (start == end) annoy_wine();". There's a register flag R200_FOG_TABLE that may or may not provide what d3d wants.
Supposedly the register documentation of r200 is available, but Google doesn't find it. >> I can deal with ARB in another way, by implementing the fog >> equation myself instead of using #option ARB_fog_linear. That >> would throw pre-sm2 hardware under the bus though. >> > Yeah, we probably don't want that. I think the value of the ARB > program backend is limited, but it's main target should be pre-SM2 > hardware that can't do GLSL. (And potentially still has dedicated > fog hardware.) Since I'm still maintaining the ARB code, I prefer something like the attached patch over failing tests any time. (It's not quite done yet. The patch needs splitting, the quirk test should test an ARB shader and I'll probably limit the custom code to start == end cases.) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.20 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQIcBAEBAgAGBQJRwE4GAAoJEN0/YqbEcdMwweMP/3IZhKiTeaVnhmVg1nfHBpjG hegDyIfFKVa1Xy2yxV3fYiKhYxuXHzHRl7pQ8qJlNLttoq2i/MMYZuQcZ9Ww3xWd sHs/UD+RTQgGasNxYYx1Ody/yjHt+fx+98rXSR2b31/oyjmzijnLZqmSr/8JSB3/ JYSNkKSW91GG/IAlcp2C4QZZo+upg4t29+WPHn4aeQeYX/oxlY6rQFVrlWwb7UBN FQL9WV29ah8Wb3jeGp5UZM0Z8C83cu5efRH5kyGsdM/8YcPzqHAoHuFv3vmnpJxi dze41y0RqgZMsocFog/VlegZqCheH1alDEmRuEkl1/1jIBGgHnJsw2FggjJ+veEg zkGmt9GXPjn2u0+gcj48a2FDpLZw5UAdwaI5jKyoDVsTY/cSk8RdoxlqcQVcu6BI xWx1XaAyjPwg81mvVyugyR0B+GSIsfXXhYl1kCExwLXuFam4Vn0RkPbwcdj1WHem g3ufGT9FHGeftCmnXMLR9ETSiHdgnB6/oabwe7fc5zLBAGfgi8fTYB4DZvXpqWas ZWAcunRRpDuIA4w7xqjYFqWNF8J6WIouki1sUrCvd/lNtBXM9ieRHgG28qY8h9JO 9xeC7UCh950juECgocTYz3W1qqsrEL9fmmbVp0HdltiBtqmTBfFSxuDtfWIN7ViZ 9HsSdt/Bw0tiXy3uRvlN =8SHq -----END PGP SIGNATURE-----
>From 63d8e32ad4dc3606f641472f4844b5e439174196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <ste...@codeweavers.com> Date: Fri, 14 Jun 2013 12:19:24 +0200 Subject: [PATCH 1/8] wined3d: Handle fog_start==fog_end with table fog(try 2) Reply-To: wine-devel <wine-devel@winehq.org> Wizard101 triggers this when running on a GPU that does not support shader model 3. try 2: Make the fogend increase code a quirk rather than using it unconditionally. GLSL doesn't need it because it implements the fog equation itself, and some OSX drivers handle fog_start == fog_end correctly with fixed function fog. Tested as usual on Geforce9 (OSX, Linux), Geforce7 (Linux), r300g, r600g, i965 (OSX), r200. The follow-up tests pass on all GPUs except r200. The fog table works correctly in the dx7 sdk mfcfog example on r200, and I didn't spend a lot of time trying to find out why my test is broken on that old card. --- dlls/wined3d/arb_program_shader.c | 56 +++++++++++++++++++++++----- dlls/wined3d/directx.c | 78 +++++++++++++++++++++++++++++++++++++++ dlls/wined3d/glsl_shader.c | 4 +- dlls/wined3d/state.c | 13 +++++-- dlls/wined3d/wined3d_private.h | 1 + 5 files changed, 139 insertions(+), 13 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index fd2df68..8c67f1c 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) { @@ -3849,11 +3865,15 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, /* Base Shader Body */ shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx); - if(args->super.srgb_correction) { + if (args->super.srgb_correction) + { arbfp_add_sRGB_correction(buffer, fragcolor, srgbtmp[0], srgbtmp[1], srgbtmp[2], srgbtmp[3], 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 +6167,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 +6240,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 +6413,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 result.color, fragment.color.secondary, specular_enable, %s;\n", + final_combiner_src); + } + else + { 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); } /* Footer */ @@ -6513,6 +6549,8 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi static void state_arbfp_fog(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { enum fogsource new_source; + DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; + DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); @@ -6541,7 +6579,7 @@ static void state_arbfp_fog(struct wined3d_context *context, const struct wined3 new_source = FOGSOURCE_FFP; } - if (new_source != context->fog_source) + if (new_source != context->fog_source || fogstart == fogend) { context->fog_source = new_source; state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART)); diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 760fa34..bcf90f7 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -791,6 +791,74 @@ static BOOL match_r200(const struct wined3d_gl_info *gl_info, const char *gl_ren return FALSE; } +static BOOL match_broken_ffp_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}; + + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) 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); + gl_info->gl_ops.gl.p_glViewport(0, 0, 4, 1); + + 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_info->gl_ops.gl.p_glColor3f(1.0f, 0.0f, 0.0f); + 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("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); + checkGLcall("glBindTexture"); + + gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo); + gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex); + checkGLcall("glDeleteTextures"); + gl_info->gl_ops.gl.p_glDisable(GL_FOG); + checkGLcall("glDisable(GL_FOG)"); + + 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 +982,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_ffp_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 +1072,11 @@ static const struct driver_quirk quirk_table[] = quirk_r200_constants, "r200 vertex shader constants" }, + { + match_broken_ffp_fog, + quirk_broken_ffp_fog, + "fogstart == fogend workaround" + }, }; /* Certain applications (Steam) complain if we report an outdated driver version. In general, diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index e14d7ab..ad9be6a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -7086,6 +7086,8 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, { BOOL use_vshader = use_vs(state); enum fogsource new_source; + DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; + DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; context->select_shader = 1; context->load_constants = 1; @@ -7107,7 +7109,7 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, new_source = FOGSOURCE_FFP; } - if (new_source != context->fog_source) + if (new_source != context->fog_source || fogstart == fogend) { context->fog_source = new_source; state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART)); diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index ffce803..5d6355b 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1043,8 +1043,13 @@ void state_fogstartend(struct wined3d_context *context, const struct wined3d_sta fogstart = tmpvalue.f; tmpvalue.d = state->render_states[WINED3D_RS_FOGEND]; fogend = tmpvalue.f; - /* In GL, fogstart == fogend disables fog, in D3D everything's fogged.*/ - if(fogstart == fogend) { + /* Special handling for fogstart == fogend. In d3d with vertex + * fog, everything is fogged. With table fog, everything with + * fog_coord < fog_start is unfogged, and fog_coord > fog_start + * is fogged. Windows drivers disagree when fog_coord == fog_start. */ + if (state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE + && fogstart == fogend) + { fogstart = -INFINITY; fogend = 0.0f; } @@ -1072,6 +1077,8 @@ void state_fog_fragpart(struct wined3d_context *context, const struct wined3d_st { const struct wined3d_gl_info *gl_info = context->gl_info; enum fogsource new_source; + DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; + DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); @@ -1217,7 +1224,7 @@ void state_fog_fragpart(struct wined3d_context *context, const struct wined3d_st glEnableWINE(GL_FOG); checkGLcall("glEnable GL_FOG"); - if (new_source != context->fog_source) + if (new_source != context->fog_source || fogstart == fogend) { context->fog_source = new_source; state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART)); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 1ed2587..dca0d61 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 */ -- 1.8.1.5
0001-wined3d-Handle-fog_start-fog_end-with-table-fog-try-.patch.sig
Description: PGP signature