From c4edc048c6f6877461a9d9dc07142640f380f340 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 13 Oct 2015 20:50:22 -0700 Subject: [PATCH] i965/meta/gen9: Individually fast clear color attachments The impetus for this patch comes from a seemingly benign statement within the spec (quoted within the patch). It is very important for clearing multiple color buffer attachments and can be observed in the following piglit tests: spec/arb_framebuffer_object/fbo-drawbuffers-none glclear spec/ext_framebuffer_multisample/blit-multiple-render-targets 0 v2: Doing the framebuffer binding only once (Chad) Directly use the renderbuffers from the mt (Chad) v3: Patch from Neil whose feedback I originally missed. Signed-off-by: Ben Widawsky Reviewed-by: Chad Versace Reviewed-by: Neil Roberts --- .../drivers/dri/i965/brw_meta_fast_clear.c | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_meta_fast_clear.c b/src/mesa/drivers/dri/i965/brw_meta_fast_clear.c index 938e028f58d..7bf68194b71 100644 --- a/src/mesa/drivers/dri/i965/brw_meta_fast_clear.c +++ b/src/mesa/drivers/dri/i965/brw_meta_fast_clear.c @@ -427,6 +427,55 @@ use_rectlist(struct brw_context *brw, bool enable) brw->ctx.NewDriverState |= BRW_NEW_FRAGMENT_PROGRAM; } +/** + * Individually fast clear each color buffer attachment. On previous gens this + * isn't required. The motivation for this comes from one line (which seems to + * be specific to SKL+). The list item is in section titled _MCS Buffer for + * Render Target(s)_ + * + * "Since only one RT is bound with a clear pass, only one RT can be cleared + * at a time. To clear multiple RTs, multiple clear passes are required." + * + * The code follows the same idea as the resolve code which creates a fake FBO + * to avoid interfering with too much of the GL state. + */ +static void +fast_clear_attachments(struct brw_context *brw, + struct gl_framebuffer *fb, + uint32_t fast_clear_buffers, + struct rect fast_clear_rect) +{ + assert(brw->gen >= 9); + struct gl_context *ctx = &brw->ctx; + + brw_bind_rep_write_shader(brw, (float *) fast_clear_color); + + /* SKL+ also has a resolve mode for compressed render targets and thus more + * bits to let us select the type of resolve. For fast clear resolves, it + * turns out we can use the same value as pre-SKL though. + */ + set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE); + + while (fast_clear_buffers) { + int index = ffs(fast_clear_buffers) - 1; + + fast_clear_buffers &= ~(1 << index); + + _mesa_meta_drawbuffers_from_bitfield(1 << index); + + brw_draw_rectlist(ctx, &fast_clear_rect, MAX2(1, fb->MaxNumLayers)); + + /* Now set the mcs we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll + * resolve them eventually. + */ + struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[0]; + struct intel_renderbuffer *irb = intel_renderbuffer(rb); + irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; + } + + set_fast_clear_op(brw, 0); +} + bool brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb, GLbitfield buffers, bool partial_clear) @@ -609,12 +658,27 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb, use_rectlist(brw, true); layers = MAX2(1, fb->MaxNumLayers); - if (fast_clear_buffers) { + + if (brw->gen >= 9 && fast_clear_buffers) { + fast_clear_attachments(brw, fb, fast_clear_buffers, fast_clear_rect); + } else if (fast_clear_buffers) { _mesa_meta_drawbuffers_from_bitfield(fast_clear_buffers); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE); brw_draw_rectlist(ctx, &fast_clear_rect, layers); set_fast_clear_op(brw, 0); + + /* Now set the mcs we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll + * resolve them eventually. + */ + for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { + struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; + struct intel_renderbuffer *irb = intel_renderbuffer(rb); + int index = fb->_ColorDrawBufferIndexes[buf]; + + if ((1 << index) & fast_clear_buffers) + irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; + } } if (rep_clear_buffers) { @@ -623,18 +687,6 @@ brw_meta_fast_clear(struct brw_context *brw, struct gl_framebuffer *fb, brw_draw_rectlist(ctx, &clear_rect, layers); } - /* Now set the mts we cleared to INTEL_FAST_CLEAR_STATE_CLEAR so we'll - * resolve them eventually. - */ - for (unsigned buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { - struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf]; - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - int index = fb->_ColorDrawBufferIndexes[buf]; - - if ((1 << index) & fast_clear_buffers) - irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_CLEAR; - } - bail_to_meta: /* Dirty _NEW_BUFFERS so we reemit SURFACE_STATE which sets the fast clear * color before resolve and sets irb->mt->fast_clear_state to UNRESOLVED if -- 2.30.2