svga: sync resource content from backing resource before image upload
authorCharmaine Lee <charmainel@vmware.com>
Wed, 7 Jun 2023 20:49:28 +0000 (23:49 +0300)
committerMarge Bot <emma+marge@anholt.net>
Tue, 26 Sep 2023 21:38:01 +0000 (21:38 +0000)
When a backing resource is created for a render target view when the
same resource is currently bound to a shader resource view, the content
update back to the original resource happens when the associated render
target view is unbound. But state update only happens at clear or draw
time. So if TexSubImage happens after BindFrameBuffer and before Draw,
the original texture resource that is mapped to for subimage update
would not have been updated. As a matter of fact at the subsequent state
update at the next draw, the render target views will be updated, the
content from the previous backing resource will be propogated to the
original resource, hence overwriting the changes from the last TexSubImage.

To fix the problem, this patch validates the texture resource, updates
any pending changes from the backing resource before transfer map upload
occurs.

Fixes the rendering issue demonstrated from the fbo_texsubimage_update trace

Reviewed-by: Martin Krastev <krastevm@vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25386>

src/gallium/drivers/svga/svga_pipe_draw.c
src/gallium/drivers/svga/svga_resource_texture.c
src/gallium/drivers/svga/svga_surface.h

index bd88f5b..7208756 100644 (file)
@@ -1,5 +1,5 @@
 /**********************************************************
- * Copyright 2008-2009 VMware, Inc.  All rights reserved.
+ * Copyright 2008-2023 VMware, Inc.  All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -245,15 +245,6 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info,
        svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK)
       goto done;
 
-   /*
-    * Mark currently bound target surfaces as dirty
-    * doesn't really matter if it is done before drawing.
-    *
-    * TODO If we ever normaly return something other then
-    * true we should not mark it as dirty then.
-    */
-   svga_mark_surfaces_dirty(svga_context(pipe));
-
    if (svga->curr.reduced_prim != reduced_prim) {
       svga->curr.reduced_prim = reduced_prim;
       svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
@@ -373,6 +364,11 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info,
       }
    }
 
+   /*
+    * Mark currently bound target surfaces as dirty after draw is completed.
+    */
+   svga_mark_surfaces_dirty(svga_context(pipe));
+
    /* XXX: Silence warnings, do something sensible here? */
    (void)ret;
 
index 8ce5b94..17d91d1 100644 (file)
@@ -43,6 +43,7 @@
 #include "svga_resource_texture.h"
 #include "svga_resource_buffer.h"
 #include "svga_sampler_view.h"
+#include "svga_surface.h"
 #include "svga_winsys.h"
 #include "svga_debug.h"
 
@@ -1347,6 +1348,51 @@ svga_texture_transfer_map_can_upload(const struct svga_screen *svgascreen,
 
 
 /**
+ *  Return TRUE if the same texture is bound to the specified
+ *  surface view and a backing resource is created for the surface view.
+ */
+static bool
+need_update_texture_resource(struct pipe_surface *surf,
+                            struct svga_texture *tex)
+{
+   struct svga_texture *stex = svga_texture(surf->texture);
+   struct svga_surface *s = svga_surface(surf);
+
+   return (stex == tex && s->handle != tex->handle);
+}
+
+
+/**
+ *  Make sure the texture resource is up-to-date. If the texture is
+ *  currently bound to a render target view and a backing resource is
+ *  created, we will need to update the original resource with the
+ *  changes in the backing resource.
+ */
+static void
+svga_validate_texture_resource(struct svga_context *svga,
+                              struct svga_texture *tex)
+{
+   if (svga_was_texture_rendered_to(tex) == false)
+      return;
+
+   if ((svga->state.hw_draw.has_backed_views == false) ||
+       (tex->backed_handle == NULL))
+      return;
+
+   struct pipe_surface *s;
+   for (unsigned i = 0; i < svga->state.hw_clear.num_rendertargets; i++) {
+      s = svga->state.hw_clear.rtv[i];
+      if (s && need_update_texture_resource(s, tex))
+         svga_propagate_surface(svga, s, true);
+   }
+
+   s = svga->state.hw_clear.dsv;
+   if (s && need_update_texture_resource(s, tex))
+      svga_propagate_surface(svga, s, true);
+}
+
+
+/**
  * Use upload buffer for the transfer map request.
  */
 void *
@@ -1355,6 +1401,7 @@ svga_texture_transfer_map_upload(struct svga_context *svga,
 {
    struct pipe_resource *texture = st->base.resource;
    struct pipe_resource *tex_buffer = NULL;
+   struct svga_texture *tex = svga_texture(texture);
    void *tex_map;
    unsigned nblocksx, nblocksy;
    unsigned offset;
@@ -1362,6 +1409,14 @@ svga_texture_transfer_map_upload(struct svga_context *svga,
 
    assert(svga->tex_upload);
 
+   /* Validate the texture resource in case there is any changes
+    * in the backing resource that needs to be updated to the original
+    * texture resource first before the transfer upload occurs, otherwise,
+    * the later update from backing resource to original will overwrite the
+    * changes in this transfer map update.
+    */
+   svga_validate_texture_resource(svga, tex);
+
    st->upload.box.x = st->base.box.x;
    st->upload.box.y = st->base.box.y;
    st->upload.box.z = st->base.box.z;
@@ -1407,7 +1462,6 @@ svga_texture_transfer_map_upload(struct svga_context *svga,
 
 #ifdef DEBUG
    if (util_format_is_compressed(texture->format)) {
-      struct svga_texture *tex = svga_texture(texture);
       unsigned blockw, blockh, bytesPerBlock;
 
       svga_format_size(tex->key.format, &blockw, &blockh, &bytesPerBlock);
index b2745f4..48ad4b4 100644 (file)
@@ -1,5 +1,5 @@
 /**********************************************************
- * Copyright 2008-2009 VMware, Inc.  All rights reserved.
+ * Copyright 2008-2023 VMware, Inc.  All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -142,6 +142,10 @@ svga_surface_const(const struct pipe_surface *surface)
 struct pipe_surface *
 svga_validate_surface_view(struct svga_context *svga, struct svga_surface *s);
 
+void
+svga_propagate_surface(struct svga_context *svga, struct pipe_surface *surf,
+                       bool reset);
+
 static inline SVGA3dResourceType
 svga_resource_type(enum pipe_texture_target target)
 {