From 6ad9e8690d144f110150d3367254504c1b322682 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 28 Nov 2018 17:22:45 -0800 Subject: [PATCH] v3d: Add support for texturing from linear. Just like vc4, we have to support linear shared BOs for X11 on arbitrary displays. When we're faced with a request to texture from one of those, make a shadow image that we copy using the TFU at the start of the draw call. --- src/gallium/drivers/v3d/v3d_context.h | 6 +++ src/gallium/drivers/v3d/v3d_resource.c | 55 ++++++++++++++++++++++++++ src/gallium/drivers/v3d/v3d_resource.h | 2 + src/gallium/drivers/v3d/v3d_uniforms.c | 2 +- src/gallium/drivers/v3d/v3dx_draw.c | 8 +++- src/gallium/drivers/v3d/v3dx_state.c | 40 +++++++++++++++++++ 6 files changed, 110 insertions(+), 3 deletions(-) diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h index a2fcf1ae2d4..575b74f4940 100644 --- a/src/gallium/drivers/v3d/v3d_context.h +++ b/src/gallium/drivers/v3d/v3d_context.h @@ -95,6 +95,12 @@ struct v3d_sampler_view { uint8_t texture_shader_state[32]; /* V3D 4.x: Texture state struct. */ struct v3d_bo *bo; + + /* Actual texture to be read by this sampler view. May be different + * from base.texture in the case of having a shadow tiled copy of a + * raster texture. + */ + struct pipe_resource *texture; }; struct v3d_sampler_state { diff --git a/src/gallium/drivers/v3d/v3d_resource.c b/src/gallium/drivers/v3d/v3d_resource.c index 6c69cbe03f7..33b44868bbd 100644 --- a/src/gallium/drivers/v3d/v3d_resource.c +++ b/src/gallium/drivers/v3d/v3d_resource.c @@ -828,6 +828,61 @@ fail: return NULL; } +void +v3d_update_shadow_texture(struct pipe_context *pctx, + struct pipe_sampler_view *pview) +{ + struct v3d_sampler_view *view = v3d_sampler_view(pview); + struct v3d_resource *shadow = v3d_resource(view->texture); + struct v3d_resource *orig = v3d_resource(pview->texture); + + assert(view->texture != pview->texture); + + if (shadow->writes == orig->writes && orig->bo->private) + return; + + perf_debug("Updating %dx%d@%d shadow for linear texture\n", + orig->base.width0, orig->base.height0, + pview->u.tex.first_level); + + for (int i = 0; i <= shadow->base.last_level; i++) { + unsigned width = u_minify(shadow->base.width0, i); + unsigned height = u_minify(shadow->base.height0, i); + struct pipe_blit_info info = { + .dst = { + .resource = &shadow->base, + .level = i, + .box = { + .x = 0, + .y = 0, + .z = 0, + .width = width, + .height = height, + .depth = 1, + }, + .format = shadow->base.format, + }, + .src = { + .resource = &orig->base, + .level = pview->u.tex.first_level + i, + .box = { + .x = 0, + .y = 0, + .z = 0, + .width = width, + .height = height, + .depth = 1, + }, + .format = orig->base.format, + }, + .mask = util_format_get_mask(orig->base.format), + }; + pctx->blit(pctx, &info); + } + + shadow->writes = orig->writes; +} + static struct pipe_surface * v3d_create_surface(struct pipe_context *pctx, struct pipe_resource *ptex, diff --git a/src/gallium/drivers/v3d/v3d_resource.h b/src/gallium/drivers/v3d/v3d_resource.h index 80b1d6eb9ad..2aa28627338 100644 --- a/src/gallium/drivers/v3d/v3d_resource.h +++ b/src/gallium/drivers/v3d/v3d_resource.h @@ -176,6 +176,8 @@ void v3d_resource_screen_init(struct pipe_screen *pscreen); void v3d_resource_context_init(struct pipe_context *pctx); struct pipe_resource *v3d_resource_create(struct pipe_screen *pscreen, const struct pipe_resource *tmpl); +void v3d_update_shadow_texture(struct pipe_context *pctx, + struct pipe_sampler_view *view); uint32_t v3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer); diff --git a/src/gallium/drivers/v3d/v3d_uniforms.c b/src/gallium/drivers/v3d/v3d_uniforms.c index 49e83ccdb1d..c924c2f2e04 100644 --- a/src/gallium/drivers/v3d/v3d_uniforms.c +++ b/src/gallium/drivers/v3d/v3d_uniforms.c @@ -151,7 +151,7 @@ write_tmu_p0(struct v3d_job *job, int unit = v3d_tmu_config_data_get_unit(data); struct pipe_sampler_view *psview = texstate->textures[unit]; struct v3d_sampler_view *sview = v3d_sampler_view(psview); - struct v3d_resource *rsc = v3d_resource(psview->texture); + struct v3d_resource *rsc = v3d_resource(sview->texture); cl_aligned_reloc(&job->indirect, uniforms, sview->bo, v3d_tmu_config_data_get_value(data)); diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c index ca0a1ab39c2..d48970e1e2b 100644 --- a/src/gallium/drivers/v3d/v3dx_draw.c +++ b/src/gallium/drivers/v3d/v3dx_draw.c @@ -126,9 +126,13 @@ v3d_predraw_check_stage_inputs(struct pipe_context *pctx, /* Flush writes to textures we're sampling. */ for (int i = 0; i < v3d->tex[s].num_textures; i++) { - struct pipe_sampler_view *view = v3d->tex[s].textures[i]; - if (!view) + struct pipe_sampler_view *pview = v3d->tex[s].textures[i]; + if (!pview) continue; + struct v3d_sampler_view *view = v3d_sampler_view(pview); + + if (view->texture != view->base.texture) + v3d_update_shadow_texture(pctx, &view->base); v3d_flush_jobs_writing_resource(v3d, view->texture); } diff --git a/src/gallium/drivers/v3d/v3dx_state.c b/src/gallium/drivers/v3d/v3dx_state.c index 2980547f1d6..ee1ba7b2d10 100644 --- a/src/gallium/drivers/v3d/v3dx_state.c +++ b/src/gallium/drivers/v3d/v3dx_state.c @@ -746,6 +746,7 @@ v3d_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc, struct v3d_context *v3d = v3d_context(pctx); struct v3d_screen *screen = v3d->screen; struct v3d_sampler_view *so = CALLOC_STRUCT(v3d_sampler_view); + struct v3d_resource *rsc = v3d_resource(prsc); if (!so) return NULL; @@ -772,6 +773,44 @@ v3d_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc, so->base.reference.count = 1; so->base.context = pctx; + /* V3D still doesn't support sampling from raster textures, so we will + * have to copy to a temporary tiled texture. + */ + if (!rsc->tiled) { + struct v3d_resource *shadow_parent = rsc; + struct pipe_resource tmpl = { + .target = prsc->target, + .format = prsc->format, + .width0 = u_minify(prsc->width0, + cso->u.tex.first_level), + .height0 = u_minify(prsc->height0, + cso->u.tex.first_level), + .depth0 = 1, + .array_size = 1, + .bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET, + .last_level = cso->u.tex.last_level - cso->u.tex.first_level, + .nr_samples = prsc->nr_samples, + }; + + /* Create the shadow texture. The rest of the sampler view + * setup will use the shadow. + */ + prsc = v3d_resource_create(pctx->screen, &tmpl); + if (!prsc) { + free(so); + return NULL; + } + rsc = v3d_resource(prsc); + + /* Flag it as needing update of the contents from the parent. */ + rsc->writes = shadow_parent->writes - 1; + assert(rsc->tiled); + + so->texture = prsc; + } else { + pipe_resource_reference(&so->texture, prsc); + } + void *map; #if V3D_VERSION >= 40 so->bo = v3d_bo_alloc(v3d->screen, @@ -859,6 +898,7 @@ v3d_sampler_view_destroy(struct pipe_context *pctx, v3d_bo_unreference(&sview->bo); pipe_resource_reference(&psview->texture, NULL); + pipe_resource_reference(&sview->texture, NULL); free(psview); } -- 2.30.2