[Mesa-dev] [PATCH 6/6] freedreno: support invalidate_{sub_}surface

Rob Clark robdclark at gmail.com
Tue Dec 11 22:50:08 UTC 2018


Signed-off-by: Rob Clark <robdclark at gmail.com>
---
 src/gallium/drivers/freedreno/a6xx/fd6_gmem.c |  3 +-
 .../drivers/freedreno/freedreno_batch.c       |  1 +
 .../drivers/freedreno/freedreno_batch.h       |  8 +-
 .../drivers/freedreno/freedreno_draw.c        | 99 ++++++++++++-------
 .../drivers/freedreno/freedreno_resource.c    | 41 ++++++++
 .../drivers/freedreno/freedreno_state.h       | 10 ++
 .../drivers/freedreno/freedreno_surface.h     | 18 ++++
 7 files changed, 145 insertions(+), 35 deletions(-)

diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c b/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c
index 8cda7d6ddae..0a82f69fc62 100644
--- a/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c
+++ b/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c
@@ -36,6 +36,7 @@
 #include "freedreno_draw.h"
 #include "freedreno_state.h"
 #include "freedreno_resource.h"
+#include "freedreno_surface.h"
 
 #include "fd6_gmem.h"
 #include "fd6_context.h"
@@ -901,7 +902,7 @@ emit_resolve_blit(struct fd_batch *batch,
 {
 	uint32_t info = 0;
 
-	if (!rsc->valid)
+	if (!fd_surface_valid(psurf))
 		return;
 
 	switch (buffer) {
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.c b/src/gallium/drivers/freedreno/freedreno_batch.c
index eae2f68ce11..280a412222a 100644
--- a/src/gallium/drivers/freedreno/freedreno_batch.c
+++ b/src/gallium/drivers/freedreno/freedreno_batch.c
@@ -78,6 +78,7 @@ batch_init(struct fd_batch *batch)
 	batch->cleared = 0;
 	batch->fast_cleared = 0;
 	batch->invalidated = 0;
+	batch->partial_invalidated = 0;
 	batch->restore = batch->resolve = 0;
 	batch->needs_flush = false;
 	batch->flushed = false;
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h b/src/gallium/drivers/freedreno/freedreno_batch.h
index a40d36094cd..b5c1c321bf0 100644
--- a/src/gallium/drivers/freedreno/freedreno_batch.h
+++ b/src/gallium/drivers/freedreno/freedreno_batch.h
@@ -95,7 +95,13 @@ struct fd_batch {
 		FD_BUFFER_DEPTH   = PIPE_CLEAR_DEPTH,
 		FD_BUFFER_STENCIL = PIPE_CLEAR_STENCIL,
 		FD_BUFFER_ALL     = FD_BUFFER_COLOR | FD_BUFFER_DEPTH | FD_BUFFER_STENCIL,
-	} invalidated, cleared, fast_cleared, restore, resolve;
+	} invalidated, partial_invalidated, cleared, fast_cleared, restore, resolve;
+
+	/* for partially invalidated fb surfaces, track the invalidated rect: */
+	struct {
+		struct pipe_scissor_state zsbuf;
+		struct pipe_scissor_state cbuf[8];
+	} invalid;
 
 	/* is this a non-draw batch (ie compute/blit which has no pfb state)? */
 	bool nondraw : 1;
diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c
index f17cb563063..07c3ecfa805 100644
--- a/src/gallium/drivers/freedreno/freedreno_draw.c
+++ b/src/gallium/drivers/freedreno/freedreno_draw.c
@@ -36,6 +36,7 @@
 #include "freedreno_context.h"
 #include "freedreno_fence.h"
 #include "freedreno_state.h"
+#include "freedreno_surface.h"
 #include "freedreno_resource.h"
 #include "freedreno_query_acc.h"
 #include "freedreno_query_hw.h"
@@ -57,6 +58,14 @@ resource_written(struct fd_batch *batch, struct pipe_resource *prsc)
 	fd_batch_resource_used(batch, fd_resource(prsc), true);
 }
 
+static void
+surface_valid(struct pipe_surface *psurf)
+{
+	struct fd_surface *surf = fd_surface(psurf);
+	surf->invalid = false;
+	surf->partial_invalid = false;
+}
+
 static void
 fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 {
@@ -138,59 +147,78 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 	mtx_lock(&ctx->screen->lock);
 
 	if (ctx->dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_ZSA)) {
+		unsigned b = 0;
 		if (fd_depth_enabled(ctx)) {
-			if (fd_resource(pfb->zsbuf->texture)->valid) {
-				restore_buffers |= FD_BUFFER_DEPTH;
-			} else {
-				batch->invalidated |= FD_BUFFER_DEPTH;
-			}
-			buffers |= FD_BUFFER_DEPTH;
-			resource_written(batch, pfb->zsbuf->texture);
+			b |= FD_BUFFER_DEPTH;
 			batch->gmem_reason |= FD_GMEM_DEPTH_ENABLED;
 		}
 
 		if (fd_stencil_enabled(ctx)) {
-			if (fd_resource(pfb->zsbuf->texture)->valid) {
-				restore_buffers |= FD_BUFFER_STENCIL;
+			b |= FD_BUFFER_STENCIL;
+			batch->gmem_reason |= FD_GMEM_STENCIL_ENABLED;
+		}
+
+		if (b) {
+			if (fd_surface_valid(pfb->zsbuf)) {
+				restore_buffers |= b;
+			} else if (fd_surface_partially_valid(pfb->zsbuf)) {
+				restore_buffers |= b;
+				batch->partial_invalidated |= b;
+				batch->invalid.zsbuf = fd_surface(pfb->zsbuf)->invalid_rect;
 			} else {
-				batch->invalidated |= FD_BUFFER_STENCIL;
+				batch->invalidated |= b;
+			}
+			buffers |= b;
+
+			if (fd_depth_write_enabled(ctx) ||
+					fd_stencil_write_enabled(ctx)) {
+				resource_written(batch, pfb->zsbuf->texture);
+			} else {
+				resource_read(batch, pfb->zsbuf->texture);
 			}
-			buffers |= FD_BUFFER_STENCIL;
-			resource_written(batch, pfb->zsbuf->texture);
-			batch->gmem_reason |= FD_GMEM_STENCIL_ENABLED;
 		}
 	}
 
 	if (ctx->dirty & FD_DIRTY_FRAMEBUFFER) {
 		for (i = 0; i < pfb->nr_cbufs; i++) {
-			if (!pfb->cbufs[i])
+			struct pipe_surface *psurf = pfb->cbufs[i];
+
+			if (!psurf)
 				continue;
 
+			if (fd_surface_valid(psurf)) {
+				restore_buffers |= PIPE_CLEAR_COLOR0 << i;
+			} else if (fd_surface_partially_valid(psurf)) {
+				restore_buffers |= PIPE_CLEAR_COLOR0 << i;
+				batch->partial_invalidated |= PIPE_CLEAR_COLOR0 << i;
+				batch->invalid.cbuf[i] = fd_surface(psurf)->invalid_rect;
+			} else {
+				batch->invalidated |= PIPE_CLEAR_COLOR0 << i;
+			}
+
+			buffers |= PIPE_CLEAR_COLOR0 << i;
+
 			resource_written(batch, pfb->cbufs[i]->texture);
 		}
 	}
 
-	if (fd_logicop_enabled(ctx))
-		batch->gmem_reason |= FD_GMEM_LOGICOP_ENABLED;
+	if (pfb->zsbuf)
+		surface_valid(pfb->zsbuf);
 
-	for (i = 0; i < pfb->nr_cbufs; i++) {
-		struct pipe_resource *surf;
+	for (i = 0; i < pfb->nr_cbufs; i++)
+		surface_valid(pfb->cbufs[i]);
 
-		if (!pfb->cbufs[i])
-			continue;
+	if (fd_logicop_enabled(ctx))
+		batch->gmem_reason |= FD_GMEM_LOGICOP_ENABLED;
 
-		surf = pfb->cbufs[i]->texture;
+	if (ctx->dirty & FD_DIRTY_BLEND) {
+		for (i = 0; i < pfb->nr_cbufs; i++) {
+			if (!pfb->cbufs[i])
+				continue;
 
-		if (fd_resource(surf)->valid) {
-			restore_buffers |= PIPE_CLEAR_COLOR0 << i;
-		} else {
-			batch->invalidated |= PIPE_CLEAR_COLOR0 << i;
+			if (fd_blend_enabled(ctx, i))
+				batch->gmem_reason |= FD_GMEM_BLEND_ENABLED;
 		}
-
-		buffers |= PIPE_CLEAR_COLOR0 << i;
-
-		if (fd_blend_enabled(ctx, i))
-			batch->gmem_reason |= FD_GMEM_BLEND_ENABLED;
 	}
 
 	/* Mark SSBOs as being written.. we don't actually know which ones are
@@ -420,13 +448,18 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
 
 	mtx_lock(&ctx->screen->lock);
 
-	if (buffers & PIPE_CLEAR_COLOR)
-		for (i = 0; i < pfb->nr_cbufs; i++)
-			if (buffers & (PIPE_CLEAR_COLOR0 << i))
+	if (buffers & PIPE_CLEAR_COLOR) {
+		for (i = 0; i < pfb->nr_cbufs; i++) {
+			if (buffers & (PIPE_CLEAR_COLOR0 << i)) {
 				resource_written(batch, pfb->cbufs[i]->texture);
+				surface_valid(pfb->cbufs[i]);
+			}
+		}
+	}
 
 	if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
 		resource_written(batch, pfb->zsbuf->texture);
+		surface_valid(pfb->zsbuf);
 		batch->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL;
 	}
 
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c
index 85bbbe271f9..283f7de89bc 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.c
+++ b/src/gallium/drivers/freedreno/freedreno_resource.c
@@ -1124,6 +1124,17 @@ fd_blitter_pipe_end(struct fd_context *ctx)
 	ctx->in_blit = false;
 }
 
+/**
+ * Invalidate the contents of the resource. This is used to
+ *
+ * (1) implement EGL's semantic of undefined depth/stencil
+ * contents after a swapbuffers.  This allows a tiled renderer (for
+ * example) to not store the depth buffer.
+ *
+ * (2) implement GL's InvalidateBufferData. For backwards compatibility,
+ * you must only rely on the usability for this purpose when
+ * PIPE_CAP_INVALIDATE_BUFFER is enabled.
+ */
 static void
 fd_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
 {
@@ -1152,6 +1163,34 @@ fd_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
 	rsc->valid = false;
 }
 
+/**
+ * Like ->invalidate_surface, but can invalidate a specific layer and level
+ * of a resource.  If the backing surf->texture has just a single layer and
+ * level (like window system buffers) it is equiv to ->invalidate_resource
+ */
+static void
+fd_invalidate_surface(struct pipe_context *pctx, struct pipe_surface *psurf)
+{
+	fd_surface(psurf)->invalid = true;
+}
+
+/**
+ * Invalidate a portion of a surface.  This is used to
+ *
+ * (1) implement glInvalidateSubFramebuffer() and friends
+ * (2) as a hint before a scissored clear (which is turned into draw_vbo()
+ *     that the cleared rect can be discarded
+ */
+static void
+fd_invalidate_sub_surface(struct pipe_context *pctx,
+		struct pipe_surface *psurf, const struct pipe_scissor_state *rect)
+{
+	struct fd_surface *surf = fd_surface(psurf);
+
+	surf->partial_invalid = true;
+	surf->invalid_rect = *rect;
+}
+
 static enum pipe_format
 fd_resource_get_internal_format(struct pipe_resource *prsc)
 {
@@ -1261,5 +1300,7 @@ fd_resource_context_init(struct pipe_context *pctx)
 	pctx->blit = fd_blit;
 	pctx->flush_resource = fd_flush_resource;
 	pctx->invalidate_resource = fd_invalidate_resource;
+	pctx->invalidate_surface = fd_invalidate_surface;
+	pctx->invalidate_sub_surface = fd_invalidate_sub_surface;
 	pctx->get_sample_position = fd_get_sample_position;
 }
diff --git a/src/gallium/drivers/freedreno/freedreno_state.h b/src/gallium/drivers/freedreno/freedreno_state.h
index 35584e41e3a..18e90dc0056 100644
--- a/src/gallium/drivers/freedreno/freedreno_state.h
+++ b/src/gallium/drivers/freedreno/freedreno_state.h
@@ -35,11 +35,21 @@ static inline bool fd_depth_enabled(struct fd_context *ctx)
 	return ctx->zsa && ctx->zsa->depth.enabled;
 }
 
+static inline bool fd_depth_write_enabled(struct fd_context *ctx)
+{
+	return ctx->zsa && ctx->zsa->depth.writemask;
+}
+
 static inline bool fd_stencil_enabled(struct fd_context *ctx)
 {
 	return ctx->zsa && ctx->zsa->stencil[0].enabled;
 }
 
+static inline bool fd_stencil_write_enabled(struct fd_context *ctx)
+{
+	return ctx->zsa && ctx->zsa->stencil[0].writemask;
+}
+
 static inline bool fd_logicop_enabled(struct fd_context *ctx)
 {
 	return ctx->blend && ctx->blend->logicop_enable;
diff --git a/src/gallium/drivers/freedreno/freedreno_surface.h b/src/gallium/drivers/freedreno/freedreno_surface.h
index 8898f890eda..489bc705e9a 100644
--- a/src/gallium/drivers/freedreno/freedreno_surface.h
+++ b/src/gallium/drivers/freedreno/freedreno_surface.h
@@ -29,8 +29,13 @@
 
 #include "pipe/p_state.h"
 
+#include "freedreno_resource.h"
+
 struct fd_surface {
 	struct pipe_surface base;
+	bool invalid;
+	bool partial_invalid;
+	struct pipe_scissor_state invalid_rect;
 };
 
 static inline struct fd_surface *
@@ -39,6 +44,19 @@ fd_surface(struct pipe_surface *psurf)
 	return (struct fd_surface *)psurf;
 }
 
+static inline bool
+fd_surface_valid(struct pipe_surface *psurf)
+{
+	return fd_resource(psurf->texture)->valid &&
+			!fd_surface(psurf)->invalid;
+}
+
+static inline bool
+fd_surface_partially_valid(struct pipe_surface *psurf)
+{
+	return fd_surface(psurf)->partial_invalid;
+}
+
 struct pipe_surface* fd_create_surface(struct pipe_context *pctx,
 		struct pipe_resource *ptex,
 		const struct pipe_surface *surf_tmpl);
-- 
2.19.2



More information about the mesa-dev mailing list