wined3d: Create a FBO for each combination of render targets and depth stencil

Henri Verbeet hverbeet at codeweavers.com
Thu Sep 18 07:57:53 CDT 2008


The main reason for this change is crappy performance for reconfiguring FBOs.
---
 dlls/wined3d/context.c         |  123 +++++++++++++++++++++++++---------------
 dlls/wined3d/device.c          |   26 +++++---
 dlls/wined3d/surface.c         |    8 +-
 dlls/wined3d/wined3d_private.h |   15 ++++-
 4 files changed, 110 insertions(+), 62 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 6e93970..76d449a 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 entry;
+}
+
+void context_destroy_fbo_entry(IWineD3DDeviceImpl *This, struct fbo_entry *entry)
+{
+    if (entry->id)
     {
-        return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
-                rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
+        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);
+}
+
 
-    return (rt_impl->pow2Width != ds_impl->pow2Width ||
-            rt_impl->pow2Height != ds_impl->pow2Height);
+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;
 }
 
-void context_apply_fbo_state(IWineD3DDevice *iface)
+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 496e5e8..4ca96e6 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 69bf0fb..be6ffb3 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 654c585..d347807 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
-- 
1.5.6.4



--------------080104070209050408000007--



More information about the wine-patches mailing list