From 45820046e84413e38a17ea71bfb96b5900bddff9 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 18 Sep 2008 14:57:53 +0200 Subject: [PATCH] wined3d: Create a FBO for each combination of render targets and depth stencil. The main reason for this change is crappy performance for reconfiguring FBOs. --- dlls/wined3d/context.c | 129 +++++++++++++++++++++------------ dlls/wined3d/device.c | 26 ++++--- dlls/wined3d/surface.c | 8 +- dlls/wined3d/wined3d_private.h | 15 +++- 4 files changed, 113 insertions(+), 65 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 6e939700872..76d449ad7ea 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -194,14 +194,14 @@ static void context_check_fbo_status(IWineD3DDevice *iface) /* Dump the FBO attachments */ for (i = 0; i < GL_LIMITS(buffers); ++i) { - attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i]; + attachment = (IWineD3DSurfaceImpl *)This->activeContext->current_fbo->render_targets[i]; if (attachment) { FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format), attachment->pow2Width, attachment->pow2Height); } } - attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment; + attachment = (IWineD3DSurfaceImpl *)This->activeContext->current_fbo->depth_stencil; if (attachment) { FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format), @@ -210,67 +210,109 @@ static void context_check_fbo_status(IWineD3DDevice *iface) } } -static BOOL context_depth_mismatch_fbo(IWineD3DDevice *iface) +static struct fbo_entry *context_create_fbo_entry(IWineD3DDevice *iface) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0]; - IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget; + struct fbo_entry *entry; - if (!ds_impl) return FALSE; + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); + entry->render_targets = HeapAlloc(GetProcessHeap(), 0, GL_LIMITS(buffers) * sizeof(*entry->render_targets)); + memcpy(entry->render_targets, This->render_targets, GL_LIMITS(buffers) * sizeof(*entry->render_targets)); + entry->depth_stencil = This->stencilBufferTarget; + entry->attached = FALSE; + entry->id = 0; - if (ds_impl->current_renderbuffer) - { - return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width || - rt_impl->pow2Height != ds_impl->current_renderbuffer->height); - } - - return (rt_impl->pow2Width != ds_impl->pow2Width || - rt_impl->pow2Height != ds_impl->pow2Height); + return entry; } -void context_apply_fbo_state(IWineD3DDevice *iface) +void context_destroy_fbo_entry(IWineD3DDeviceImpl *This, struct fbo_entry *entry) +{ + if (entry->id) + { + TRACE("Destroy FBO %d\n", entry->id); + context_destroy_fbo(This, &entry->id); + } + list_remove(&entry->entry); + HeapFree(GetProcessHeap(), 0, entry->render_targets); + HeapFree(GetProcessHeap(), 0, entry); +} + + +static struct fbo_entry *context_find_fbo_entry(IWineD3DDevice *iface, WineD3DContext *context) +{ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + struct fbo_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry) + { + if (!memcmp(entry->render_targets, This->render_targets, GL_LIMITS(buffers) * sizeof(*entry->render_targets)) + && entry->depth_stencil == This->stencilBufferTarget) + { + return entry; + } + } + + entry = context_create_fbo_entry(iface); + list_add_head(&context->fbo_list, &entry->entry); + return entry; +} + +static void context_apply_fbo_entry(IWineD3DDevice *iface, struct fbo_entry *entry) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - WineD3DContext *context = This->activeContext; unsigned int i; - if (This->render_offscreen) - { - context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo); + context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &entry->id); + if (!entry->attached) + { /* Apply render targets */ for (i = 0; i < GL_LIMITS(buffers); ++i) { IWineD3DSurface *render_target = This->render_targets[i]; - if (context->fbo_color_attachments[i] != render_target) - { - context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, i, render_target); - context->fbo_color_attachments[i] = render_target; - } + context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, i, render_target); } /* Apply depth targets */ - if (context->fbo_depth_attachment != This->stencilBufferTarget || context_depth_mismatch_fbo(iface)) - { + if (This->stencilBufferTarget) { unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width; unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height; - if (This->stencilBufferTarget) - { - surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h); - } - context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, This->stencilBufferTarget, TRUE); - context->fbo_depth_attachment = This->stencilBufferTarget; + surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h); } + context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, This->stencilBufferTarget, TRUE); + entry->attached = TRUE; + } else { for (i = 0; i < GL_LIMITS(buffers); ++i) { if (This->render_targets[i]) - This->draw_buffers[i] = GL_COLOR_ATTACHMENT0_EXT + i; - else - This->draw_buffers[i] = GL_NONE; + context_apply_attachment_filter_states(iface, This->render_targets[i], FALSE); } + if (This->stencilBufferTarget) + context_apply_attachment_filter_states(iface, This->stencilBufferTarget, FALSE); + } + + for (i = 0; i < GL_LIMITS(buffers); ++i) + { + if (This->render_targets[i]) + This->draw_buffers[i] = GL_COLOR_ATTACHMENT0_EXT + i; + else + This->draw_buffers[i] = GL_NONE; + } +} + +static void context_apply_fbo_state(IWineD3DDevice *iface) +{ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3DContext *context = This->activeContext; + + if (This->render_offscreen) + { + context->current_fbo = context_find_fbo_entry(iface, context); + context_apply_fbo_entry(iface, context->current_fbo); } else { + context->current_fbo = NULL; GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); } @@ -726,12 +768,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar TRACE("Successfully created new context %p\n", ret); - ret->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers)); - if (!ret->fbo_color_attachments) - { - ERR("Out of memory!\n"); - goto out; - } + list_init(&ret->fbo_list); /* Set up the context defaults */ oldCtx = pwglGetCurrentContext(); @@ -827,7 +864,6 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar return ret; out: - HeapFree(GetProcessHeap(), 0, ret->fbo_color_attachments); return NULL; } @@ -884,6 +920,7 @@ static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *con * *****************************************************************************/ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) { + struct fbo_entry *entry, *entry2; TRACE("Destroying ctx %p\n", context); @@ -895,9 +932,8 @@ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) { ENTER_GL(); - if (context->fbo) { - TRACE("Destroy FBO %d\n", context->fbo); - context_destroy_fbo(This, &context->fbo); + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) { + context_destroy_fbo_entry(This, entry); } if (context->src_fbo) { TRACE("Destroy src FBO %d\n", context->src_fbo); @@ -910,9 +946,6 @@ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) { LEAVE_GL(); - HeapFree(GetProcessHeap(), 0, context->fbo_color_attachments); - context->fbo_color_attachments = NULL; - /* Cleanup the GL context */ pwglMakeCurrent(NULL, NULL); if(context->isPBuffer) { diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 496e5e84c3b..4ca96e655fa 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -6174,8 +6174,8 @@ static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONS glClear(GL_COLOR_BUFFER_BIT); checkGLcall("glClear"); - if (This->render_offscreen) { - context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo); + if (This->activeContext->current_fbo) { + context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id); } else { GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); checkGLcall("glBindFramebuffer()"); @@ -6567,8 +6567,8 @@ void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE); - if (This->render_offscreen) { - context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo); + if (This->activeContext->current_fbo) { + context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id); } else { GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); checkGLcall("glBindFramebuffer()"); @@ -7376,14 +7376,20 @@ static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IW } for (i = 0; i < This->numContexts; ++i) { + struct fbo_entry *entry, *entry2; int j; - for (j = 0; j < GL_LIMITS(buffers); ++j) { - if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) { - This->contexts[i]->fbo_color_attachments[j] = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->contexts[i]->fbo_list, struct fbo_entry, entry) { + BOOL destroyed = FALSE; + for (j = 0; !destroyed && j < GL_LIMITS(buffers); ++j) { + if (entry->render_targets[j] == (IWineD3DSurface *)resource) { + context_destroy_fbo_entry(This, entry); + destroyed = TRUE; + } + } + if (!destroyed && entry->depth_stencil == (IWineD3DSurface *)resource) { + context_destroy_fbo_entry(This, entry); } - } - if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) { - This->contexts[i]->fbo_depth_attachment = NULL; } } } diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 69bf0fb82d9..be6ffb33c85 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -4004,8 +4004,8 @@ void surface_load_ds_location(IWineD3DSurface *iface, DWORD location) { depth_blt((IWineD3DDevice *)device, device->depth_blt_texture, This->currentDesc.Width, This->currentDesc.Height); checkGLcall("depth_blt"); - if (device->render_offscreen) { - context_bind_fbo((IWineD3DDevice *)device, GL_FRAMEBUFFER_EXT, &device->activeContext->fbo); + if (device->activeContext->current_fbo) { + context_bind_fbo((IWineD3DDevice *)device, GL_FRAMEBUFFER_EXT, &device->activeContext->current_fbo->id); } else { GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); checkGLcall("glBindFramebuffer()"); @@ -4026,8 +4026,8 @@ void surface_load_ds_location(IWineD3DSurface *iface, DWORD location) { depth_blt((IWineD3DDevice *)device, This->glDescription.textureName, This->currentDesc.Width, This->currentDesc.Height); checkGLcall("depth_blt"); - if (device->render_offscreen) { - GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, device->activeContext->fbo)); + if (device->activeContext->current_fbo) { + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, device->activeContext->current_fbo->id)); checkGLcall("glBindFramebuffer()"); } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 654c585bf2b..d3478071209 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -613,9 +613,8 @@ struct WineD3DContext { GLint aux_buffers; /* FBOs */ - IWineD3DSurface **fbo_color_attachments; - IWineD3DSurface *fbo_depth_attachment; - GLuint fbo; + struct list fbo_list; + struct fbo_entry *current_fbo; GLuint src_fbo; GLuint dst_fbo; }; @@ -1260,6 +1259,15 @@ typedef struct { UINT height; } renderbuffer_entry_t; +struct fbo_entry +{ + struct list entry; + IWineD3DSurface **render_targets; + IWineD3DSurface *depth_stencil; + BOOL attached; + GLuint id; +}; + /***************************************************************************** * IWineD3DClipp implementation structure */ @@ -2435,4 +2443,5 @@ void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip); void depth_blt(IWineD3DDevice *iface, GLuint texture, GLsizei w, GLsizei h); +void context_destroy_fbo_entry(IWineD3DDeviceImpl *This, struct fbo_entry *entry); #endif