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.
This commit is contained in:
Eric Anholt 2018-11-28 17:22:45 -08:00
parent 976ea90bdc
commit 6ad9e8690d
6 changed files with 110 additions and 3 deletions

View file

@ -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 {

View file

@ -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,

View file

@ -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);

View file

@ -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));

View file

@ -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);
}

View file

@ -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);
}