[PATCH 2/6] wined3d: Store the context's current rendertarget as a texture and sub-resource index.

Henri Verbeet hverbeet at codeweavers.com
Tue Mar 29 09:45:32 CDT 2016


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/context.c         | 119 ++++++++++++++++++++++++++---------------
 dlls/wined3d/query.c           |  14 ++---
 dlls/wined3d/surface.c         |  44 +++++++--------
 dlls/wined3d/wined3d_private.h |  15 +++++-
 4 files changed, 119 insertions(+), 73 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index dfeb4fb..41647f5 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -852,22 +852,26 @@ static void context_queue_fbo_entry_destruction(struct wined3d_context *context,
 void context_resource_released(const struct wined3d_device *device,
         struct wined3d_resource *resource, enum wined3d_resource_type type)
 {
+    struct wined3d_texture *texture;
     UINT i;
-    struct wined3d_surface *surface;
 
     if (!device->d3d_initialized)
         return;
 
     switch (type)
     {
-        case WINED3D_RTYPE_SURFACE:
-            surface = surface_from_resource(resource);
+        case WINED3D_RTYPE_TEXTURE_2D:
+        case WINED3D_RTYPE_TEXTURE_3D:
+            texture = wined3d_texture_from_resource(resource);
 
             for (i = 0; i < device->context_count; ++i)
             {
                 struct wined3d_context *context = device->contexts[i];
-                if (context->current_rt == surface)
-                    context->current_rt = NULL;
+                if (context->current_rt.texture == texture)
+                {
+                    context->current_rt.texture = NULL;
+                    context->current_rt.sub_resource_idx = 0;
+                }
             }
             break;
 
@@ -1318,7 +1322,8 @@ void context_release(struct wined3d_context *context)
  * A to avoid breaking caller code. */
 void context_restore(struct wined3d_context *context, struct wined3d_surface *restore)
 {
-    if (context->current_rt != restore)
+    if (context->current_rt.texture != restore->container
+            || context->current_rt.sub_resource_idx != surface_get_sub_resource_idx(restore))
     {
         context_release(context);
         context = context_acquire(restore->container->resource.device, restore);
@@ -1777,7 +1782,8 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     }
 
     ret->swapchain = swapchain;
-    ret->current_rt = target->sub_resources[0].u.surface;
+    ret->current_rt.texture = target;
+    ret->current_rt.sub_resource_idx = 0;
     ret->tid = GetCurrentThreadId();
 
     ret->render_offscreen = wined3d_resource_is_offscreen(&target->resource);
@@ -2031,9 +2037,10 @@ static void set_blit_dimension(const struct wined3d_gl_info *gl_info, UINT width
 
 static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
 {
-    const struct wined3d_surface *rt = context->current_rt;
+    const struct wined3d_texture *rt = context->current_rt.texture;
+    unsigned int level;
 
-    if (rt->container->swapchain && rt->container->swapchain->front_buffer == rt->container)
+    if (rt->swapchain && rt->swapchain->front_buffer == rt)
     {
         RECT window_size;
 
@@ -2044,8 +2051,9 @@ static void context_get_rt_size(const struct wined3d_context *context, SIZE *siz
         return;
     }
 
-    size->cx = rt->resource.width;
-    size->cy = rt->resource.height;
+    level = context->current_rt.sub_resource_idx % rt->level_count;
+    size->cx = wined3d_texture_get_level_width(rt, level);
+    size->cy = wined3d_texture_get_level_height(rt, level);
 }
 
 /*****************************************************************************
@@ -2412,7 +2420,8 @@ static void context_validate_onscreen_formats(struct wined3d_context *context,
         const struct wined3d_rendertarget_view *depth_stencil)
 {
     /* Onscreen surfaces are always in a swapchain */
-    struct wined3d_swapchain *swapchain = context->current_rt->container->swapchain;
+    struct wined3d_swapchain *swapchain = context->current_rt.texture->swapchain;
+    struct wined3d_surface *surface;
 
     if (context->render_offscreen || !depth_stencil) return;
     if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->format)) return;
@@ -2423,7 +2432,8 @@ static void context_validate_onscreen_formats(struct wined3d_context *context,
     WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
 
     /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
-    surface_load_location(context->current_rt, context, WINED3D_LOCATION_TEXTURE_RGB);
+    surface = context->current_rt.texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
+    surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
     swapchain->render_to_fbo = TRUE;
     swapchain_update_draw_bindings(swapchain);
     context_set_render_offscreen(context, TRUE);
@@ -2458,7 +2468,8 @@ static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_context *conte
 /* Context activation is done by the caller. */
 void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
 {
-    struct wined3d_surface *rt = context->current_rt;
+    struct wined3d_texture *rt = context->current_rt.texture;
+    struct wined3d_surface *surface;
     DWORD rt_mask, *cur_mask;
 
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
@@ -2467,10 +2478,11 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine
 
         if (context->render_offscreen)
         {
-            wined3d_texture_load(rt->container, context, FALSE);
+            wined3d_texture_load(rt, context, FALSE);
 
-            context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, rt, NULL, rt->container->resource.draw_binding);
-            if (rt->container->resource.format->id != WINED3DFMT_NULL)
+            surface = rt->sub_resources[context->current_rt.sub_resource_idx].u.surface;
+            context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, surface, NULL, rt->resource.draw_binding);
+            if (rt->resource.format->id != WINED3DFMT_NULL)
                 rt_mask = 1;
             else
                 rt_mask = 0;
@@ -2479,12 +2491,12 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine
         {
             context->current_fbo = NULL;
             context_bind_fbo(context, GL_FRAMEBUFFER, 0);
-            rt_mask = context_generate_rt_mask_from_resource(&rt->container->resource);
+            rt_mask = context_generate_rt_mask_from_resource(&rt->resource);
         }
     }
     else
     {
-        rt_mask = context_generate_rt_mask_no_fbo(context, rt->container);
+        rt_mask = context_generate_rt_mask_no_fbo(context, rt);
     }
 
     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
@@ -3418,34 +3430,38 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
     return TRUE;
 }
 
-static void context_setup_target(struct wined3d_context *context, struct wined3d_surface *target)
+static void context_setup_target(struct wined3d_context *context,
+        struct wined3d_texture *texture, unsigned int sub_resource_idx)
 {
     BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
 
-    render_offscreen = wined3d_resource_is_offscreen(&target->container->resource);
-    if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
+    render_offscreen = wined3d_resource_is_offscreen(&texture->resource);
+    if (context->current_rt.texture == texture
+            && context->current_rt.sub_resource_idx == sub_resource_idx
+            && render_offscreen == old_render_offscreen)
+        return;
 
     /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
      * the alpha blend state changes with different render target formats. */
-    if (!context->current_rt)
+    if (!context->current_rt.texture)
     {
         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
     }
     else
     {
-        const struct wined3d_format *old = context->current_rt->container->resource.format;
-        const struct wined3d_format *new = target->container->resource.format;
+        const struct wined3d_format *old = context->current_rt.texture->resource.format;
+        const struct wined3d_format *new = texture->resource.format;
 
         if (old->id != new->id)
         {
             /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
             if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
-                    || !(target->container->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
+                    || !(texture->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
 
             /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
-            if ((context->current_rt->container->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
-                    != (target->container->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
+            if ((context->current_rt.texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
+                    != (texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
         }
 
@@ -3457,25 +3473,32 @@ static void context_setup_target(struct wined3d_context *context, struct wined3d
          * has to be called with the old rendertarget active, otherwise a
          * wrong drawable is read. */
         if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
-                && old_render_offscreen && context->current_rt != target)
+                && old_render_offscreen && (context->current_rt.texture != texture
+                || context->current_rt.sub_resource_idx != sub_resource_idx))
         {
-            struct wined3d_texture *texture = context->current_rt->container;
+            unsigned int prev_sub_resource_idx = context->current_rt.sub_resource_idx;
+            struct wined3d_texture *prev_texture = context->current_rt.texture;
+            struct wined3d_surface *prev_surface;
 
             /* Read the back buffer of the old drawable into the destination texture. */
-            if (texture->texture_srgb.name)
-                wined3d_texture_load(texture, context, TRUE);
-            wined3d_texture_load(texture, context, FALSE);
-            surface_invalidate_location(context->current_rt, WINED3D_LOCATION_DRAWABLE);
+            if (prev_texture->texture_srgb.name)
+                wined3d_texture_load(prev_texture, context, TRUE);
+            wined3d_texture_load(prev_texture, context, FALSE);
+            prev_surface = prev_texture->sub_resources[prev_sub_resource_idx].u.surface;
+            surface_invalidate_location(prev_surface, WINED3D_LOCATION_DRAWABLE);
         }
     }
 
-    context->current_rt = target;
+    context->current_rt.texture = texture;
+    context->current_rt.sub_resource_idx = sub_resource_idx;
     context_set_render_offscreen(context, render_offscreen);
 }
 
 struct wined3d_context *context_acquire(const struct wined3d_device *device, struct wined3d_surface *target)
 {
     struct wined3d_context *current_context = context_get_current();
+    struct wined3d_texture *target_texture;
+    unsigned int target_sub_resource_idx;
     struct wined3d_context *context;
 
     TRACE("device %p, target %p.\n", device, target);
@@ -3483,33 +3506,41 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
     if (current_context && current_context->destroyed)
         current_context = NULL;
 
-    if (!target)
+    if (target)
+    {
+        target_texture = target->container;
+        target_sub_resource_idx = surface_get_sub_resource_idx(target);
+    }
+    else
     {
         if (current_context
-                && current_context->current_rt
+                && current_context->current_rt.texture
                 && current_context->swapchain->device == device)
         {
-            target = current_context->current_rt;
+            target_texture = current_context->current_rt.texture;
+            target_sub_resource_idx = current_context->current_rt.sub_resource_idx;
         }
         else
         {
             struct wined3d_swapchain *swapchain = device->swapchains[0];
+
             if (swapchain->back_buffers)
-                target = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0));
+                target_texture = swapchain->back_buffers[0];
             else
-                target = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0));
+                target_texture = swapchain->front_buffer;
+            target_sub_resource_idx = 0;
         }
     }
 
-    if (current_context && current_context->current_rt == target)
+    if (current_context && current_context->current_rt.texture == target_texture)
     {
         context = current_context;
     }
-    else if (target->container->swapchain)
+    else if (target_texture->swapchain)
     {
         TRACE("Rendering onscreen.\n");
 
-        context = swapchain_get_context(target->container->swapchain);
+        context = swapchain_get_context(target_texture->swapchain);
     }
     else
     {
@@ -3525,7 +3556,7 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
 
     context_enter(context);
     context_update_window(context);
-    context_setup_target(context, target);
+    context_setup_target(context, target_texture, target_sub_resource_idx);
     if (!context->valid) return context;
 
     if (context != current_context)
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index b86adf1..410ce6c 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -58,7 +58,7 @@ static enum wined3d_event_query_result wined3d_event_query_test(const struct win
         return WINED3D_EVENT_QUERY_WRONG_THREAD;
     }
 
-    context = context_acquire(device, query->context->current_rt);
+    context = context_acquire(device, context_get_rt_surface(query->context));
     gl_info = context->gl_info;
 
     if (gl_info->supported[ARB_SYNC])
@@ -132,7 +132,7 @@ enum wined3d_event_query_result wined3d_event_query_finish(const struct wined3d_
         return WINED3D_EVENT_QUERY_WRONG_THREAD;
     }
 
-    context = context_acquire(device, query->context->current_rt);
+    context = context_acquire(device, context_get_rt_surface(query->context));
 
     if (gl_info->supported[ARB_SYNC])
     {
@@ -192,7 +192,7 @@ void wined3d_event_query_issue(struct wined3d_event_query *query, const struct w
         }
         else
         {
-            context = context_acquire(device, query->context->current_rt);
+            context = context_acquire(device, context_get_rt_surface(query->context));
         }
     }
     else
@@ -348,7 +348,7 @@ static HRESULT wined3d_occlusion_query_ops_get_data(struct wined3d_query *query,
         return S_OK;
     }
 
-    context = context_acquire(query->device, oq->context->current_rt);
+    context = context_acquire(device, context_get_rt_surface(oq->context));
 
     GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
     checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
@@ -490,7 +490,7 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
                 }
                 else
                 {
-                    context = context_acquire(query->device, oq->context->current_rt);
+                    context = context_acquire(device, context_get_rt_surface(oq->context));
 
                     GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
                     checkGLcall("glEndQuery()");
@@ -522,7 +522,7 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
                 }
                 else
                 {
-                    context = context_acquire(query->device, oq->context->current_rt);
+                    context = context_acquire(device, context_get_rt_surface(oq->context));
 
                     GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
                     checkGLcall("glEndQuery()");
@@ -578,7 +578,7 @@ static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
         return S_OK;
     }
 
-    context = context_acquire(query->device, tq->context->current_rt);
+    context = context_acquire(device, context_get_rt_surface(tq->context));
 
     GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
     checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 114b368..cd8c863 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -108,8 +108,8 @@ void surface_get_drawable_size(const struct wined3d_surface *surface, const stru
         /* The drawable size of an onscreen drawable is the surface size.
          * (Actually: The window size, but the surface is created in window
          * size.) */
-        *width = context->current_rt->resource.width;
-        *height = context->current_rt->resource.height;
+        *width = context->current_rt.texture->resource.width;
+        *height = context->current_rt.texture->resource.height;
     }
     else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
     {
@@ -123,10 +123,13 @@ void surface_get_drawable_size(const struct wined3d_surface *surface, const stru
     }
     else
     {
+        struct wined3d_surface *rt;
+
         /* The drawable size of an FBO target is the OpenGL texture size,
          * which is the power of two size. */
-        *width = context->current_rt->pow2Width;
-        *height = context->current_rt->pow2Height;
+        rt = context->current_rt.texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
+        *width = rt->pow2Width;
+        *height = rt->pow2Height;
     }
 }
 
@@ -675,11 +678,11 @@ static void surface_blt_fbo(const struct wined3d_device *device,
     else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
     else required_rt = NULL;
 
-    if (required_rt && required_rt != old_ctx->current_rt)
-    {
-        restore_rt = old_ctx->current_rt;
+    restore_rt = context_get_rt_surface(old_ctx);
+    if (restore_rt != required_rt)
         context = context_acquire(device, required_rt);
-    }
+    else
+        restore_rt = NULL;
 
     if (!context->valid)
     {
@@ -1852,11 +1855,11 @@ static void read_from_framebuffer(struct wined3d_surface *surface,
 
     surface_get_memory(surface, &data, dst_location);
 
-    if (surface != old_ctx->current_rt)
-    {
-        restore_rt = old_ctx->current_rt;
+    restore_rt = context_get_rt_surface(old_ctx);
+    if (restore_rt != surface)
         context = context_acquire(device, surface);
-    }
+    else
+        restore_rt = NULL;
 
     context_apply_blit_state(context, device);
     gl_info = context->gl_info;
@@ -1962,11 +1965,11 @@ void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct
     struct wined3d_context *context = old_ctx;
     struct wined3d_surface *restore_rt = NULL;
 
-    if (old_ctx->current_rt != surface)
-    {
-        restore_rt = old_ctx->current_rt;
+    restore_rt = context_get_rt_surface(old_ctx);
+    if (restore_rt != surface)
         context = context_acquire(device, surface);
-    }
+    else
+        restore_rt = NULL;
 
     gl_info = context->gl_info;
     device_invalidate_state(device, STATE_FRAMEBUFFER);
@@ -2485,12 +2488,11 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
     src_rect = *src_rect_in;
     dst_rect = *dst_rect_in;
 
-
-    if (old_ctx->current_rt != dst_surface)
-    {
-        restore_rt = old_ctx->current_rt;
+    restore_rt = context_get_rt_surface(old_ctx);
+    if (restore_rt != dst_surface)
         context = context_acquire(device, dst_surface);
-    }
+    else
+        restore_rt = NULL;
 
     gl_info = context->gl_info;
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 6e5b96b..d6645fa 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1274,7 +1274,11 @@ struct wined3d_context
     DWORD isStateDirty[STATE_HIGHEST / (sizeof(DWORD) * CHAR_BIT) + 1]; /* Bitmap to find out quickly if a state is dirty */
 
     struct wined3d_swapchain *swapchain;
-    struct wined3d_surface *current_rt;
+    struct
+    {
+        struct wined3d_texture *texture;
+        unsigned int sub_resource_idx;
+    } current_rt;
     DWORD                   tid;    /* Thread ID which owns this context at the moment */
 
     /* Stores some information about the context state for optimization */
@@ -3464,6 +3468,15 @@ static inline BOOL can_use_texture_swizzle(const struct wined3d_gl_info *gl_info
             && !is_scaling_fixup(format->color_fixup);
 }
 
+static inline struct wined3d_surface *context_get_rt_surface(const struct wined3d_context *context)
+{
+    struct wined3d_texture *texture = context->current_rt.texture;
+
+    if (!texture)
+        return NULL;
+    return texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
+}
+
 /* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */
 #define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"
 
-- 
2.1.4




More information about the wine-patches mailing list