From 28837ac970f103a54b877340030d8f080d63337b Mon Sep 17 00:00:00 2001 From: Italo Nicola Date: Mon, 19 Jun 2023 22:04:15 +0000 Subject: [PATCH] gallium: implement u_default_clear_texture MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit util_clear_texture implements clear_texture through a memset. This patch implements u_default_clear_texture, which tries to clear the given texture using a surface plus clear_render_target or clear_depth_stencil. In case this path fails, either because the formats are non-renderable or for some other reason, we fallback to `util_clear_texture`, which is guaranteed to work. This will allow us to make ARB_clear_texture available to every driver, as well as provide HW acceleration for the clear_texture operation. If some hardware doesn't want to use it, such as llvmpipe, it can always just directly point to the software version using pipe->clear_texture. Signed-off-by: Italo Nicola Reviewed-by: Alyssa Rosenzweig Reviewed-by: Erik Faye-Lund Reviewed-by: Marek Olšák Part-of: --- src/gallium/auxiliary/util/u_surface.c | 119 +++++++++++++++++++++++++ src/gallium/auxiliary/util/u_surface.h | 7 ++ src/util/format/u_format.h | 25 ++++++ 3 files changed, 151 insertions(+) diff --git a/src/gallium/auxiliary/util/u_surface.c b/src/gallium/auxiliary/util/u_surface.c index 5d3ac0cdd60..2746bdbd700 100644 --- a/src/gallium/auxiliary/util/u_surface.c +++ b/src/gallium/auxiliary/util/u_surface.c @@ -611,6 +611,125 @@ util_clear_depth_stencil_texture(struct pipe_context *pipe, } +/* Try to clear the texture as a surface, returns true if successful. + */ +static bool +util_clear_texture_as_surface(struct pipe_context *pipe, + struct pipe_resource *res, + unsigned level, + const struct pipe_box *box, + const void *data) +{ + struct pipe_surface tmpl = {{0}}, *sf; + + tmpl.format = res->format; + tmpl.u.tex.first_layer = box->z; + tmpl.u.tex.last_layer = box->z + box->depth - 1; + tmpl.u.tex.level = level; + + if (util_format_is_depth_or_stencil(res->format)) { + if (!pipe->clear_depth_stencil) + return false; + + sf = pipe->create_surface(pipe, res, &tmpl); + if (!sf) + return false; + + float depth = 0; + uint8_t stencil = 0; + unsigned clear = 0; + const struct util_format_description *desc = + util_format_description(tmpl.format); + + if (util_format_has_depth(desc)) { + clear |= PIPE_CLEAR_DEPTH; + util_format_unpack_z_float(tmpl.format, &depth, data, 1); + } + if (util_format_has_stencil(desc)) { + clear |= PIPE_CLEAR_STENCIL; + util_format_unpack_s_8uint(tmpl.format, &stencil, data, 1); + } + pipe->clear_depth_stencil(pipe, sf, clear, depth, stencil, + box->x, box->y, box->width, box->height, + false); + + pipe_surface_reference(&sf, NULL); + } else { + if (!pipe->clear_render_target) + return false; + + if (!pipe->screen->is_format_supported(pipe->screen, tmpl.format, + res->target, 0, 0, + PIPE_BIND_RENDER_TARGET)) { + tmpl.format = util_format_as_renderable(tmpl.format); + + if (tmpl.format == PIPE_FORMAT_NONE) + return false; + + if (!pipe->screen->is_format_supported(pipe->screen, tmpl.format, + res->target, 0, 0, + PIPE_BIND_RENDER_TARGET)) + return false; + } + + sf = pipe->create_surface(pipe, res, &tmpl); + if (!sf) + return false; + + union pipe_color_union color; + util_format_unpack_rgba(sf->format, color.ui, data, 1); + pipe->clear_render_target(pipe, sf, &color, box->x, box->y, + box->width, box->height, false); + + pipe_surface_reference(&sf, NULL); + } + + return true; +} + +/* First attempt to clear using HW, fallback to SW if needed. + */ +void +u_default_clear_texture(struct pipe_context *pipe, + struct pipe_resource *tex, + unsigned level, + const struct pipe_box *box, + const void *data) +{ + struct pipe_screen *screen = pipe->screen; + bool cleared = false; + assert(data != NULL); + + bool has_layers = screen->get_param(screen, PIPE_CAP_VS_INSTANCEID) && + screen->get_param(screen, PIPE_CAP_VS_LAYER_VIEWPORT); + + if (has_layers) { + cleared = util_clear_texture_as_surface(pipe, tex, level, + box, data); + } else { + struct pipe_box layer = *box; + layer.depth = 1; + int l; + for (l = box->z; l < box->z + box->depth; l++) { + layer.z = l; + cleared |= util_clear_texture_as_surface(pipe, tex, level, + &layer, data); + if (!cleared) { + /* If one layer is cleared, all layers should also be clearable. + * Therefore, if we fail on any later other than the first, it + * is a bug somewhere. + */ + assert(l == box->z); + break; + } + } + } + + /* Fallback to clearing it in SW if the HW paths failed. */ + if (!cleared) + util_clear_texture(pipe, tex, level, box, data); +} + void util_clear_texture(struct pipe_context *pipe, struct pipe_resource *tex, diff --git a/src/gallium/auxiliary/util/u_surface.h b/src/gallium/auxiliary/util/u_surface.h index c635239e846..e2166e370cd 100644 --- a/src/gallium/auxiliary/util/u_surface.h +++ b/src/gallium/auxiliary/util/u_surface.h @@ -82,6 +82,13 @@ util_resource_copy_region(struct pipe_context *pipe, unsigned src_level, const struct pipe_box *src_box); +extern void +u_default_clear_texture(struct pipe_context *pipe, + struct pipe_resource *tex, + unsigned level, + const struct pipe_box *box, + const void *data); + extern void util_clear_texture(struct pipe_context *pipe, struct pipe_resource *tex, diff --git a/src/util/format/u_format.h b/src/util/format/u_format.h index 2a9b84f6f00..011eeb04df6 100644 --- a/src/util/format/u_format.h +++ b/src/util/format/u_format.h @@ -1233,6 +1233,31 @@ util_format_stencil_only(enum pipe_format format) } } +static inline enum pipe_format +util_format_as_renderable(enum pipe_format format) +{ + switch (util_format_get_blocksizebits(format)) { + case 128: + return PIPE_FORMAT_R32G32B32A32_UINT; + case 96: + return PIPE_FORMAT_R32G32B32_UINT; + case 64: + return PIPE_FORMAT_R32G32_UINT; + case 48: + return PIPE_FORMAT_R16G16B16_UINT; + case 32: + return PIPE_FORMAT_R32_UINT; + case 24: + return PIPE_FORMAT_R8G8B8_UINT; + case 16: + return PIPE_FORMAT_R16_UINT; + case 8: + return PIPE_FORMAT_R8_UINT; + default: + return PIPE_FORMAT_NONE; + } +} + /** * Converts PIPE_FORMAT_*I* to PIPE_FORMAT_*R*. * This is identity for non-intensity formats. -- 2.34.1