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

Stefan Dösinger stefan at codeweavers.com
Thu Oct 22 16:38:40 CDT 2015


The next two patches will improve integration with the fixed up depth
stencil and context_enum_surface_fbo_entries. fbo_entry->d3d_* will
remain for logging in context_check_fbo_status.

I'm storing the bind target + level in the key instead of the sub
resource index because after finding the key we want to limit access to
fbo_entry->d3d_render_targets and d3d_depth_stencil. After a swapchain
flip they won't match with the GL resource any more. That's acceptable
for the debug FIXMEs, but could cause issues for FBO binding operations.
We could probably get away with it because all swapchain textures are
very similar, and ideally we won't re-attach the FBO after the initial
creation.

There are two non-debug uses of d3d_render_targets / d3d_depth_stencil:
Finding what to attach to the stencil slot, and catching multisample
mismatches. I'll move those away with separate patches.

Signed-off-by: Stefan Dösinger <stefan at codeweavers.com>
---
 dlls/wined3d/context.c         | 265 +++++++++++++++++++++++------------------
 dlls/wined3d/wined3d_private.h |  17 ++-
 2 files changed, 164 insertions(+), 118 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index a40f126..4a64576 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, rb_override);
+        }
+        else if (rb_namespace)
         {
             context_attach_depth_stencil_rb(gl_info, fbo_target,
-                    format_flags, depth_stencil->current_renderbuffer->id);
+                    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, gl_info, 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
@@ -269,15 +237,13 @@ void context_check_fbo_status(const struct wined3d_context *context, GLenum targ
             return;
         }
 
-        FIXME("\tColor Location %s (%#x).\n", wined3d_debug_location(context->current_fbo->color_location),
-                context->current_fbo->color_location);
-        FIXME("\tDepth Stencil Location %s (%#x).\n", wined3d_debug_location(context->current_fbo->ds_location),
-                context->current_fbo->ds_location);
+        FIXME("\tColor renderbuffer %u.\n", context->current_fbo->key.rb_namespace & 0x2);
+        FIXME("\tDepth Stencil Type %u.\n", context->current_fbo->key.rb_namespace & 0x1);
 
         /* Dump the FBO attachments */
         for (i = 0; i < gl_info->limits.buffers; ++i)
         {
-            attachment = context->current_fbo->render_targets[i];
+            attachment = context->current_fbo->d3d_render_targets[i];
             if (attachment)
             {
                 FIXME("\tColor attachment %d: (%p) %s %ux%u %u samples.\n",
@@ -285,7 +251,7 @@ void context_check_fbo_status(const struct wined3d_context *context, GLenum targ
                         attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
             }
         }
-        attachment = context->current_fbo->depth_stencil;
+        attachment = context->current_fbo->d3d_depth_stencil;
         if (attachment)
         {
             FIXME("\tDepth attachment: (%p) %s %ux%u %u samples.\n",
@@ -306,19 +272,74 @@ 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(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->container->texture_rgb.name;
+                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->container->texture_srgb.name;
+                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 inline void context_create_fbo_key(struct wined3d_fbo_entry_key *key,
+        struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
+        DWORD color_location, DWORD ds_location, UINT color_buffers)
+{
+    UINT i;
+
+    key->rb_namespace = 0;
+    context_set_fbo_key_for_surface(key, 0, depth_stencil, ds_location);
+
+    for (i = 0; i < color_buffers; ++i)
+        context_set_fbo_key_for_surface(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(), HEAP_ZERO_MEMORY,
+            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));
+    context_create_fbo_key(&entry->key, render_targets, depth_stencil, color_location, ds_location,
+            gl_info->limits.buffers);
+    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);
@@ -338,10 +359,10 @@ 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_create_fbo_key(&entry->key, render_targets, depth_stencil, color_location, ds_location,
+            gl_info->limits.buffers);
+    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;
 }
 
@@ -355,7 +376,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);
 }
 
@@ -366,6 +387,7 @@ 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;
 
     if (depth_stencil && render_targets && render_targets[0])
     {
@@ -377,17 +399,17 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context,
         }
     }
 
+    context_create_fbo_key(context->fbo_key, render_targets, depth_stencil, color_location,
+            ds_location, gl_info->limits.buffers);
+
     LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
     {
-        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)
-        {
-            list_remove(&entry->entry);
-            list_add_head(&context->fbo_list, &entry->entry);
-            return 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)
@@ -413,7 +435,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)
     {
@@ -428,25 +450,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
+    {
+        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. */
@@ -743,7 +776,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;
@@ -751,7 +784,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;
@@ -812,21 +845,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)
@@ -1528,6 +1556,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));
@@ -1880,6 +1913,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);
@@ -1911,6 +1945,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 d30b59d..8a78cd4 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1229,6 +1229,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. */
 
@@ -2374,15 +2375,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