v3d: Add support for texturing from linear.
authorEric Anholt <eric@anholt.net>
Thu, 29 Nov 2018 01:22:45 +0000 (17:22 -0800)
committerEric Anholt <eric@anholt.net>
Sat, 15 Dec 2018 01:48:01 +0000 (17:48 -0800)
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
src/gallium/drivers/v3d/v3d_resource.c
src/gallium/drivers/v3d/v3d_resource.h
src/gallium/drivers/v3d/v3d_uniforms.c
src/gallium/drivers/v3d/v3dx_draw.c
src/gallium/drivers/v3d/v3dx_state.c

index a2fcf1ae2d4dcc1fc6de7e35484d3c009136ae55..575b74f494016cc95c766ad28fad32e1af01c087 100644 (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 {
index 6c69cbe03f7451ba49196d3e9b0f20f603b84605..33b44868bbd551a9d0737664e711b6895bae89ac 100644 (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,
index 80b1d6eb9adac9f8534eb38b85aa66a7dc2ccf8d..2aa28627338644f15ff40f339bd96d19b58ce01a 100644 (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);
 
index 49e83ccdb1d5fdd509c4aba8cb7cbd6c05be7dc8..c924c2f2e0483fe4e21ecf80c766ef849ace1236 100644 (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));
index ca0a1ab39c2f8f28298fe0c2f9d979565079c85d..d48970e1e2b072fc4b75dd165ff69f60c5e10aa2 100644 (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);
         }
index 2980547f1d64755ecf5cc3aff322d43c855e473f..ee1ba7b2d1009931053db351b3ccc5a3cdbcf929 100644 (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);
 }