From 2ebca177dc188a10db93a087ce18c2f3042d9b1c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 2 Nov 2018 11:31:42 -0700 Subject: [PATCH] v3d: Use the TFU to do generatemipmap. This is a separate, dedicated hardware unit for texture layout conversions and mipmap generation. --- src/gallium/drivers/v3d/v3d_blit.c | 104 ++++++++++++++++++++ src/gallium/drivers/v3d/v3d_context.h | 11 ++- src/gallium/drivers/v3d/v3d_formats.c | 11 +++ src/gallium/drivers/v3d/v3d_resource.c | 1 + src/gallium/drivers/v3d/v3d_screen.c | 17 ++++ src/gallium/drivers/v3d/v3dx_context.h | 1 + src/gallium/drivers/v3d/v3dx_format_table.c | 31 ++++++ 7 files changed, 175 insertions(+), 1 deletion(-) diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c index 1a0406a6ed9..f2ded8bbf72 100644 --- a/src/gallium/drivers/v3d/v3d_blit.c +++ b/src/gallium/drivers/v3d/v3d_blit.c @@ -25,6 +25,7 @@ #include "util/u_surface.h" #include "util/u_blitter.h" #include "v3d_context.h" +#include "v3d_tiling.h" #if 0 static struct pipe_surface * @@ -316,6 +317,109 @@ v3d_stencil_blit(struct pipe_context *ctx, const struct pipe_blit_info *info) pipe_sampler_view_reference(&src_view, NULL); } +/* Disable level 0 write, just write following mipmaps */ +#define V3D_TFU_IOA_DIMTW (1 << 0) +#define V3D_TFU_IOA_FORMAT_SHIFT 3 +#define V3D_TFU_IOA_FORMAT_LINEARTILE 3 +#define V3D_TFU_IOA_FORMAT_UBLINEAR_1_COLUMN 4 +#define V3D_TFU_IOA_FORMAT_UBLINEAR_2_COLUMN 5 +#define V3D_TFU_IOA_FORMAT_UIF_NO_XOR 6 +#define V3D_TFU_IOA_FORMAT_UIF_XOR 7 + +#define V3D_TFU_ICFG_NUMMM_SHIFT 5 +#define V3D_TFU_ICFG_TTYPE_SHIFT 9 + +#define V3D_TFU_ICFG_FORMAT_SHIFT 18 +#define V3D_TFU_ICFG_FORMAT_RASTER 0 +#define V3D_TFU_ICFG_FORMAT_SAND_128 1 +#define V3D_TFU_ICFG_FORMAT_SAND_256 2 +#define V3D_TFU_ICFG_FORMAT_LINEARTILE 11 +#define V3D_TFU_ICFG_FORMAT_UBLINEAR_1_COLUMN 12 +#define V3D_TFU_ICFG_FORMAT_UBLINEAR_2_COLUMN 13 +#define V3D_TFU_ICFG_FORMAT_UIF_NO_XOR 14 +#define V3D_TFU_ICFG_FORMAT_UIF_XOR 15 + +boolean +v3d_generate_mipmap(struct pipe_context *pctx, + struct pipe_resource *prsc, + enum pipe_format format, + unsigned int base_level, + unsigned int last_level, + unsigned int first_layer, + unsigned int last_layer) +{ + struct v3d_context *v3d = v3d_context(pctx); + struct v3d_screen *screen = v3d->screen; + struct v3d_resource *rsc = v3d_resource(prsc); + struct v3d_resource_slice *base_slice = &rsc->slices[base_level]; + int width = u_minify(prsc->width0, base_level); + int height = u_minify(prsc->height0, base_level); + uint32_t tex_format = v3d_get_tex_format(&screen->devinfo, + prsc->format); + + if (!v3d_tfu_supports_tex_format(&screen->devinfo, tex_format)) + return false; + + if (prsc->target != PIPE_TEXTURE_2D) + return false; + /* Since we don't support array or 3D textures, there should be only + * one layer. + */ + int layer = first_layer; + assert(first_layer == last_layer); + + /* Can't write to raster. */ + if (base_slice->tiling == VC5_TILING_RASTER) + return false; + + v3d_flush_jobs_reading_resource(v3d, prsc); + + struct drm_v3d_submit_tfu tfu = { + .ios = (height << 16) | width, + .bo_handles = { rsc->bo->handle }, + .in_sync = v3d->out_sync, + .out_sync = v3d->out_sync, + }; + uint32_t offset = (rsc->bo->offset + + v3d_layer_offset(prsc, base_level, layer)); + tfu.iia |= offset; + tfu.icfg |= ((V3D_TFU_ICFG_FORMAT_LINEARTILE + + (base_slice->tiling - VC5_TILING_LINEARTILE)) << + V3D_TFU_ICFG_FORMAT_SHIFT); + + tfu.ioa |= offset; + tfu.ioa |= V3D_TFU_IOA_DIMTW; + tfu.ioa |= ((V3D_TFU_IOA_FORMAT_LINEARTILE + + (base_slice->tiling - VC5_TILING_LINEARTILE)) << + V3D_TFU_IOA_FORMAT_SHIFT); + + tfu.icfg |= tex_format << V3D_TFU_ICFG_TTYPE_SHIFT; + tfu.icfg |= (last_level - base_level) << V3D_TFU_ICFG_NUMMM_SHIFT; + + switch (base_slice->tiling) { + case VC5_TILING_UIF_NO_XOR: + case VC5_TILING_UIF_XOR: + tfu.iis |= (base_slice->padded_height / + (2 * v3d_utile_height(rsc->cpp))); + break; + case VC5_TILING_RASTER: + tfu.iis |= base_slice->stride; + break; + case VC5_TILING_LINEARTILE: + case VC5_TILING_UBLINEAR_1_COLUMN: + case VC5_TILING_UBLINEAR_2_COLUMN: + break; + } + + int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_SUBMIT_TFU, &tfu); + if (ret != 0) { + fprintf(stderr, "Failed to submit TFU job: %d\n", ret); + return false; + } + + return true; +} + /* Optimal hardware path for blitting pixels. * Scaling, format conversion, up- and downsampling (resolve) are allowed. */ diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h index 4c3779a4990..8c55eadfa15 100644 --- a/src/gallium/drivers/v3d/v3d_context.h +++ b/src/gallium/drivers/v3d/v3d_context.h @@ -365,7 +365,7 @@ struct v3d_context { /** Maximum index buffer valid for the current shader_rec. */ uint32_t max_index; - /** Sync object that our RCL will update as its out_sync. */ + /** Sync object that our RCL or TFU job will update as its out_sync. */ uint32_t out_sync; struct u_upload_mgr *uploader; @@ -526,10 +526,19 @@ void v3d_get_internal_type_bpp_for_output_format(const struct v3d_device_info *d uint32_t format, uint32_t *type, uint32_t *bpp); +bool v3d_tfu_supports_tex_format(const struct v3d_device_info *devinfo, + uint32_t tex_format); void v3d_init_query_functions(struct v3d_context *v3d); void v3d_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info); void v3d_blitter_save(struct v3d_context *v3d); +boolean v3d_generate_mipmap(struct pipe_context *pctx, + struct pipe_resource *prsc, + enum pipe_format format, + unsigned int base_level, + unsigned int last_level, + unsigned int first_layer, + unsigned int last_layer); struct v3d_fence *v3d_fence_create(struct v3d_context *v3d); diff --git a/src/gallium/drivers/v3d/v3d_formats.c b/src/gallium/drivers/v3d/v3d_formats.c index bdb86935f65..5bd8db0dbd4 100644 --- a/src/gallium/drivers/v3d/v3d_formats.c +++ b/src/gallium/drivers/v3d/v3d_formats.c @@ -142,3 +142,14 @@ v3d_get_internal_type_bpp_for_output_format(const struct v3d_device_info *devinf type, bpp); } } + +bool +v3d_tfu_supports_tex_format(const struct v3d_device_info *devinfo, + uint32_t tex_format) +{ + if (devinfo->ver >= 41) { + return v3d41_tfu_supports_tex_format(tex_format); + } else { + return v3d33_tfu_supports_tex_format(tex_format); + } +} diff --git a/src/gallium/drivers/v3d/v3d_resource.c b/src/gallium/drivers/v3d/v3d_resource.c index 39529c10c4c..6c69cbe03f7 100644 --- a/src/gallium/drivers/v3d/v3d_resource.c +++ b/src/gallium/drivers/v3d/v3d_resource.c @@ -985,5 +985,6 @@ v3d_resource_context_init(struct pipe_context *pctx) pctx->surface_destroy = v3d_surface_destroy; pctx->resource_copy_region = util_resource_copy_region; pctx->blit = v3d_blit; + pctx->generate_mipmap = v3d_generate_mipmap; pctx->flush_resource = v3d_flush_resource; } diff --git a/src/gallium/drivers/v3d/v3d_screen.c b/src/gallium/drivers/v3d/v3d_screen.c index 7fab90677ea..49ea489d5ef 100644 --- a/src/gallium/drivers/v3d/v3d_screen.c +++ b/src/gallium/drivers/v3d/v3d_screen.c @@ -79,6 +79,20 @@ v3d_screen_destroy(struct pipe_screen *pscreen) ralloc_free(pscreen); } +static bool +v3d_has_feature(struct v3d_screen *screen, enum drm_v3d_param feature) +{ + struct drm_v3d_get_param p = { + .param = feature, + }; + int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_GET_PARAM, &p); + + if (ret != 0) + return false; + + return p.value; +} + static int v3d_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) { @@ -113,6 +127,9 @@ v3d_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR: return 1; + case PIPE_CAP_GENERATE_MIPMAP: + return v3d_has_feature(screen,DRM_V3D_PARAM_SUPPORTS_TFU); + case PIPE_CAP_INDEP_BLEND_ENABLE: return screen->devinfo.ver >= 40; diff --git a/src/gallium/drivers/v3d/v3dx_context.h b/src/gallium/drivers/v3d/v3dx_context.h index ca69294a99f..722b854b819 100644 --- a/src/gallium/drivers/v3d/v3dx_context.h +++ b/src/gallium/drivers/v3d/v3dx_context.h @@ -48,3 +48,4 @@ const struct v3d_format *v3dX(get_format_desc)(enum pipe_format f); void v3dX(get_internal_type_bpp_for_output_format)(uint32_t format, uint32_t *type, uint32_t *bpp); +bool v3dX(tfu_supports_tex_format)(uint32_t tex_format); diff --git a/src/gallium/drivers/v3d/v3dx_format_table.c b/src/gallium/drivers/v3d/v3dx_format_table.c index 100fd3b0da4..6f9af3cea4f 100644 --- a/src/gallium/drivers/v3d/v3dx_format_table.c +++ b/src/gallium/drivers/v3d/v3dx_format_table.c @@ -318,3 +318,34 @@ v3dX(get_internal_type_bpp_for_output_format)(uint32_t format, break; } } + +bool +v3dX(tfu_supports_tex_format)(enum V3DX(Texture_Data_Formats) format) +{ + switch (format) { + case TEXTURE_DATA_FORMAT_R8: + case TEXTURE_DATA_FORMAT_R8_SNORM: + case TEXTURE_DATA_FORMAT_RG8: + case TEXTURE_DATA_FORMAT_RG8_SNORM: + case TEXTURE_DATA_FORMAT_RGBA8: + case TEXTURE_DATA_FORMAT_RGBA8_SNORM: + case TEXTURE_DATA_FORMAT_RGB565: + case TEXTURE_DATA_FORMAT_RGBA4: + case TEXTURE_DATA_FORMAT_RGB5_A1: + case TEXTURE_DATA_FORMAT_RGB10_A2: + case TEXTURE_DATA_FORMAT_R16: + case TEXTURE_DATA_FORMAT_R16_SNORM: + case TEXTURE_DATA_FORMAT_RG16: + case TEXTURE_DATA_FORMAT_RG16_SNORM: + case TEXTURE_DATA_FORMAT_RGBA16: + case TEXTURE_DATA_FORMAT_RGBA16_SNORM: + case TEXTURE_DATA_FORMAT_R16F: + case TEXTURE_DATA_FORMAT_RG16F: + case TEXTURE_DATA_FORMAT_RGBA16F: + case TEXTURE_DATA_FORMAT_R11F_G11F_B10F: + case TEXTURE_DATA_FORMAT_R4: + return true; + default: + return false; + } +} -- 2.30.2