panfrost: Reload framebuffer contents if there's no clear
authorTomeu Vizoso <tomeu.vizoso@collabora.com>
Tue, 14 May 2019 15:28:17 +0000 (17:28 +0200)
committerAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Wed, 5 Jun 2019 21:35:48 +0000 (14:35 -0700)
If by flush time the client hasn't submitted a clear, add jobs for
reloading the framebuffer contents as the first draw in the frame.

This is required by programs such as Weston which don't do clears and
rely on the previous contents of the framebuffer being there.

Reloading the whole framebuffer on every frame without regards to what
is needed or what is going to be covered is very inefficient, but future
work will introduce support for damage regions and partial updates so we
know what needs to be actually reloaded.

Fixes quite a few tests in dEQP-EGL.functional.buffer_age.*.

[Alyssa: The context is that tilers do an implicit glClear() on every
frame, whether you asked them to or not. If you want a clear, this is
very efficient. But if you don't, you have to explicitly blit the
backbuffer back into tile memory, accomplished by a dummy texturing
draw. This patch generates that draw via u_blitter, although we could do
a bit better ourselves by eliding the vertex job. This fixes "black
rectangles in Weston/sway" as well as "video not displaying when UI
visible in mpv"]

Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
src/gallium/drivers/panfrost/meson.build
src/gallium/drivers/panfrost/pan_context.c
src/gallium/drivers/panfrost/pan_wallpaper.c [deleted file]
src/gallium/drivers/panfrost/pan_wallpaper.h [deleted file]

index b65f027f2c4e0f0edcb08a84011b1b6c8038865f..cf4b0c2d2411f27560f32d4cf2c7bc297e0b3992 100644 (file)
@@ -52,7 +52,6 @@ files_panfrost = files(
   'pan_swizzle.c',
   'pan_blending.c',
   'pan_blend_shaders.c',
-  'pan_wallpaper.c',
   'pan_pretty_print.c',
   'pan_fragment.c',
   'pan_sfbd.c',
index 337faaca0f73caebf350a7f8fa8ec2b2f561e508..b15cf5f38a49ff0304bfd8b989de1a21d7c48cc4 100644 (file)
@@ -46,7 +46,6 @@
 #include "pan_blending.h"
 #include "pan_blend_shaders.h"
 #include "pan_util.h"
-#include "pan_wallpaper.h"
 
 static int performance_counter_number = 0;
 extern const char *pan_counters_base;
@@ -1373,6 +1372,87 @@ panfrost_submit_frame(struct panfrost_context *ctx, bool flush_immediate,
 #endif
 }
 
+static void
+panfrost_draw_wallpaper(struct pipe_context *pipe)
+{
+       struct panfrost_context *ctx = pan_context(pipe);
+       struct pipe_blit_info binfo = { };
+
+       /* Nothing to reload? */
+       if (ctx->pipe_framebuffer.cbufs[0] == NULL)
+               return;
+
+        util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffers);
+        util_blitter_save_vertex_elements(ctx->blitter, ctx->vertex);
+        util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
+        util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer);
+        util_blitter_save_viewport(ctx->blitter, &ctx->pipe_viewport);
+        util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
+        util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
+        util_blitter_save_blend(ctx->blitter, ctx->blend);
+        util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->depth_stencil);
+        util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
+       util_blitter_save_so_targets(ctx->blitter, 0, NULL);
+
+       /* For later */
+//        util_blitter_save_sample_mask(ctx->blitter, vc4->sample_mask);
+
+        util_blitter_save_framebuffer(ctx->blitter, &ctx->pipe_framebuffer);
+        util_blitter_save_fragment_sampler_states(ctx->blitter,
+                                                 ctx->sampler_count[PIPE_SHADER_FRAGMENT],
+                                                 (void **)(&ctx->samplers[PIPE_SHADER_FRAGMENT]));
+        util_blitter_save_fragment_sampler_views(ctx->blitter,
+                                                ctx->sampler_view_count[PIPE_SHADER_FRAGMENT],
+                                                (struct pipe_sampler_view **)&ctx->sampler_views[PIPE_SHADER_FRAGMENT]);
+
+
+       binfo.src.resource = binfo.dst.resource = ctx->pipe_framebuffer.cbufs[0]->texture;
+       binfo.src.level = binfo.dst.level = 0;
+       binfo.src.box.x = binfo.dst.box.x = 0;
+       binfo.src.box.y = binfo.dst.box.y = 0;
+       binfo.src.box.width = binfo.dst.box.width = ctx->pipe_framebuffer.width;
+       binfo.src.box.height = binfo.dst.box.height = ctx->pipe_framebuffer.height;
+
+       /* This avoids an assert due to missing nir_texop_txb support */
+       //binfo.src.box.depth = binfo.dst.box.depth = 1;
+
+       binfo.src.format = binfo.dst.format = ctx->pipe_framebuffer.cbufs[0]->texture->format;
+
+       assert(ctx->pipe_framebuffer.nr_cbufs == 1);
+       binfo.mask = PIPE_MASK_RGBA;
+       binfo.filter = PIPE_TEX_FILTER_LINEAR;
+       binfo.scissor_enable = FALSE;
+
+       util_blitter_blit(ctx->blitter, &binfo);
+
+        /* We are flushing all queued draws and we know that no more jobs will
+         * be added until the next frame.
+         * We also know that the last jobs are the wallpaper jobs, and they
+         * need to be linked so they execute right after the set_value job.
+         */
+
+        /* set_value job to wallpaper vertex job */
+        panfrost_link_job_pair(ctx->u_set_value_job, ctx->vertex_jobs[ctx->vertex_job_count - 1]);
+        ctx->u_vertex_jobs[ctx->vertex_job_count - 1]->job_dependency_index_1 = ctx->u_set_value_job->job_index;
+
+        /* wallpaper vertex job to first vertex job */
+        panfrost_link_job_pair(ctx->u_vertex_jobs[ctx->vertex_job_count - 1], ctx->vertex_jobs[0]);
+        ctx->u_vertex_jobs[0]->job_dependency_index_1 = ctx->u_set_value_job->job_index;
+
+        /* last vertex job to wallpaper tiler job */
+        panfrost_link_job_pair(ctx->u_vertex_jobs[ctx->vertex_job_count - 2], ctx->tiler_jobs[ctx->tiler_job_count - 1]);
+        ctx->u_tiler_jobs[ctx->tiler_job_count - 1]->job_dependency_index_1 = ctx->u_vertex_jobs[ctx->vertex_job_count - 1]->job_index;
+        ctx->u_tiler_jobs[ctx->tiler_job_count - 1]->job_dependency_index_2 = 0;
+
+        /* wallpaper tiler job to first tiler job */
+        panfrost_link_job_pair(ctx->u_tiler_jobs[ctx->tiler_job_count - 1], ctx->tiler_jobs[0]);
+        ctx->u_tiler_jobs[0]->job_dependency_index_1 = ctx->u_vertex_jobs[0]->job_index;
+        ctx->u_tiler_jobs[0]->job_dependency_index_2 = ctx->u_tiler_jobs[ctx->tiler_job_count - 1]->job_index;
+
+        /* last tiler job to NULL */
+        panfrost_link_job_pair(ctx->u_tiler_jobs[ctx->tiler_job_count - 2], 0);
+}
+
 void
 panfrost_flush(
         struct pipe_context *pipe,
@@ -1385,6 +1465,9 @@ panfrost_flush(
         /* Nothing to do! */
         if (!ctx->draw_count && !job->clear) return;
 
+       if (!job->clear)
+               panfrost_draw_wallpaper(&ctx->base);
+
         /* Whether to stall the pipeline for immediately correct results */
         bool flush_immediate = flags & PIPE_FLUSH_END_OF_FRAME;
 
@@ -2050,9 +2133,11 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx,
 {
         struct panfrost_context *ctx = pan_context(pctx);
 
-        /* Flush when switching away from an FBO */
+        /* Flush when switching away from an FBO, but not if the framebuffer
+         * state is being restored by u_blitter
+         */
 
-        if (!panfrost_is_scanout(ctx)) {
+        if (!panfrost_is_scanout(ctx) && !ctx->blitter->running) {
                 panfrost_flush(pctx, NULL, 0);
         }
 
diff --git a/src/gallium/drivers/panfrost/pan_wallpaper.c b/src/gallium/drivers/panfrost/pan_wallpaper.c
deleted file mode 100644 (file)
index ac77ad0..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * © Copyright 2018 Alyssa Rosenzweig
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include "pan_wallpaper.h"
-#include "pan_context.h"
-#include "pan_screen.h"
-#include "pan_util.h"
-//#include "include/panfrost-job.h"
-#include "midgard/midgard_compile.h"
-#include "compiler/nir/nir_builder.h"
-
-/* Creates the special-purpose fragment shader for wallpapering. A
- * pseudo-vertex shader sets us up for a fullscreen quad render, with a texture
- * coordinate varying */
-
-static nir_shader *
-panfrost_build_wallpaper_program()
-{
-        nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
-        nir_function *fn = nir_function_create(shader, "main");
-        nir_function_impl *impl = nir_function_impl_create(fn);
-
-        /* Create the variables variables */
-
-        nir_variable *c_texcoord = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_TexCoord");
-        nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_FragColor");
-
-        c_texcoord->data.location = VARYING_SLOT_VAR0;
-        c_out->data.location = FRAG_RESULT_COLOR;
-
-        /* Setup nir_builder */
-
-        nir_builder _b;
-        nir_builder *b = &_b;
-        nir_builder_init(b, impl);
-        b->cursor = nir_before_block(nir_start_block(impl));
-
-        /* Setup inputs */
-
-        nir_ssa_def *s_src = nir_load_var(b, c_texcoord);
-
-        /* Build the passthrough texture shader */
-
-        nir_tex_instr *tx = nir_tex_instr_create(shader, 1);
-        tx->op = nir_texop_tex;
-        tx->texture_index = tx->sampler_index = 0;
-        tx->sampler_dim = GLSL_SAMPLER_DIM_2D;
-        tx->dest_type = nir_type_float;
-
-        nir_src src = nir_src_for_ssa(s_src);
-        nir_src_copy(&tx->src[0].src, &src, tx);
-        tx->src[0].src_type = nir_tex_src_coord;
-
-        nir_ssa_dest_init(&tx->instr, &tx->dest, nir_tex_instr_dest_size(tx), 32, NULL);
-        nir_builder_instr_insert(b, &tx->instr);
-
-        nir_ssa_def *texel = &tx->dest.ssa;
-
-        nir_store_var(b, c_out, texel, 0xFF);
-
-        return shader;
-}
-
-/* Creates the CSO corresponding to the wallpaper program */
-
-static struct panfrost_shader_variants *
-panfrost_create_wallpaper_program(struct pipe_context *pctx) 
-{
-        nir_shader *built_nir_shader = panfrost_build_wallpaper_program();
-
-        struct pipe_shader_state so = {
-                .type = PIPE_SHADER_IR_NIR,
-                .ir = {
-                        .nir = built_nir_shader
-                }
-        };
-
-        return pctx->create_fs_state(pctx, &so);
-}
-
-static struct panfrost_shader_variants *wallpaper_program = NULL;
-static struct panfrost_shader_variants *wallpaper_saved_program = NULL;
-
-static void
-panfrost_enable_wallpaper_program(struct pipe_context *pctx)
-{
-        struct panfrost_context *ctx = pan_context(pctx);
-
-        if (!wallpaper_program) {
-                wallpaper_program = panfrost_create_wallpaper_program(pctx);
-        }
-
-        /* Push the shader state */
-        wallpaper_saved_program = ctx->fs;
-
-        /* Bind the program */
-        pctx->bind_fs_state(pctx, wallpaper_program);
-}
-
-static void
-panfrost_disable_wallpaper_program(struct pipe_context *pctx)
-{
-        /* Pop off the shader state */
-        pctx->bind_fs_state(pctx, wallpaper_saved_program);
-}
-
-/* Essentially, we insert a fullscreen textured quad, reading from the
- * previous frame's framebuffer */
-
-void
-panfrost_draw_wallpaper(struct pipe_context *pipe)
-{
-        /* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */
-
-        panfrost_enable_wallpaper_program(pipe);
-        panfrost_disable_wallpaper_program(pipe);
-
-        return;
-
-#if 0
-        struct panfrost_context *ctx = pan_context(pipe);
-
-        /* Setup payload for elided quad. TODO: Refactor draw_vbo so this can
-         * be a little more DRY */
-
-        ctx->payload_tiler.draw_start = 0;
-        ctx->payload_tiler.prefix.draw_mode = MALI_TRIANGLE_STRIP;
-        ctx->vertex_count = 4;
-        ctx->payload_tiler.prefix.invocation_count = MALI_POSITIVE(4);
-        ctx->payload_tiler.prefix.unknown_draw &= ~(0x3000 | 0x18000);
-        ctx->payload_tiler.prefix.unknown_draw |= 0x18000;
-        ctx->payload_tiler.prefix.negative_start = 0;
-        ctx->payload_tiler.prefix.index_count = MALI_POSITIVE(4);
-        ctx->payload_tiler.prefix.unknown_draw &= ~MALI_DRAW_INDEXED_UINT32;
-        ctx->payload_tiler.prefix.indices = (uintptr_t) NULL;
-
-        /* Setup the wallpapering program. We need to build the program via
-         * NIR. */
-
-        panfrost_enable_wallpaper_program(pipe);
-
-        /* Setup the texture/sampler pair */
-
-        struct pipe_sampler_view tmpl = {
-                .target = PIPE_TEXTURE_2D,
-                .swizzle_r = PIPE_SWIZZLE_X,
-                .swizzle_g = PIPE_SWIZZLE_Y,
-                .swizzle_b = PIPE_SWIZZLE_Z,
-                .swizzle_a = PIPE_SWIZZLE_W
-        };
-
-        struct pipe_sampler_state state = {
-                .min_mip_filter = PIPE_TEX_MIPFILTER_NONE,
-                .min_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
-                .mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
-                .wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
-                .wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
-                .wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
-                .normalized_coords = 1
-        };
-
-        struct pipe_resource *rsrc = pan_screen(pipe->screen)->display_target;
-        struct pipe_sampler_state *sampler_state = pipe->create_sampler_state(pipe, &state);
-        struct pipe_sampler_view *sampler_view = pipe->create_sampler_view(pipe, rsrc, &tmpl);
-
-        /* Bind texture/sampler. TODO: push/pop */
-        pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);
-        pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_view);
-
-        panfrost_emit_for_draw(ctx, false);
-
-        /* Elision occurs by essential precomputing the results of the
-         * implied vertex shader. Insert these results for fullscreen. The
-         * first two channels are ~screenspace coordinates, whereas the latter
-         * two are fixed 0.0/1.0 after perspective division. See the vertex
-         * shader epilogue for more context */
-
-        float implied_position_varying[] = {
-                /* The following is correct for scissored clears whose scissor deals with cutoff appropriately */
-
-//                -1.0, -1.0,        0.0, 1.0,
-//                -1.0, 65535.0,     0.0, 1.0,
-//                65536.0, 1.0,      0.0, 1.0,
-//                65536.0, 65536.0,  0.0, 1.0
-
-                /* The following output is correct for a fullscreen quad with screen size 2048x1600 */
-                0.0, 0.0, 0.0, 1.0,
-                0.0, 1600.0, 0.0, 1.0,
-                2048.0, 0.0, 0.0, 1.0,
-                2048.0, 1280.0, 0.0, 1.0,
-        };
-
-        ctx->payload_tiler.postfix.position_varying = panfrost_upload_transient(ctx, implied_position_varying, sizeof(implied_position_varying));
-
-        /* Similarly, setup the texture coordinate varying, hardcoded to match
-         * the corners of the screen */
-
-        float texture_coordinates[] = {
-                0.0, 0.0, 0.0, 0.0,
-                0.0, 1.0, 0.0, 0.0,
-                1.0, 0.0, 0.0, 0.0,
-                1.0, 1.0, 0.0, 0.0
-        };
-
-        union mali_attr varyings[1] = {
-                {
-                        .elements = panfrost_upload_transient(ctx, texture_coordinates, sizeof(texture_coordinates)) | 1,
-                        .stride = sizeof(float) * 4,
-                        .size = sizeof(texture_coordinates)
-                }
-        };
-
-        ctx->payload_tiler.postfix.varyings = panfrost_upload_transient(ctx, varyings, sizeof(varyings));
-
-        struct mali_attr_meta varying_meta[1] = {
-                {
-                        .type = MALI_ATYPE_FLOAT,
-                        .nr_components = MALI_POSITIVE(4),
-                        .not_normalised = 1,
-                        .unknown1 = /*0x2c22 - nr_comp=2*/ 0x2a22,
-                        .unknown2 = 0x1
-                }
-        };
-
-        mali_ptr saved_varying_meta = ctx->payload_tiler.postfix.varying_meta;
-        ctx->payload_tiler.postfix.varying_meta = panfrost_upload_transient(ctx, varying_meta, sizeof(varying_meta));
-
-        /* Emit the tiler job */
-        struct panfrost_transfer tiler = panfrost_vertex_tiler_job(ctx, true, true);
-        struct mali_job_descriptor_header *jd = (struct mali_job_descriptor_header *) tiler.cpu;
-        ctx->u_tiler_jobs[ctx->tiler_job_count] = jd;
-        ctx->tiler_jobs[ctx->tiler_job_count++] = tiler.gpu;
-        ctx->draw_count++;
-
-        /* Okay, so we have the tiler job emitted. Since we set elided_tiler
-         * mode, no dependencies will be set automatically. We don't actually
-         * want any dependencies, since we go first and we don't need a vertex
-         * first. That said, we do need the first tiler job to depend on us.
-         * Its second dep slot will be free (see the panfrost_vertex_tiler_job
-         * dependency setting algorithm), so fill us in with that
-         */
-
-        if (ctx->tiler_job_count > 1) {
-                ctx->u_tiler_jobs[0]->job_dependency_index_2 = jd->job_index;
-        }
-
-        printf("Wallpaper boop\n");
-        
-        /* Cleanup */
-        panfrost_disable_wallpaper_program(pipe);
-        ctx->payload_tiler.postfix.varying_meta = saved_varying_meta;
-#endif
-}
diff --git a/src/gallium/drivers/panfrost/pan_wallpaper.h b/src/gallium/drivers/panfrost/pan_wallpaper.h
deleted file mode 100644 (file)
index 301e45e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * © Copyright 2018 Alyssa Rosenzweig
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef __PAN_WALLPAPER_H
-#define __PAN_WALLPAPER_H
-
-#include "pipe/p_state.h"
-
-void
-panfrost_draw_wallpaper(struct pipe_context *pipe);
-
-#endif