wined3d: Try to detect the polygon offset scale value.
FEAR draws the same geometry twice, the second time using zfunc=equal. In both cases it sets a huge depth bias of -0.5, presumably to get better precision for the fragile Z comparison. The GL polygon offset we set ends up being so large that it pulls the geometry into the negative Z range. It isn't clipped (or no longer, older NV drivers probably had a separate bug there), but the Z value gets clamped to 0.0 in the first draw and doesn't match the incoming Z in the second draw.
This commit is contained in:
parent
f529a5aaae
commit
34d8b987c4
|
@ -446,7 +446,8 @@ static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const
|
|||
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
|
||||
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
|
||||
}
|
||||
else if (prev && prev->format->depth_size != op->view->format->depth_size)
|
||||
else if (prev && (prev->format_flags & WINED3DFMT_FLAG_FLOAT)
|
||||
!= (op->view->format_flags & WINED3DFMT_FLAG_FLOAT))
|
||||
{
|
||||
device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
|
||||
}
|
||||
|
|
|
@ -5903,6 +5903,10 @@ static BOOL wined3d_adapter_init(struct wined3d_adapter *adapter, UINT ordinal)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gl_info->fixed_polyoffset_scale = wined3d_adapter_find_polyoffset_scale(&caps_gl_ctx, GL_DEPTH_COMPONENT);
|
||||
if (gl_info->supported[ARB_DEPTH_BUFFER_FLOAT])
|
||||
gl_info->float_polyoffset_scale = wined3d_adapter_find_polyoffset_scale(&caps_gl_ctx, GL_DEPTH32F_STENCIL8);
|
||||
|
||||
adapter->vram_bytes = adapter->driver_info.vram_bytes;
|
||||
adapter->vram_bytes_used = 0;
|
||||
TRACE("Emulating 0x%s bytes of video ram.\n", wine_dbgstr_longlong(adapter->vram_bytes));
|
||||
|
|
|
@ -1632,11 +1632,17 @@ static void state_scissor(struct wined3d_context *context, const struct wined3d_
|
|||
* OpenGL the bias is specified in units of "the smallest value that is
|
||||
* guaranteed to produce a resolvable offset for a given implementation". To
|
||||
* convert from D3D to GL we need to divide the D3D depth bias by that value.
|
||||
* There's no practical way to retrieve that value from a given GL
|
||||
* implementation, but the D3D application has essentially the same problem,
|
||||
* which makes a guess of the depth buffer format's highest possible value a
|
||||
* reasonable guess. Note that SLOPESCALEDEPTHBIAS is a scaling factor for the
|
||||
* depth slope, and doesn't need to be scaled. */
|
||||
* We try to detect the value from GL with test draws. On most drivers (r300g,
|
||||
* 600g, Nvidia, i965 on Mesa) the value is 2^23 for fixed point depth buffers,
|
||||
* for r200 and i965 on OSX it is 2^24, for r500 on OSX it is 2^22. For floating
|
||||
* point buffers it is 2^22, 2^23 or 2^24 depending on the GPU. The value does
|
||||
* not depend on the depth buffer precision on any driver.
|
||||
*
|
||||
* Two games that are picky regarding depth bias are Mass Effect 2 (flickering
|
||||
* decals) and F.E.A.R and F.E.A.R. 2 (semi-transparent guns).
|
||||
*
|
||||
* Note that SLOPESCALEDEPTHBIAS is a scaling factor for the depth slope, and
|
||||
* doesn't need to be scaled to account for GL vs D3D differences. */
|
||||
static void state_depthbias(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
|
||||
{
|
||||
const struct wined3d_gl_info *gl_info = context->gl_info;
|
||||
|
@ -1669,10 +1675,13 @@ static void state_depthbias(struct wined3d_context *context, const struct wined3
|
|||
{
|
||||
if (depth)
|
||||
{
|
||||
const struct wined3d_format *fmt = depth->format;
|
||||
scale = powf(2, fmt->depth_size) - 1;
|
||||
if (depth->format_flags & WINED3DFMT_FLAG_FLOAT)
|
||||
scale = gl_info->float_polyoffset_scale;
|
||||
else
|
||||
scale = gl_info->fixed_polyoffset_scale;
|
||||
|
||||
TRACE("Depth format %s, using depthbias scale of %.8e.\n",
|
||||
debug_d3dformat(fmt->id), scale);
|
||||
debug_d3dformat(depth->format->id), scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2707,6 +2707,100 @@ fail:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
float wined3d_adapter_find_polyoffset_scale(struct wined3d_caps_gl_ctx *ctx, GLenum format)
|
||||
{
|
||||
const struct wined3d_gl_info *gl_info = ctx->gl_info;
|
||||
static const struct wined3d_color blue = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
GLuint fbo, color, depth;
|
||||
unsigned int low = 0, high = 32, cur;
|
||||
DWORD readback[256];
|
||||
static const struct wined3d_vec3 geometry[] =
|
||||
{
|
||||
{-1.0f, -1.0f, -1.0f},
|
||||
{ 1.0f, -1.0f, 0.0f},
|
||||
{-1.0f, 1.0f, -1.0f},
|
||||
{ 1.0f, 1.0f, 0.0f},
|
||||
};
|
||||
|
||||
/* Most drivers want 2^23 for fixed point depth buffers, including r300g, r600g,
|
||||
* Nvidia. Use this as a fallback if the detection fails. */
|
||||
unsigned int fallback = 23;
|
||||
|
||||
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
|
||||
{
|
||||
FIXME("No FBOs, assuming polyoffset scale of 2^%u.\n", fallback);
|
||||
return (float)(1 << fallback);
|
||||
}
|
||||
|
||||
gl_info->gl_ops.gl.p_glGenTextures(1, &color);
|
||||
gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, color);
|
||||
gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
|
||||
gl_info->fbo_ops.glGenRenderbuffers(1, &depth);
|
||||
gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, depth);
|
||||
gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format, 256, 1);
|
||||
|
||||
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, color, 0);
|
||||
gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
|
||||
checkGLcall("Setup framebuffer");
|
||||
|
||||
gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.5f, 0.0f);
|
||||
gl_info->gl_ops.gl.p_glClearDepth(0.5f);
|
||||
gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
|
||||
gl_info->gl_ops.gl.p_glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
gl_info->gl_ops.gl.p_glViewport(0, 0, 256, 1);
|
||||
checkGLcall("Misc parameters");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (high - low <= 1)
|
||||
{
|
||||
ERR("PolygonOffset scale factor detection failed, using fallback value 2^%u.\n", fallback);
|
||||
cur = fallback;
|
||||
break;
|
||||
}
|
||||
cur = (low + high) / 2;
|
||||
|
||||
gl_info->gl_ops.gl.p_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
/* The post viewport transform Z of the geometry runs from 0.0 to 0.5. We want to push it another
|
||||
* 0.25 so that the Z buffer content (0.5) cuts the quad off at half the screen. */
|
||||
gl_info->gl_ops.gl.p_glPolygonOffset(0.0f, (float)(1 << cur) * 0.25f);
|
||||
draw_test_quad(ctx, geometry, &blue);
|
||||
checkGLcall("Test draw");
|
||||
|
||||
/* Rebinding texture to workaround a fglrx bug. */
|
||||
gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, color);
|
||||
gl_info->gl_ops.gl.p_glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, readback);
|
||||
checkGLcall("readback");
|
||||
|
||||
TRACE("low %02u, high %02u, cur %2u, 0=0x%08x, 125=0x%08x, 131=0x%08x, 255=0x%08x\n",
|
||||
low, high, cur, readback[0], readback[125], readback[131], readback[255]);
|
||||
|
||||
if ((readback[125] & 0xff) < 0xa0)
|
||||
high = cur;
|
||||
else if ((readback[131] & 0xff) > 0xa0)
|
||||
low = cur;
|
||||
else
|
||||
{
|
||||
TRACE("Found scale factor 2^%u for format %x\n", cur, format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gl_info->gl_ops.gl.p_glDeleteTextures(1, &color);
|
||||
gl_info->fbo_ops.glDeleteRenderbuffers(1, &depth);
|
||||
gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
|
||||
gl_info->fbo_ops.glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
checkGLcall("Delete framebuffer");
|
||||
|
||||
gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
|
||||
gl_info->gl_ops.gl.p_glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
return (float)(1 << cur);
|
||||
}
|
||||
|
||||
const struct wined3d_format *wined3d_get_format(const struct wined3d_gl_info *gl_info,
|
||||
enum wined3d_format_id format_id)
|
||||
{
|
||||
|
|
|
@ -1723,6 +1723,7 @@ struct wined3d_gl_info
|
|||
DWORD quirks;
|
||||
BOOL supported[WINED3D_GL_EXT_COUNT];
|
||||
GLint wrap_lookup[WINED3D_TADDRESS_MIRROR_ONCE - WINED3D_TADDRESS_WRAP + 1];
|
||||
float fixed_polyoffset_scale, float_polyoffset_scale;
|
||||
|
||||
HGLRC (WINAPI *p_wglCreateContextAttribsARB)(HDC dc, HGLRC share, const GLint *attribs);
|
||||
struct opengl_funcs gl_ops;
|
||||
|
@ -1812,6 +1813,7 @@ struct wined3d_caps_gl_ctx
|
|||
GLuint test_program_id;
|
||||
};
|
||||
|
||||
float wined3d_adapter_find_polyoffset_scale(struct wined3d_caps_gl_ctx *ctx, GLenum format) DECLSPEC_HIDDEN;
|
||||
BOOL wined3d_adapter_init_format_info(struct wined3d_adapter *adapter,
|
||||
struct wined3d_caps_gl_ctx *ctx) DECLSPEC_HIDDEN;
|
||||
UINT64 adapter_adjust_memory(struct wined3d_adapter *adapter, INT64 amount) DECLSPEC_HIDDEN;
|
||||
|
|
Loading…
Reference in New Issue