From: Adam Martinson Subject: wined3d: Track when the FBO is dirty. (try 4) Message-Id: <4DB7024A.1020304@codeweavers.com> Date: Tue, 26 Apr 2011 12:35:06 -0500 --- dlls/wined3d/context.c | 54 +++++++++++++++++++++++++++++++++++++-- dlls/wined3d/device.c | 16 ++++++++++++ dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 3d07a35..1810096 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -374,6 +374,9 @@ static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum targ entry->depth_stencil = depth_stencil; entry->location = location; entry->attached = FALSE; + + if (entry == context->device_fbo) + context->device_fbo = NULL; } /* GL locking is done by the caller */ @@ -473,6 +476,24 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ } /* GL locking is done by the caller */ +static void context_apply_device_fbo(struct wined3d_context *context) +{ + struct fbo_entry *entry = context->device_fbo; + if (context->rebind_fbo) + { + context_bind_fbo(context, GL_FRAMEBUFFER, NULL); + context->rebind_fbo = FALSE; + } + + list_remove(&entry->entry); + list_add_head(&context->fbo_list, &entry->entry); + + context->current_fbo = entry; + context_apply_fbo_entry(context, GL_FRAMEBUFFER, entry); + context_check_fbo_status(context, GL_FRAMEBUFFER); +} + +/* GL locking is done by the caller */ static void context_apply_fbo_state(struct wined3d_context *context, GLenum target, IWineD3DSurfaceImpl **render_targets, IWineD3DSurfaceImpl *depth_stencil, DWORD location) { @@ -1461,6 +1482,7 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain, ret->render_offscreen = surface_is_offscreen(target); ret->draw_buffer_dirty = TRUE; + ret->device_fbo = NULL; ret->valid = 1; ret->glCtx = ctx; @@ -2166,7 +2188,25 @@ BOOL context_apply_clear_state(struct wined3d_context *context, IWineD3DDeviceIm context->blit_targets[i] = NULL; ++i; } - context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE); + + if (rt_count == device->adapter->gl_info.limits.buffers && + rts == device->render_targets && + depth_stencil == device->depth_stencil) + { + if (context->device_fbo != NULL) + { + context_apply_device_fbo(context); + } + else + { + context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE); + context->device_fbo = context->current_fbo; + } + } + else + { + context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, depth_stencil, SFLAG_INTEXTURE); + } glReadBuffer(GL_NONE); checkGLcall("glReadBuffer"); } @@ -2241,8 +2281,16 @@ BOOL context_apply_draw_state(struct wined3d_context *context, IWineD3DDeviceImp else { ENTER_GL(); - context_apply_fbo_state(context, GL_FRAMEBUFFER, device->render_targets, - device->depth_stencil, SFLAG_INTEXTURE); + if (context->device_fbo != NULL) + { + context_apply_device_fbo(context); + } + else + { + context_apply_fbo_state(context, GL_FRAMEBUFFER, device->render_targets, + device->depth_stencil, SFLAG_INTEXTURE); + context->device_fbo = context->current_fbo; + } glReadBuffer(GL_NONE); checkGLcall("glReadBuffer"); LEAVE_GL(); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 827365a..4883a0b 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -453,6 +453,15 @@ void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_ } } +static inline void IWineD3DDeviceImpl_MarkFBODirty(IWineD3DDeviceImpl *This) +{ + UINT i; + for (i = 0; i < This->context_count; ++i) + { + This->contexts[i]->device_fbo = NULL; + } +} + static void device_preload_texture(const struct wined3d_state *state, unsigned int idx) { struct wined3d_texture *texture; @@ -5873,6 +5882,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, if (render_target) IWineD3DSurface_AddRef(render_target); device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target; + IWineD3DDeviceImpl_MarkFBODirty(device); /* Release after the assignment, to prevent device_resource_released() * from seeing the surface as still in use. */ if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev); @@ -5932,6 +5942,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice * tmp = This->depth_stencil; This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil; + IWineD3DDeviceImpl_MarkFBODirty(This); if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil); if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp); @@ -6714,6 +6725,7 @@ void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_ { case WINED3DRTYPE_SURFACE: { + BOOL fbo_dirty = FALSE; IWineD3DSurfaceImpl *surface = surface_from_resource(resource); if (!device->d3d_initialized) break; @@ -6724,6 +6736,7 @@ void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_ { ERR("Surface %p is still in use as render target %u.\n", surface, i); device->render_targets[i] = NULL; + fbo_dirty = TRUE; } } @@ -6731,7 +6744,10 @@ void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_ { ERR("Surface %p is still in use as depth/stencil buffer.\n", surface); device->depth_stencil = NULL; + fbo_dirty = TRUE; } + + if (fbo_dirty) IWineD3DDeviceImpl_MarkFBODirty(device); } break; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 0a9b36a..7580551 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1093,6 +1093,7 @@ struct wined3d_context struct list fbo_list; struct list fbo_destroy_list; struct fbo_entry *current_fbo; + struct fbo_entry *device_fbo; GLuint dst_fbo; GLuint fbo_read_binding; GLuint fbo_draw_binding;