summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCharmaine Lee <[email protected]>2016-04-14 17:33:32 -0700
committerBrian Paul <[email protected]>2016-04-25 12:59:29 -0600
commitd7a6c1a4769774a0a86cc75090d5d3089f248a7d (patch)
tree293f352d62a79f46c27c5f1bfa29e25e0fd88320 /src
parent23949cdf2c85637448d9df0b0b4be647ac722b3a (diff)
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 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/svga/svga_resource_texture.c71
-rw-r--r--src/gallium/drivers/svga/svga_resource_texture.h29
2 files changed, 85 insertions, 15 deletions
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,