[PATCH 2/6] wined3d: Keep track of FBOs through the GL names (v3).

Stefan Dösinger stefandoesinger at gmx.at
Sun Feb 21 15:29:57 CST 2016


Version 2: Don't use fbo_entry->d3d_* for logging, plan for it to go
away. The disadvantage is now that we don't know the d3d properties once
we find out that an FBO doesn't work and need a full TRACE log for this
information, but I think that's something we can live with.

If there is a prettier way to find the texture target of a GL texture
name please advise. I couldn't find any.

Version 3:
*) Memset only struct wined3d_fbo_entry_key, not the entire fbo_entry
struct. I guess I could only memset up to the first object to catch the
potential alignment gap between rb_namespace and the object array, but
it seems cleaner to memset the entire structure.

*) Explicitly enumerate all possible GL attachments for the debug
strings instead of using sprintf.

*) Rename context_generate_fbo_key and the render target count
parameter, remove the inline.

*) Make the empty resource static const.

Signed-off-by: Stefan Dösinger <stefandoesinger at gmx.at>
---
 dlls/wined3d/context.c         | 280 +++++++++++++++++++++++++----------------
 dlls/wined3d/wined3d_private.h |  17 ++-
 2 files changed, 186 insertions(+), 111 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 3668195..6862fe3 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -120,57 +120,39 @@ static void context_attach_depth_stencil_rb(const struct wined3d_gl_info *gl_inf
 
 /* Context activation is done by the caller. */
 static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
-        GLenum fbo_target, struct wined3d_surface *depth_stencil, DWORD location)
+        GLenum fbo_target, const struct wined3d_fbo_resource *resource, BOOL rb_namespace,
+        DWORD format_flags, GLuint rb_override)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
-    TRACE("Attach depth stencil %p\n", depth_stencil);
-
-    if (depth_stencil)
+    if (resource->object)
     {
-        DWORD format_flags = depth_stencil->container->resource.format_flags;
+        TRACE("Attach depth stencil %u.\n", resource->object);
 
-        if (depth_stencil->current_renderbuffer)
+        if (rb_override)
         {
             context_attach_depth_stencil_rb(gl_info, fbo_target,
-                    format_flags, depth_stencil->current_renderbuffer->id);
+                    format_flags, rb_override);
+        }
+        else if (rb_namespace)
+        {
+            context_attach_depth_stencil_rb(gl_info, fbo_target,
+                    format_flags, resource->object);
         }
         else
         {
-            switch (location)
+            if (format_flags & WINED3DFMT_FLAG_DEPTH)
             {
-                case WINED3D_LOCATION_TEXTURE_RGB:
-                case WINED3D_LOCATION_TEXTURE_SRGB:
-                    if (format_flags & WINED3DFMT_FLAG_DEPTH)
-                    {
-                        gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
-                                depth_stencil->texture_target, depth_stencil->container->texture_rgb.name,
-                                depth_stencil->texture_level);
-                        checkGLcall("glFramebufferTexture2D()");
-                    }
-
-                    if (format_flags & WINED3DFMT_FLAG_STENCIL)
-                    {
-                        gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
-                                depth_stencil->texture_target, depth_stencil->container->texture_rgb.name,
-                                depth_stencil->texture_level);
-                        checkGLcall("glFramebufferTexture2D()");
-                    }
-                    break;
-
-                case WINED3D_LOCATION_RB_MULTISAMPLE:
-                    context_attach_depth_stencil_rb(gl_info, fbo_target,
-                            format_flags, depth_stencil->rb_multisample);
-                    break;
-
-                case WINED3D_LOCATION_RB_RESOLVED:
-                    context_attach_depth_stencil_rb(gl_info, fbo_target,
-                            format_flags, depth_stencil->rb_resolved);
-                    break;
+                gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
+                        resource->target, resource->object, resource->level);
+                checkGLcall("glFramebufferTexture2D()");
+            }
 
-                default:
-                    ERR("Unsupported location %s (%#x).\n", wined3d_debug_location(location), location);
-                    break;
+            if (format_flags & WINED3DFMT_FLAG_STENCIL)
+            {
+                gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
+                        resource->target, resource->object, resource->level);
+                checkGLcall("glFramebufferTexture2D()");
             }
         }
 
@@ -188,6 +170,8 @@ static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
     }
     else
     {
+        TRACE("Attach depth stencil 0.\n");
+
         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
         checkGLcall("glFramebufferTexture2D()");
 
@@ -198,42 +182,26 @@ static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
 
 /* Context activation is done by the caller. */
 static void context_attach_surface_fbo(struct wined3d_context *context,
-        GLenum fbo_target, DWORD idx, struct wined3d_surface *surface, DWORD location)
+        GLenum fbo_target, DWORD idx, const struct wined3d_fbo_resource *resource, BOOL rb_namespace)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
-    TRACE("Attach surface %p to %u\n", surface, idx);
+    TRACE("Attach GL object %u to %u.\n", resource->object, idx);
 
-    if (surface && surface->resource.format->id != WINED3DFMT_NULL)
+    if (resource->object)
     {
-        BOOL srgb;
 
-        switch (location)
+        if (rb_namespace)
         {
-            case WINED3D_LOCATION_TEXTURE_RGB:
-            case WINED3D_LOCATION_TEXTURE_SRGB:
-                srgb = location == WINED3D_LOCATION_TEXTURE_SRGB;
-                gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
-                        surface->texture_target, surface_get_texture_name(surface, context, srgb),
-                        surface->texture_level);
-                checkGLcall("glFramebufferTexture2D()");
-                break;
-
-            case WINED3D_LOCATION_RB_MULTISAMPLE:
-                gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
-                        GL_RENDERBUFFER, surface->rb_multisample);
-                checkGLcall("glFramebufferRenderbuffer()");
-                break;
-
-            case WINED3D_LOCATION_RB_RESOLVED:
-                gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
-                        GL_RENDERBUFFER, surface->rb_resolved);
-                checkGLcall("glFramebufferRenderbuffer()");
-                break;
-
-            default:
-                ERR("Unsupported location %s (%#x).\n", wined3d_debug_location(location), location);
-                break;
+            gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
+                    GL_RENDERBUFFER, resource->object);
+            checkGLcall("glFramebufferRenderbuffer()");
+        }
+        else
+        {
+            gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
+                    resource->target, resource->object, resource->level);
+            checkGLcall("glFramebufferTexture2D()");
         }
     }
     else
@@ -377,19 +345,76 @@ static inline DWORD context_generate_rt_mask_from_surface(const struct wined3d_s
     return (1u << 31) | surface_get_gl_buffer(target);
 }
 
+static inline void context_set_fbo_key_for_surface(const struct wined3d_context *context,
+        struct wined3d_fbo_entry_key *key, UINT idx, struct wined3d_surface *surface,
+        DWORD location)
+{
+    if (!surface)
+    {
+        key->objects[idx].object = 0;
+        key->objects[idx].level = key->objects[idx].target = 0;
+    }
+    else
+    {
+        switch (location)
+        {
+            case WINED3D_LOCATION_TEXTURE_RGB:
+                key->objects[idx].object = surface_get_texture_name(surface, context, FALSE);
+                key->objects[idx].level = surface->texture_level;
+                key->objects[idx].target = surface->texture_target;
+                break;
+
+            case WINED3D_LOCATION_TEXTURE_SRGB:
+                key->objects[idx].object = surface_get_texture_name(surface, context, TRUE);
+                key->objects[idx].level = surface->texture_level;
+                key->objects[idx].target = surface->texture_target;
+                break;
+
+            case WINED3D_LOCATION_RB_MULTISAMPLE:
+                key->objects[idx].object = surface->rb_multisample;
+                key->objects[idx].level = key->objects[idx].target = 0;
+                key->rb_namespace |= 1 << idx;
+                break;
+
+            case WINED3D_LOCATION_RB_RESOLVED:
+                key->objects[idx].object = surface->rb_resolved;
+                key->objects[idx].level = key->objects[idx].target = 0;
+                key->rb_namespace |= 1 << idx;
+                break;
+        }
+    }
+}
+
+static void context_generate_fbo_key(const struct wined3d_context *context,
+        struct wined3d_fbo_entry_key *key, struct wined3d_surface **render_targets,
+        struct wined3d_surface *depth_stencil, DWORD color_location,
+        DWORD ds_location)
+{
+    UINT i;
+
+    key->rb_namespace = 0;
+    context_set_fbo_key_for_surface(context, key, 0, depth_stencil, ds_location);
+
+    for (i = 0; i < context->gl_info->limits.buffers; ++i)
+        context_set_fbo_key_for_surface(context, key, i + 1, render_targets[i], color_location);
+}
+
 static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
         struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
         DWORD color_location, DWORD ds_location)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct fbo_entry *entry;
-
-    entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
-    entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
-    memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
-    entry->depth_stencil = depth_stencil;
-    entry->color_location = color_location;
-    entry->ds_location = ds_location;
+    UINT object_count = gl_info->limits.buffers + 1;
+
+    entry = HeapAlloc(GetProcessHeap(), 0,
+            FIELD_OFFSET(struct fbo_entry, key.objects[object_count]));
+    entry->d3d_render_targets = HeapAlloc(GetProcessHeap(), 0,
+            gl_info->limits.buffers * sizeof(*entry->d3d_render_targets));
+    memset(&entry->key, 0, FIELD_OFFSET(struct wined3d_fbo_entry_key, objects[object_count]));
+    context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
+    memcpy(entry->d3d_render_targets, render_targets, sizeof(*entry->d3d_render_targets) * gl_info->limits.buffers);
+    entry->d3d_depth_stencil = depth_stencil;
     entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
     entry->attached = FALSE;
     gl_info->fbo_ops.glGenFramebuffers(1, &entry->id);
@@ -409,10 +434,9 @@ static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum targ
     context_bind_fbo(context, target, entry->id);
     context_clean_fbo_attachments(gl_info, target);
 
-    memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
-    entry->depth_stencil = depth_stencil;
-    entry->color_location = color_location;
-    entry->ds_location = ds_location;
+    context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
+    memcpy(entry->d3d_render_targets, render_targets, sizeof(*entry->d3d_render_targets) * gl_info->limits.buffers);
+    entry->d3d_depth_stencil = depth_stencil;
     entry->attached = FALSE;
 }
 
@@ -426,7 +450,7 @@ static void context_destroy_fbo_entry(struct wined3d_context *context, struct fb
     }
     --context->fbo_entry_count;
     list_remove(&entry->entry);
-    HeapFree(GetProcessHeap(), 0, entry->render_targets);
+    HeapFree(GetProcessHeap(), 0, entry->d3d_render_targets);
     HeapFree(GetProcessHeap(), 0, entry);
 }
 
@@ -437,6 +461,8 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context,
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct fbo_entry *entry;
+    UINT object_count = gl_info->limits.buffers + 1;
+    unsigned int i;
 
     if (depth_stencil && render_targets && render_targets[0])
     {
@@ -448,19 +474,44 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context,
         }
     }
 
-    LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
+    context_generate_fbo_key(context, context->fbo_key, render_targets, depth_stencil, color_location,
+            ds_location);
+
+    if (TRACE_ON(d3d))
     {
-        if (!memcmp(entry->render_targets,
-                render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
-                && entry->depth_stencil == depth_stencil && entry->color_location == color_location
-                && entry->ds_location == ds_location)
+        TRACE("Dumping FBO attachments:\n");
+        for (i = 0; i < gl_info->limits.buffers; ++i)
         {
-            list_remove(&entry->entry);
-            list_add_head(&context->fbo_list, &entry->entry);
-            return entry;
+            if (render_targets[i])
+            {
+                TRACE("\tColor attachment %u: (%p) %s gl obj %u(%s) %ux%u %u samples.\n",
+                        i, render_targets[i], debug_d3dformat(render_targets[i]->resource.format->id),
+                        context->fbo_key->objects[i + 1].object,
+                        context->fbo_key->rb_namespace & (1 << (i + 1)) ? "rb" : "texure",
+                        render_targets[i]->pow2Width, render_targets[i]->pow2Height,
+                        render_targets[i]->resource.multisample_type);
+            }
+        }
+        if (depth_stencil)
+        {
+            TRACE("\tDepth attachment: (%p) %s gl obj %u(%s) %ux%u %u samples.\n",
+                    depth_stencil, debug_d3dformat(depth_stencil->resource.format->id),
+                    context->fbo_key->objects[0].object,
+                    context->fbo_key->rb_namespace & (1 << 0) ? "rb" : "texure",
+                    depth_stencil->pow2Width, depth_stencil->pow2Height, depth_stencil->resource.multisample_type);
         }
     }
 
+    LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
+    {
+        if (memcmp(context->fbo_key, &entry->key, FIELD_OFFSET(struct wined3d_fbo_entry_key, objects[object_count])))
+            continue;
+
+        list_remove(&entry->entry);
+        list_add_head(&context->fbo_list, &entry->entry);
+        return entry;
+    }
+
     if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
     {
         entry = context_create_fbo_entry(context, render_targets, depth_stencil, color_location, ds_location);
@@ -484,7 +535,7 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ
     const struct wined3d_gl_info *gl_info = context->gl_info;
     unsigned int i;
     GLuint read_binding, draw_binding;
-    struct wined3d_surface *depth_stencil = entry->depth_stencil;
+    struct wined3d_surface *depth_stencil = entry->d3d_depth_stencil;
 
     if (entry->attached)
     {
@@ -499,25 +550,36 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ
     /* Apply render targets */
     for (i = 0; i < gl_info->limits.buffers; ++i)
     {
-        context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->color_location);
+        context_attach_surface_fbo(context, target, i, &entry->key.objects[i + 1],
+                entry->key.rb_namespace & (1 << (i + 1)));
     }
 
-    if (depth_stencil && entry->render_targets[0]
+    if (depth_stencil && entry->d3d_render_targets[0]
             && (depth_stencil->resource.multisample_type
-            != entry->render_targets[0]->resource.multisample_type
+            != entry->d3d_render_targets[0]->resource.multisample_type
             || depth_stencil->resource.multisample_quality
-            != entry->render_targets[0]->resource.multisample_quality))
+            != entry->d3d_render_targets[0]->resource.multisample_quality))
     {
         WARN("Color multisample type %u and quality %u, depth stencil has %u and %u, disabling ds buffer.\n",
-                entry->render_targets[0]->resource.multisample_quality,
-                entry->render_targets[0]->resource.multisample_type,
+                entry->d3d_render_targets[0]->resource.multisample_quality,
+                entry->d3d_render_targets[0]->resource.multisample_type,
                 depth_stencil->resource.multisample_quality, depth_stencil->resource.multisample_type);
         depth_stencil = NULL;
     }
 
     if (depth_stencil)
-        surface_set_compatible_renderbuffer(depth_stencil, entry->render_targets[0]);
-    context_attach_depth_stencil_fbo(context, target, depth_stencil, entry->ds_location);
+    {
+        DWORD format_flags = depth_stencil->container->resource.format_flags;
+        surface_set_compatible_renderbuffer(depth_stencil, entry->d3d_render_targets[0]);
+        context_attach_depth_stencil_fbo(context, target, &entry->key.objects[0],
+                entry->key.rb_namespace & 0x1, format_flags,
+                depth_stencil->current_renderbuffer ? depth_stencil->current_renderbuffer->id : 0);
+    }
+    else
+    {
+        static const struct wined3d_fbo_resource resource = {0};
+        context_attach_depth_stencil_fbo(context, target, &resource, FALSE, 0, 0);
+    }
 
     /* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
      * GL contexts requirements. */
@@ -766,7 +828,7 @@ static void context_enum_surface_fbo_entries(const struct wined3d_device *device
         {
             UINT j;
 
-            if (entry->depth_stencil == surface)
+            if (entry->d3d_depth_stencil == surface)
             {
                 callback(context, entry);
                 continue;
@@ -774,7 +836,7 @@ static void context_enum_surface_fbo_entries(const struct wined3d_device *device
 
             for (j = 0; j < gl_info->limits.buffers; ++j)
             {
-                if (entry->render_targets[j] == surface)
+                if (entry->d3d_render_targets[j] == surface)
                 {
                     callback(context, entry);
                     break;
@@ -835,21 +897,16 @@ void context_surface_update(struct wined3d_context *context, const struct wined3
 
     if (!entry || context->rebind_fbo) return;
 
-    for (i = 0; i < gl_info->limits.buffers; ++i)
+    for (i = 0; i < gl_info->limits.buffers + 1; ++i)
     {
-        if (surface == entry->render_targets[i])
+        if (surface->container->texture_rgb.name == entry->key.objects[i].object
+                || surface->container->texture_srgb.name == entry->key.objects[i].object)
         {
-            TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
+            TRACE("Updated surface %p is bound as attachment %u to the current FBO.\n", surface, i);
             context->rebind_fbo = TRUE;
             return;
         }
     }
-
-    if (surface == 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_restore_pixel_format(struct wined3d_context *ctx)
@@ -1546,6 +1603,11 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     if (!ret->draw_buffers)
         goto out;
 
+    ret->fbo_key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            FIELD_OFFSET(struct wined3d_fbo_entry_key, objects[gl_info->limits.buffers + 1]));
+    if (!ret->fbo_key)
+        goto out;
+
     ret->free_timestamp_query_size = 4;
     ret->free_timestamp_queries = HeapAlloc(GetProcessHeap(), 0,
             ret->free_timestamp_query_size * sizeof(*ret->free_timestamp_queries));
@@ -1914,6 +1976,7 @@ out:
     HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_timestamp_queries);
+    HeapFree(GetProcessHeap(), 0, ret->fbo_key);
     HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
     HeapFree(GetProcessHeap(), 0, ret->blit_targets);
     HeapFree(GetProcessHeap(), 0, ret);
@@ -1945,6 +2008,7 @@ void context_destroy(struct wined3d_device *device, struct wined3d_context *cont
 
     device->shader_backend->shader_free_context_data(context);
     device->adapter->fragment_pipe->free_context_data(context);
+    HeapFree(GetProcessHeap(), 0, context->fbo_key);
     HeapFree(GetProcessHeap(), 0, context->draw_buffers);
     HeapFree(GetProcessHeap(), 0, context->blit_targets);
     device_context_remove(device, context);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 8fd0d8b..e2c35c3 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1311,6 +1311,7 @@ struct wined3d_context
     GLuint                  fbo_read_binding;
     GLuint                  fbo_draw_binding;
     struct wined3d_surface **blit_targets;
+    struct wined3d_fbo_entry_key *fbo_key;
     GLenum *draw_buffers;
     DWORD draw_buffers_mask; /* Enabled draw buffers, 31 max. */
 
@@ -2475,15 +2476,25 @@ struct wined3d_renderbuffer_entry
     UINT height;
 };
 
+struct wined3d_fbo_resource
+{
+    GLuint object;
+    GLuint level, target;
+};
+
 struct fbo_entry
 {
     struct list entry;
-    struct wined3d_surface **render_targets;
-    struct wined3d_surface *depth_stencil;
-    DWORD color_location, ds_location;
+    struct wined3d_surface **d3d_render_targets;
+    struct wined3d_surface *d3d_depth_stencil;
     DWORD rt_mask;
     BOOL attached;
     GLuint id;
+    struct wined3d_fbo_entry_key
+    {
+        DWORD rb_namespace;
+        struct wined3d_fbo_resource objects[1];
+    } key;
 };
 
 struct wined3d_surface_ops
-- 
2.4.10




More information about the wine-patches mailing list