From 131b42f0aa574cc654c5970ba48c4d1896f6d502 Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Tue, 19 Feb 2019 16:07:09 -0800 Subject: iris: Implement fast clear color. If all the restrictions are satisfied, do a fast clear instead of regular clear. v2: - add perf_debug() when we can't fast clear (Ken) - improve comment: s/miptree/resource/ (Ken) - use swizzle_color_value from blorp (Ken) Reviewed-by: Kenneth Graunke --- src/gallium/drivers/iris/iris_clear.c | 180 +++++++++++++++++++++++++++++----- src/gallium/drivers/iris/iris_state.c | 1 - 2 files changed, 157 insertions(+), 24 deletions(-) (limited to 'src/gallium/drivers/iris') diff --git a/src/gallium/drivers/iris/iris_clear.c b/src/gallium/drivers/iris/iris_clear.c index d61f2fd5b43..62c42feeb15 100644 --- a/src/gallium/drivers/iris/iris_clear.c +++ b/src/gallium/drivers/iris/iris_clear.c @@ -36,10 +36,93 @@ #include "intel/compiler/brw_compiler.h" #include "util/format_srgb.h" +static bool +iris_is_color_fast_clear_compatible(struct iris_context *ice, + enum isl_format format, + const union isl_color_value color) +{ + struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; + const struct gen_device_info *devinfo = &batch->screen->devinfo; + + if (isl_format_has_int_channel(format)) { + perf_debug(&ice->dbg, "Integer fast clear not enabled for %s", + isl_format_get_name(format)); + return false; + } + + for (int i = 0; i < 4; i++) { + if (!isl_format_has_color_component(format, i)) { + continue; + } + + if (devinfo->gen < 9 && + color.f32[i] != 0.0f && color.f32[i] != 1.0f) { + return false; + } + } + + return true; +} + +static bool +can_fast_clear_color(struct iris_context *ice, + struct pipe_resource *p_res, + unsigned level, + const struct pipe_box *box, + enum isl_format format, + enum isl_format render_format, + union isl_color_value color) +{ + struct iris_resource *res = (void *) p_res; + + struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; + const struct gen_device_info *devinfo = &batch->screen->devinfo; + + /* XXX: Need to fix channel select for gen8 before enabling this. */ + if (devinfo->gen != 9) + return false; + + if (res->aux.usage == ISL_AUX_USAGE_NONE) + return false; + + /* Surface state can only record one fast clear color value. Therefore + * unless different levels/layers agree on the color it can be used to + * represent only single level/layer. Here it will be reserved for the + * first slice (level 0, layer 0). + */ + if (level > 0 || box->z > 0 || box->depth > 1) + return false; + + /* Check for partial clear */ + if (box->x > 0 || box->y > 0 || + box->width < p_res->width0 || + box->height < p_res->height0) { + return false; + } + + /* We store clear colors as floats or uints as needed. If there are + * texture views in play, the formats will not properly be respected + * during resolves because the resolve operations only know about the + * resource and not the renderbuffer. + */ + if (render_format != format) + return false; + + /* XXX: if (irb->mt->supports_fast_clear) + * see intel_miptree_create_for_dri_image() + */ + + if (!iris_is_color_fast_clear_compatible(ice, format, color)) + return false; + + return true; +} + static union isl_color_value convert_fast_clear_color(struct iris_context *ice, struct iris_resource *res, - const union isl_color_value color) + const union isl_color_value color, + struct isl_swizzle swizzle) { union isl_color_value override_color = color; struct pipe_resource *p_res = (void *) res; @@ -49,23 +132,7 @@ convert_fast_clear_color(struct iris_context *ice, util_format_description(format); unsigned colormask = util_format_colormask(desc); - /* The sampler doesn't look at the format of the surface when the fast - * clear color is used so we need to implement luminance, intensity and - * missing components manually. - */ - if (util_format_is_intensity(format) || - util_format_is_luminance(format) || - util_format_is_luminance_alpha(format)) { - override_color.u32[1] = override_color.u32[0]; - override_color.u32[2] = override_color.u32[0]; - if (util_format_is_intensity(format)) - override_color.u32[3] = override_color.u32[0]; - } else { - for (int chan = 0; chan < 3; chan++) { - if (!(colormask & (1 << chan))) - override_color.u32[chan] = 0; - } - } + override_color = swizzle_color_value(color, swizzle); if (util_format_is_unorm(format)) { for (int i = 0; i < 4; i++) @@ -117,6 +184,65 @@ convert_fast_clear_color(struct iris_context *ice, return override_color; } +static void +fast_clear_color(struct iris_context *ice, + struct iris_resource *res, + unsigned level, + const struct pipe_box *box, + enum isl_format format, + union isl_color_value color, + struct isl_swizzle swizzle, + enum blorp_batch_flags blorp_flags) +{ + struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; + struct pipe_resource *p_res = (void *) res; + const enum isl_aux_state aux_state = + iris_resource_get_aux_state(res, level, box->z); + + color = convert_fast_clear_color(ice, res, color, swizzle); + + iris_resource_set_clear_color(ice, res, color); + + /* If the buffer is already in ISL_AUX_STATE_CLEAR, the clear + * is redundant and can be skipped. + */ + if (aux_state == ISL_AUX_STATE_CLEAR) + return; + + /* Ivybrigde PRM Vol 2, Part 1, "11.7 MCS Buffer for Render Target(s)": + * + * "Any transition from any value in {Clear, Render, Resolve} to a + * different value in {Clear, Render, Resolve} requires end of pipe + * synchronization." + * + * In other words, fast clear ops are not properly synchronized with + * other drawing. We need to use a PIPE_CONTROL to ensure that the + * contents of the previous draw hit the render target before we resolve + * and again afterwards to ensure that the resolve is complete before we + * do any more regular drawing. + */ + iris_emit_end_of_pipe_sync(batch, PIPE_CONTROL_RENDER_TARGET_FLUSH); + + struct blorp_batch blorp_batch; + blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags); + + struct blorp_surf surf; + iris_blorp_surf_for_resource(&ice->vtbl, &surf, p_res, res->aux.usage, + level, true); + + blorp_fast_clear(&blorp_batch, &surf, format, + level, box->z, box->depth, + box->x, box->y, box->x + box->width, + box->y + box->height); + blorp_batch_finish(&blorp_batch); + iris_emit_end_of_pipe_sync(batch, PIPE_CONTROL_RENDER_TARGET_FLUSH); + + iris_resource_set_aux_state(ice, res, level, box->z, + box->depth, ISL_AUX_STATE_CLEAR); + ice->state.dirty |= IRIS_ALL_DIRTY_BINDINGS; + return; +} + static void clear_color(struct iris_context *ice, struct pipe_resource *p_res, @@ -131,7 +257,7 @@ clear_color(struct iris_context *ice, struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; const struct gen_device_info *devinfo = &batch->screen->devinfo; - enum blorp_batch_flags blorp_flags = 0; + enum blorp_batch_flags blorp_flags = BLORP_BATCH_NO_UPDATE_CLEAR_COLOR; if (render_condition_enabled) { if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER) @@ -143,8 +269,13 @@ clear_color(struct iris_context *ice, iris_batch_maybe_flush(batch, 1500); - struct blorp_batch blorp_batch; - blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags); + bool can_fast_clear = can_fast_clear_color(ice, p_res, level, box, + res->surf.format, format, color); + if (can_fast_clear) { + fast_clear_color(ice, res, level, box, format, color, + swizzle, blorp_flags); + return; + } bool color_write_disable[4] = { false, false, false, false }; enum isl_aux_usage aux_usage = @@ -158,6 +289,9 @@ clear_color(struct iris_context *ice, iris_blorp_surf_for_resource(&ice->vtbl, &surf, p_res, aux_usage, level, true); + struct blorp_batch blorp_batch; + blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags); + if (!isl_format_supports_rendering(devinfo, format) && isl_format_is_rgbx(format)) format = isl_format_rgbx_to_rgba(format); @@ -256,8 +390,8 @@ fast_clear_depth(struct iris_context *ice, ISL_AUX_STATE_RESOLVED); } } - const union isl_color_value clear_color = { .f32 = {depth, } }; - iris_resource_set_clear_color(ice, res, clear_color); + const union isl_color_value clear_value = { .f32 = {depth, } }; + iris_resource_set_clear_color(ice, res, clear_value); } for (unsigned l = 0; l < box->depth; l++) { diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 81313f81064..d27de09e236 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -1651,7 +1651,6 @@ fill_surface_state(struct isl_device *isl_dev, f.aux_surf = &res->aux.surf; f.aux_usage = aux_usage; f.aux_address = res->aux.bo->gtt_offset + res->aux.offset; - // XXX: clear color } isl_surf_fill_state_s(isl_dev, map, &f); -- cgit v1.2.3