From: Charmaine Lee Date: Fri, 15 Apr 2016 00:33:32 +0000 (-0700) Subject: svga: minimize surface flush X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d7a6c1a4769774a0a86cc75090d5d3089f248a7d;p=mesa.git svga: minimize surface flush Currently, we always do a surface flush when we try to establish a synchronized write transfer map. But if the subresource has not been modified, we can skip the surface flush. In other words, we only need to do a surface flush if the to-be-mapped subresource has been modified in this command buffer. With this patch, lightsmark2008 shows about 15% performance improvement. Reviewed-by: Brian Paul --- diff --git a/src/gallium/drivers/svga/svga_resource_texture.c b/src/gallium/drivers/svga/svga_resource_texture.c index db730802c7a..ae5122843a6 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.c +++ b/src/gallium/drivers/svga/svga_resource_texture.c @@ -234,6 +234,7 @@ svga_texture_destroy(struct pipe_screen *screen, FREE(tex->defined); FREE(tex->rendered_to); + FREE(tex->dirty); FREE(tex); assert(ss->hud.num_resources > 0); @@ -436,6 +437,13 @@ svga_texture_transfer_map(struct pipe_context *pipe, return NULL; } + /* If this is the first time mapping to the surface in this + * command buffer, clear the dirty masks of this surface. + */ + if (sws->surface_is_flushed(sws, surf)) { + svga_clear_texture_dirty(tex); + } + if (need_tex_readback(transfer)) { enum pipe_error ret; @@ -464,13 +472,21 @@ svga_texture_transfer_map(struct pipe_context *pipe, else { assert(transfer->usage & PIPE_TRANSFER_WRITE); if ((transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) == 0) { - svga_surfaces_flush(svga); - if (!sws->surface_is_flushed(sws, surf)) { - svga->hud.surface_write_flushes++; - svga_context_flush(svga, NULL); + if (svga_is_texture_dirty(tex, st->slice, transfer->level)) { + /* + * do a surface flush if the subresource has been modified + * in this command buffer. + */ + svga_surfaces_flush(svga); + if (!sws->surface_is_flushed(sws, surf)) { + svga->hud.surface_write_flushes++; + svga_context_flush(svga, NULL); + } } } } + /* mark this texture level as dirty */ + svga_set_texture_dirty(tex, st->slice, transfer->level); } st->use_direct_map = use_direct_map; @@ -756,9 +772,13 @@ svga_texture_create(struct pipe_screen *screen, tex->rendered_to = CALLOC(template->depth0 * template->array_size, sizeof(tex->rendered_to[0])); if (!tex->rendered_to) { - FREE(tex->defined); - FREE(tex); - return NULL; + goto fail; + } + + tex->dirty = CALLOC(template->depth0 * template->array_size, + sizeof(tex->dirty[0])); + if (!tex->dirty) { + goto fail; } tex->b.b = *template; @@ -872,10 +892,7 @@ svga_texture_create(struct pipe_screen *screen, tex->key.format = svga_translate_format(svgascreen, template->format, bindings); if (tex->key.format == SVGA3D_FORMAT_INVALID) { - FREE(tex->defined); - FREE(tex->rendered_to); - FREE(tex); - return NULL; + goto fail; } /* Use typeless formats for sRGB and depth resources. Typeless @@ -900,10 +917,7 @@ svga_texture_create(struct pipe_screen *screen, tex->handle = svga_screen_surface_create(svgascreen, bindings, tex->b.b.usage, &tex->key); if (!tex->handle) { - FREE(tex->defined); - FREE(tex->rendered_to); - FREE(tex); - return NULL; + goto fail; } SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle); @@ -916,6 +930,16 @@ svga_texture_create(struct pipe_screen *screen, svgascreen->hud.num_resources++; return &tex->b.b; + +fail: + if (tex->dirty) + FREE(tex->dirty); + if (tex->rendered_to) + FREE(tex->rendered_to); + if (tex->defined) + FREE(tex->defined); + FREE(tex); + return NULL; } @@ -993,11 +1017,28 @@ svga_texture_from_handle(struct pipe_screen *screen, tex->handle = srf; tex->rendered_to = CALLOC(1, sizeof(tex->rendered_to[0])); + if (!tex->rendered_to) + goto fail; + + tex->dirty = CALLOC(1, sizeof(tex->dirty[0])); + if (!tex->dirty) + goto fail; + tex->imported = TRUE; ss->hud.num_resources++; return &tex->b.b; + +fail: + if (tex->defined) + FREE(tex->defined); + if (tex->rendered_to) + FREE(tex->rendered_to); + if (tex->dirty) + FREE(tex->dirty); + FREE(tex); + return NULL; } boolean diff --git a/src/gallium/drivers/svga/svga_resource_texture.h b/src/gallium/drivers/svga/svga_resource_texture.h index 283b87fa780..e779f19fbad 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.h +++ b/src/gallium/drivers/svga/svga_resource_texture.h @@ -87,6 +87,11 @@ struct svga_texture /** array indexed by cube face or 3D/array slice, one bit per mipmap level */ ushort *rendered_to; + + /** array indexed by cube face or 3D/array slice, one bit per mipmap level. + * Set if the level is marked as dirty. + */ + ushort *dirty; }; @@ -207,6 +212,30 @@ svga_was_texture_rendered_to(const struct svga_texture *tex, return !!(tex->rendered_to[face] & (1 << level)); } +static inline void +svga_set_texture_dirty(struct svga_texture *tex, + unsigned face, unsigned level) +{ + check_face_level(tex, face, level); + tex->dirty[face] |= 1 << level; +} + +static inline void +svga_clear_texture_dirty(struct svga_texture *tex) +{ + unsigned i; + for (i = 0; i < tex->b.b.depth0 * tex->b.b.array_size; i++) { + tex->dirty[i] = 0; + } +} + +static inline boolean +svga_is_texture_dirty(const struct svga_texture *tex, + unsigned face, unsigned level) +{ + check_face_level(tex, face, level); + return !!(tex->dirty[face] & (1 << level)); +} struct pipe_resource * svga_texture_create(struct pipe_screen *screen,