gallium: implement compute pbo download

this reworks PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER into an
enum as PIPE_CAP_TEXTURE_TRANSFER_MODES, enabling drivers to choose
a (sometimes) faster, compute-based download mechanism based on a new
pipe_screen hook

compute pbo download is implemented using shaders with a prolog to convert
the input format to generic rgb float values, then an epilog to convert
to the output value. the prolog and epilog are determined based on a vec4
of packed ubo data which is dynamically updated based on the API usage

currently, the only known limitations are:
* GL_ARB_texture_cube_map_array is broken somehow (and disabled)
* AMD hardware somehow can't do depth readback?

otherwise it should work for every possible case

Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>

Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11984>
This commit is contained in:
Mike Blumenkrantz 2021-08-05 15:28:52 -04:00
parent ed65b5e839
commit e7b9561959
9 changed files with 1157 additions and 19 deletions

View File

@ -181,7 +181,9 @@ The integer capabilities:
that are supported for implementing a texture transfer which needs format conversions that are supported for implementing a texture transfer which needs format conversions
and swizzling in gallium frontends. Generally, all hardware drivers with and swizzling in gallium frontends. Generally, all hardware drivers with
dedicated memory should return PIPE_TEXTURE_TRANSFER_BLIT and all software rasterizers dedicated memory should return PIPE_TEXTURE_TRANSFER_BLIT and all software rasterizers
should return PIPE_TEXTURE_TRANSFER_DEFAULT. should return PIPE_TEXTURE_TRANSFER_DEFAULT. PIPE_TEXTURE_TRANSFER_COMPUTE requires drivers
to support 8bit and 16bit shader storage buffer writes and to implement
pipe_screen::is_compute_copy_faster.
* ``PIPE_CAP_QUERY_PIPELINE_STATISTICS``: Whether PIPE_QUERY_PIPELINE_STATISTICS * ``PIPE_CAP_QUERY_PIPELINE_STATISTICS``: Whether PIPE_QUERY_PIPELINE_STATISTICS
is supported. is supported.
* ``PIPE_CAP_TEXTURE_BORDER_COLOR_QUIRK``: Bitmask indicating whether special * ``PIPE_CAP_TEXTURE_BORDER_COLOR_QUIRK``: Bitmask indicating whether special

View File

@ -1007,6 +1007,7 @@ enum pipe_cap
enum pipe_texture_transfer_mode { enum pipe_texture_transfer_mode {
PIPE_TEXTURE_TRANSFER_DEFAULT = 0, PIPE_TEXTURE_TRANSFER_DEFAULT = 0,
PIPE_TEXTURE_TRANSFER_BLIT = (1 << 0), PIPE_TEXTURE_TRANSFER_BLIT = (1 << 0),
PIPE_TEXTURE_TRANSFER_COMPUTE = (1 << 1),
}; };
/** /**

View File

@ -587,6 +587,7 @@ files_libmesa_gallium = files(
'state_tracker/st_nir_lower_builtin.c', 'state_tracker/st_nir_lower_builtin.c',
'state_tracker/st_nir_lower_tex_src_plane.c', 'state_tracker/st_nir_lower_tex_src_plane.c',
'state_tracker/st_pbo.c', 'state_tracker/st_pbo.c',
'state_tracker/st_pbo_compute.c',
'state_tracker/st_pbo.h', 'state_tracker/st_pbo.h',
'state_tracker/st_program.c', 'state_tracker/st_program.c',
'state_tracker/st_program.h', 'state_tracker/st_program.h',

View File

@ -51,6 +51,7 @@
#include "state_tracker/st_debug.h" #include "state_tracker/st_debug.h"
#include "state_tracker/st_context.h" #include "state_tracker/st_context.h"
#include "state_tracker/st_cb_bitmap.h" #include "state_tracker/st_cb_bitmap.h"
#include "state_tracker/st_cb_drawpixels.h"
#include "state_tracker/st_cb_fbo.h" #include "state_tracker/st_cb_fbo.h"
#include "state_tracker/st_cb_flush.h" #include "state_tracker/st_cb_flush.h"
#include "state_tracker/st_cb_texture.h" #include "state_tracker/st_cb_texture.h"
@ -2518,31 +2519,31 @@ st_GetTexSubImage(struct gl_context * ctx,
if (!st->prefer_blit_based_texture_transfer && if (!st->prefer_blit_based_texture_transfer &&
!_mesa_is_format_compressed(texImage->TexFormat)) { !_mesa_is_format_compressed(texImage->TexFormat)) {
/* Try to avoid the fallback if we're doing texture decompression here */ /* Try to avoid the non_blit_transfer if we're doing texture decompression here */
goto fallback; goto non_blit_transfer;
} }
/* Handle non-finalized textures. */ /* Handle non-finalized textures. */
if (!stImage->pt || stImage->pt != stObj->pt || !src) { if (!stImage->pt || stImage->pt != stObj->pt || !src) {
goto fallback; goto cpu_transfer;
} }
/* XXX Fallback to _mesa_GetTexImage_sw for depth-stencil formats /* XXX Fallback to _mesa_GetTexImage_sw for depth-stencil formats
* due to an incomplete stencil blit implementation in some drivers. */ * due to an incomplete stencil blit implementation in some drivers. */
if (format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX) { if (format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX) {
goto fallback; goto non_blit_transfer;
} }
/* If the base internal format and the texture format don't match, we have /* If the base internal format and the texture format don't match, we have
* to fall back to _mesa_GetTexImage_sw. */ * to fall back to _mesa_GetTexImage_sw. */
if (texImage->_BaseFormat != if (texImage->_BaseFormat !=
_mesa_get_format_base_format(texImage->TexFormat)) { _mesa_get_format_base_format(texImage->TexFormat)) {
goto fallback; goto non_blit_transfer;
} }
src_format = st_pbo_get_src_format(screen, stObj->surface_based ? stObj->surface_format : src->format, src); src_format = st_pbo_get_src_format(screen, stObj->surface_based ? stObj->surface_format : src->format, src);
if (src_format == PIPE_FORMAT_NONE) if (src_format == PIPE_FORMAT_NONE)
goto fallback; goto non_blit_transfer;
if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL) if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
bind = PIPE_BIND_DEPTH_STENCIL; bind = PIPE_BIND_DEPTH_STENCIL;
@ -2552,7 +2553,7 @@ st_GetTexSubImage(struct gl_context * ctx,
dst_format = st_pbo_get_dst_format(ctx, pipe_target, src_format, util_format_is_compressed(src->format), dst_format = st_pbo_get_dst_format(ctx, pipe_target, src_format, util_format_is_compressed(src->format),
format, type, bind); format, type, bind);
if (dst_format == PIPE_FORMAT_NONE) if (dst_format == PIPE_FORMAT_NONE)
goto fallback; goto non_blit_transfer;
if (st->pbo.download_enabled && ctx->Pack.BufferObj) { if (st->pbo.download_enabled && ctx->Pack.BufferObj) {
if (try_pbo_download(st, texImage, if (try_pbo_download(st, texImage,
@ -2567,11 +2568,11 @@ st_GetTexSubImage(struct gl_context * ctx,
* in which case the memcpy-based fast path will be used. */ * in which case the memcpy-based fast path will be used. */
if (_mesa_format_matches_format_and_type(texImage->TexFormat, format, if (_mesa_format_matches_format_and_type(texImage->TexFormat, format,
type, ctx->Pack.SwapBytes, NULL)) type, ctx->Pack.SwapBytes, NULL))
goto fallback; goto non_blit_transfer;
dst = create_dst_texture(ctx, dst_format, pipe_target, width, height, depth, gl_target, bind); dst = create_dst_texture(ctx, dst_format, pipe_target, width, height, depth, gl_target, bind);
if (!dst) if (!dst)
goto fallback; goto non_blit_transfer;
/* From now on, we need the gallium representation of dimensions. */ /* From now on, we need the gallium representation of dimensions. */
if (gl_target == GL_TEXTURE_1D_ARRAY) { if (gl_target == GL_TEXTURE_1D_ARRAY) {
@ -2612,12 +2613,17 @@ st_GetTexSubImage(struct gl_context * ctx,
depth, format, type, pixels, texImage); depth, format, type, pixels, texImage);
pipe_resource_reference(&dst, NULL); pipe_resource_reference(&dst, NULL);
fallback: non_blit_transfer:
if (!done) { if (done)
_mesa_GetTexSubImage_sw(ctx, xoffset, yoffset, zoffset, return;
width, height, depth, if (st->allow_compute_based_texture_transfer) {
format, type, pixels, texImage); if (st_GetTexSubImage_shader(ctx, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels, texImage))
return;
} }
cpu_transfer:
_mesa_GetTexSubImage_sw(ctx, xoffset, yoffset, zoffset,
width, height, depth,
format, type, pixels, texImage);
} }

View File

@ -625,6 +625,11 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe,
st_init_atoms(st); st_init_atoms(st);
st_init_clear(st); st_init_clear(st);
{
enum pipe_texture_transfer_mode val = screen->get_param(screen, PIPE_CAP_TEXTURE_TRANSFER_MODES);
st->prefer_blit_based_texture_transfer = (val & PIPE_TEXTURE_TRANSFER_BLIT) != 0;
st->allow_compute_based_texture_transfer = (val & PIPE_TEXTURE_TRANSFER_COMPUTE) != 0;
}
st_init_pbo_helpers(st); st_init_pbo_helpers(st);
/* Choose texture target for glDrawPixels, glBitmap, renderbuffers */ /* Choose texture target for glDrawPixels, glBitmap, renderbuffers */
@ -689,10 +694,6 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe,
st->has_astc_5x5_ldr = st->has_astc_5x5_ldr =
screen->is_format_supported(screen, PIPE_FORMAT_ASTC_5x5_SRGB, screen->is_format_supported(screen, PIPE_FORMAT_ASTC_5x5_SRGB,
PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_SAMPLER_VIEW); PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_SAMPLER_VIEW);
{
enum pipe_texture_transfer_mode val = screen->get_param(screen, PIPE_CAP_TEXTURE_TRANSFER_MODES);
st->prefer_blit_based_texture_transfer = (val & PIPE_TEXTURE_TRANSFER_BLIT) == PIPE_TEXTURE_TRANSFER_BLIT;
}
st->force_persample_in_shader = st->force_persample_in_shader =
screen->get_param(screen, PIPE_CAP_SAMPLE_SHADING) && screen->get_param(screen, PIPE_CAP_SAMPLE_SHADING) &&
!screen->get_param(screen, PIPE_CAP_FORCE_PERSAMPLE_INTERP); !screen->get_param(screen, PIPE_CAP_FORCE_PERSAMPLE_INTERP);

View File

@ -147,6 +147,7 @@ struct st_context
boolean has_astc_2d_ldr; boolean has_astc_2d_ldr;
boolean has_astc_5x5_ldr; boolean has_astc_5x5_ldr;
boolean prefer_blit_based_texture_transfer; boolean prefer_blit_based_texture_transfer;
boolean allow_compute_based_texture_transfer;
boolean force_persample_in_shader; boolean force_persample_in_shader;
boolean has_shareable_shaders; boolean has_shareable_shaders;
boolean has_half_float_packing; boolean has_half_float_packing;
@ -326,6 +327,7 @@ struct st_context
void *gs; void *gs;
void *upload_fs[5][2]; void *upload_fs[5][2];
void *download_fs[5][PIPE_MAX_TEXTURE_TYPES][2]; void *download_fs[5][PIPE_MAX_TEXTURE_TYPES][2];
struct hash_table *shaders;
bool upload_enabled; bool upload_enabled;
bool download_enabled; bool download_enabled;
bool rgba_only; bool rgba_only;

View File

@ -661,6 +661,9 @@ st_init_pbo_helpers(struct st_context *st)
/* Rasterizer state */ /* Rasterizer state */
memset(&st->pbo.raster, 0, sizeof(struct pipe_rasterizer_state)); memset(&st->pbo.raster, 0, sizeof(struct pipe_rasterizer_state));
st->pbo.raster.half_pixel_center = 1; st->pbo.raster.half_pixel_center = 1;
if (st->allow_compute_based_texture_transfer)
st->pbo.shaders = _mesa_hash_table_create_u32_keys(NULL);
} }
void void
@ -697,4 +700,10 @@ st_destroy_pbo_helpers(struct st_context *st)
st->pipe->delete_vs_state(st->pipe, st->pbo.vs); st->pipe->delete_vs_state(st->pipe, st->pbo.vs);
st->pbo.vs = NULL; st->pbo.vs = NULL;
} }
if (st->pbo.shaders) {
hash_table_foreach(st->pbo.shaders, entry)
st->pipe->delete_compute_state(st->pipe, entry->data);
_mesa_hash_table_destroy(st->pbo.shaders, NULL);
}
} }

View File

@ -110,6 +110,12 @@ st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target,
enum pipe_format dst_format, enum pipe_format dst_format,
bool need_layer); bool need_layer);
bool
st_GetTexSubImage_shader(struct gl_context * ctx,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLint depth,
GLenum format, GLenum type, void * pixels,
struct gl_texture_image *texImage);
enum pipe_format enum pipe_format
st_pbo_get_dst_format(struct gl_context *ctx, enum pipe_texture_target target, st_pbo_get_dst_format(struct gl_context *ctx, enum pipe_texture_target target,

File diff suppressed because it is too large Load Diff