wined3d: Add a quirk to rebind FBOs when one of their attached textures is updated.

Updating a texture while it is attached to the currently bound FBO is
something GL implementations tend to get wrong. NVIDIA fails at
glTexSubImage2D(), fglrx and Mesa with glTexImage2D(). I'm afraid to try what
happens on OS X. Fortunately we never use glTexImage2D() while a texture is
attached to an FBO, so we only need to care about glTexSubImage2D().
This commit is contained in:
Henri Verbeet 2010-03-17 21:59:51 +01:00 committed by Alexandre Julliard
parent bd4fb33a52
commit e5673ddbc3
4 changed files with 105 additions and 0 deletions

View File

@ -461,6 +461,12 @@ static void context_apply_fbo_state(struct wined3d_context *context)
context_destroy_fbo_entry(context, entry);
}
if (context->rebind_fbo)
{
context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
context->rebind_fbo = FALSE;
}
if (context->render_offscreen)
{
context->current_fbo = context_find_fbo_entry(context);
@ -652,6 +658,31 @@ void context_resource_released(IWineD3DDevice *iface, IWineD3DResource *resource
}
}
void context_surface_update(struct wined3d_context *context, IWineD3DSurfaceImpl *surface)
{
const struct wined3d_gl_info *gl_info = context->gl_info;
struct fbo_entry *entry = context->current_fbo;
unsigned int i;
if (!entry || context->rebind_fbo) return;
for (i = 0; i < gl_info->limits.buffers; ++i)
{
if (surface == (IWineD3DSurfaceImpl *)entry->render_targets[i])
{
TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
context->rebind_fbo = TRUE;
return;
}
}
if (surface == (IWineD3DSurfaceImpl *)entry->depth_stencil)
{
TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
context->rebind_fbo = TRUE;
}
}
static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
{
int current = GetPixelFormat(dc);

View File

@ -669,6 +669,56 @@ static BOOL match_broken_nv_clip(const struct wined3d_gl_info *gl_info, const ch
return ret;
}
static BOOL match_fbo_tex_update(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)
{
char data[4 * 4 * 4];
GLuint tex, fbo;
GLenum status;
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return FALSE;
memset(data, 0xcc, sizeof(data));
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 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");
memset(data, 0x11, sizeof(data));
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
checkGLcall("glTexSubImage2D");
glClearColor(0.996, 0.729, 0.745, 0.792);
glClear(GL_COLOR_BUFFER_BIT);
checkGLcall("glClear");
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
checkGLcall("glGetTexImage");
gl_info->fbo_ops.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
gl_info->fbo_ops.glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
checkGLcall("glBindTexture");
gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &tex);
checkGLcall("glDeleteTextures");
return *(DWORD *)data == 0x11111111;
}
static void quirk_arb_constants(struct wined3d_gl_info *gl_info)
{
TRACE_(d3d_caps)("Using ARB vs constant limit(=%u) for GLSL.\n", gl_info->limits.arb_vs_native_constants);
@ -797,6 +847,11 @@ static void quirk_disable_nvvp_clip(struct wined3d_gl_info *gl_info)
gl_info->quirks |= WINED3D_QUIRK_NV_CLIP_BROKEN;
}
static void quirk_fbo_tex_update(struct wined3d_gl_info *gl_info)
{
gl_info->quirks |= WINED3D_QUIRK_FBO_TEX_UPDATE;
}
struct driver_quirk
{
BOOL (*match)(const struct wined3d_gl_info *gl_info, const char *gl_renderer,
@ -876,6 +931,11 @@ static const struct driver_quirk quirk_table[] =
quirk_disable_nvvp_clip,
"Apple NV_vertex_program clip bug quirk"
},
{
match_fbo_tex_update,
quirk_fbo_tex_update,
"FBO rebind for attachment updates"
},
};
/* Certain applications (Steam) complain if we report an outdated driver version. In general,

View File

@ -697,6 +697,17 @@ static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_
}
LEAVE_GL();
if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
{
IWineD3DDeviceImpl *device = This->resource.device;
unsigned int i;
for (i = 0; i < device->numContexts; ++i)
{
context_surface_update(device->contexts[i], This);
}
}
}
/* This call just allocates the texture, the caller is responsible for binding

View File

@ -50,6 +50,7 @@
#define WINED3D_QUIRK_GLSL_CLIP_VARYING 0x00000004
#define WINED3D_QUIRK_ALLOWS_SPECULAR_ALPHA 0x00000008
#define WINED3D_QUIRK_NV_CLIP_BROKEN 0x00000010
#define WINED3D_QUIRK_FBO_TEX_UPDATE 0x00000020
/* Texture format fixups */
@ -1100,6 +1101,7 @@ struct wined3d_context
GLuint dst_fbo;
GLuint fbo_read_binding;
GLuint fbo_draw_binding;
BOOL rebind_fbo;
/* Queries */
GLuint *free_occlusion_queries;
@ -1210,6 +1212,7 @@ void context_release(struct wined3d_context *context) DECLSPEC_HIDDEN;
BOOL context_set_current(struct wined3d_context *ctx) DECLSPEC_HIDDEN;
void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer) DECLSPEC_HIDDEN;
void context_set_tls_idx(DWORD idx) DECLSPEC_HIDDEN;
void context_surface_update(struct wined3d_context *context, IWineD3DSurfaceImpl *surface) DECLSPEC_HIDDEN;
void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain) DECLSPEC_HIDDEN;
HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain) DECLSPEC_HIDDEN;