svga: sync resource content from backing resource before image upload

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>
This commit is contained in:
Charmaine Lee 2023-06-07 23:49:28 +03:00 committed by Marge Bot
parent 83c76cceaf
commit 25c771a778
3 changed files with 66 additions and 12 deletions

View 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;

View 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"
@ -1346,6 +1347,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.
*/
@ -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);

View 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)
{