[Mesa-dev] [PATCH 1/2] panfrost: Track BO lifetime with jobs and reference counts

Erik Faye-Lund erik.faye-lund at collabora.com
Tue Apr 16 08:22:48 UTC 2019


On Tue, 2019-04-16 at 01:49 +0000, Alyssa Rosenzweig wrote:
> This (fairly large) patch continues work surrounding the panfrost_job
> abstraction to improve job lifetime management. In particular, we add
> infrastructure to track which BOs are used by a particular job
> (currently limited to the vertex buffer BOs), to reference count
> these
> BOs, and to automatically manage the BOs memory based on the
> reference
> count. This set of changes serves as a code cleanup, as a way of
> future
> proofing for allowing flushing BOs, and immediately as a bugfix to
> workaround the missing reference counting for vertex buffer BOs.
> Meanwhile, there are a few cleanups to vertex buffer handling code
> itself, so in the short-term, this allows us to remove the costly VBO
> staging workaround, since this patch addresses the underlying causes.
> 
> Signed-off-by: Alyssa Rosenzweig <alyssa at rosenzweig.io>
> ---
>  src/gallium/drivers/panfrost/pan_context.c  | 37 ++++------
>  src/gallium/drivers/panfrost/pan_context.h  |  6 +-
>  src/gallium/drivers/panfrost/pan_drm.c      |  6 ++
>  src/gallium/drivers/panfrost/pan_job.c      | 82
> +++++++++++++++++++++
>  src/gallium/drivers/panfrost/pan_job.h      | 16 ++++
>  src/gallium/drivers/panfrost/pan_resource.c | 70 +++++++++++++++++-
>  src/gallium/drivers/panfrost/pan_resource.h | 13 ++++
>  src/gallium/drivers/panfrost/pan_screen.c   |  2 +-
>  src/gallium/drivers/panfrost/pan_screen.h   |  5 +-
>  9 files changed, 208 insertions(+), 29 deletions(-)
> 
> diff --git a/src/gallium/drivers/panfrost/pan_context.c
> b/src/gallium/drivers/panfrost/pan_context.c
> index 0c97c0a2b43..75a975871db 100644
> --- a/src/gallium/drivers/panfrost/pan_context.c
> +++ b/src/gallium/drivers/panfrost/pan_context.c
> @@ -36,6 +36,8 @@
>  #include "util/u_memory.h"
>  #include "util/u_vbuf.h"
>  #include "util/half_float.h"
> +#include "util/u_helpers.h"
> +#include "util/u_format.h"
>  #include "indices/u_primconvert.h"
>  #include "tgsi/tgsi_parse.h"
>  
> @@ -737,7 +739,7 @@ panfrost_emit_varying_descriptor(
>   * excepting some obscure circumstances */
>  
>  static void
> -panfrost_emit_vertex_data(struct panfrost_context *ctx)
> +panfrost_emit_vertex_data(struct panfrost_context *ctx, struct
> panfrost_job *job)
>  {
>          /* TODO: Only update the dirtied buffers */
>          union mali_attr attrs[PIPE_MAX_ATTRIBS];
> @@ -745,6 +747,8 @@ panfrost_emit_vertex_data(struct panfrost_context
> *ctx)
>          unsigned invocation_count = MALI_NEGATIVE(ctx-
> >payload_tiler.prefix.invocation_count);
>  
>          for (int i = 0; i < ctx->vertex_buffer_count; ++i) {
> +                if (!(ctx->vb_mask & (1 << i))) continue;
> +
>                  struct pipe_vertex_buffer *buf = &ctx-
> >vertex_buffers[i];
>                  struct panfrost_resource *rsrc = (struct
> panfrost_resource *) (buf->buffer.resource);
>  
> @@ -776,9 +780,10 @@ panfrost_emit_vertex_data(struct
> panfrost_context *ctx)
>  
>                  mali_ptr effective_address = rsrc ? (rsrc->bo->gpu +
> buf->buffer_offset) : 0;
>  
> -                if (effective_address) {
> +                if (effective_address & 63) {
>                          attrs[i].elements =
> panfrost_upload_transient(ctx, rsrc->bo->cpu + buf->buffer_offset,
> attrs[i].size) | MALI_ATTR_LINEAR;
>                  } else if (effective_address) {
> +                        panfrost_job_add_bo(job, rsrc->bo);
>                          attrs[i].elements = effective_address |
> MALI_ATTR_LINEAR;
>                  } else {
>                          /* Leave unset? */
> @@ -807,7 +812,7 @@ panfrost_emit_for_draw(struct panfrost_context
> *ctx, bool with_vertex_data)
>          struct panfrost_job *job = panfrost_get_job_for_fbo(ctx);
>  
>          if (with_vertex_data) {
> -                panfrost_emit_vertex_data(ctx);
> +                panfrost_emit_vertex_data(ctx, job);
>          }
>  
>          bool msaa = ctx->rasterizer->base.multisample;
> @@ -1252,7 +1257,8 @@ panfrost_link_jobs(struct panfrost_context
> *ctx)
>  
>  static void
>  panfrost_submit_frame(struct panfrost_context *ctx, bool
> flush_immediate,
> -		      struct pipe_fence_handle **fence)
> +		      struct pipe_fence_handle **fence,
> +                      struct panfrost_job *job)
>  {
>          struct pipe_context *gallium = (struct pipe_context *) ctx;
>          struct panfrost_screen *screen = pan_screen(gallium-
> >screen);
> @@ -1274,15 +1280,15 @@ panfrost_submit_frame(struct panfrost_context
> *ctx, bool flush_immediate,
>  #ifndef DRY_RUN
>          
>          bool is_scanout = panfrost_is_scanout(ctx);
> -        int fragment_id = screen->driver->submit_vs_fs_job(ctx,
> has_draws, is_scanout);
> +        screen->driver->submit_vs_fs_job(ctx, has_draws,
> is_scanout);
>  
>          /* If visual, we can stall a frame */
>  
>          if (!flush_immediate)
>                  screen->driver->force_flush_fragment(ctx, fence);
>  
> -        screen->last_fragment_id = fragment_id;
>          screen->last_fragment_flushed = false;
> +        screen->last_job = job;
>  
>          /* If readback, flush now (hurts the pipelined performance)
> */
>          if (flush_immediate)
> @@ -1317,7 +1323,7 @@ panfrost_flush(
>          bool flush_immediate = flags & PIPE_FLUSH_END_OF_FRAME;
>  
>          /* Submit the frame itself */
> -        panfrost_submit_frame(ctx, flush_immediate, fence);
> +        panfrost_submit_frame(ctx, flush_immediate, fence, job);
>  
>          /* Prepare for the next frame */
>          panfrost_invalidate_frame(ctx);
> @@ -1793,22 +1799,9 @@ panfrost_set_vertex_buffers(
>          const struct pipe_vertex_buffer *buffers)
>  {
>          struct panfrost_context *ctx = pan_context(pctx);
> -        assert(num_buffers <= PIPE_MAX_ATTRIBS);
> -
> -        /* XXX: Dirty tracking? etc */
> -        if (buffers) {
> -                size_t sz = sizeof(buffers[0]) * num_buffers;
> -                ctx->vertex_buffers = malloc(sz);
> -                ctx->vertex_buffer_count = num_buffers;
> -                memcpy(ctx->vertex_buffers, buffers, sz);
> -        } else {
> -                if (ctx->vertex_buffers) {
> -                        free(ctx->vertex_buffers);
> -                        ctx->vertex_buffers = NULL;
> -                }
>  
> -                ctx->vertex_buffer_count = 0;
> -        }
> +        util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx-
> >vb_mask, buffers, start_slot, num_buffers);
> +        ctx->vertex_buffer_count = num_buffers;
>  }
>  
>  static void
> diff --git a/src/gallium/drivers/panfrost/pan_context.h
> b/src/gallium/drivers/panfrost/pan_context.h
> index d071da1c62f..e45f98c9b77 100644
> --- a/src/gallium/drivers/panfrost/pan_context.h
> +++ b/src/gallium/drivers/panfrost/pan_context.h
> @@ -114,6 +114,9 @@ struct panfrost_context {
>          struct panfrost_job *job;
>          struct hash_table *jobs;
>  
> +        /* panfrost_resource -> panfrost_job */
> +        struct hash_table *write_jobs;
> +
>          /* Bit mask for supported PIPE_DRAW for this hardware */
>          unsigned draw_modes;
>  
> @@ -187,8 +190,9 @@ struct panfrost_context {
>  
>          struct panfrost_vertex_state *vertex;
>  
> -        struct pipe_vertex_buffer *vertex_buffers;
> +        struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
>          unsigned vertex_buffer_count;
> +        uint32_t vb_mask;
>  
>          struct panfrost_sampler_state
> *samplers[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
>          unsigned sampler_count[PIPE_SHADER_TYPES];
> diff --git a/src/gallium/drivers/panfrost/pan_drm.c
> b/src/gallium/drivers/panfrost/pan_drm.c
> index 70d8d7498d4..5fecd4fb27e 100644
> --- a/src/gallium/drivers/panfrost/pan_drm.c
> +++ b/src/gallium/drivers/panfrost/pan_drm.c
> @@ -1,5 +1,6 @@
>  /*
>   * © Copyright 2019 Collabora, Ltd.
> + * Copyright 2019 Alyssa Rosenzweig
>   *
>   * Permission is hereby granted, free of charge, to any person
> obtaining a
>   * copy of this software and associated documentation files (the
> "Software"),
> @@ -138,6 +139,7 @@ panfrost_drm_import_bo(struct panfrost_screen
> *screen, struct winsys_handle *wha
>  
>  	bo->gem_handle = gem_handle;
>          bo->gpu = (mali_ptr) get_bo_offset.offset;
> +        panfrost_bo_reference(bo);
>  
>  	// TODO map and unmap on demand?
>  	mmap_bo.handle = gem_handle;
> @@ -227,6 +229,7 @@ panfrost_drm_submit_job(struct panfrost_context
> *ctx, u64 job_desc, int reqs, st
>  	}
>  
>  	/* TODO: Add here the transient pools */
> +        /* TODO: Add here the BOs listed in the panfrost_job */
>  	bo_handles[submit.bo_handle_count++] = ctx->shaders.gem_handle;
>  	bo_handles[submit.bo_handle_count++] = ctx-
> >scratchpad.gem_handle;
>  	bo_handles[submit.bo_handle_count++] = ctx-
> >tiler_heap.gem_handle;
> @@ -303,6 +306,9 @@ panfrost_drm_force_flush_fragment(struct
> panfrost_context *ctx,
>          if (!screen->last_fragment_flushed) {
>  		drmSyncobjWait(drm->fd, &ctx->out_sync, 1, INT64_MAX,
> 0, NULL);
>                  screen->last_fragment_flushed = true;
> +
> +                /* The job finished up, so we're safe to clean it up
> now */
> +                panfrost_free_job(ctx, screen->last_job);
>  	}
>  
>          if (fence) {
> diff --git a/src/gallium/drivers/panfrost/pan_job.c
> b/src/gallium/drivers/panfrost/pan_job.c
> index 66a8b0d4b07..6c68575158f 100644
> --- a/src/gallium/drivers/panfrost/pan_job.c
> +++ b/src/gallium/drivers/panfrost/pan_job.c
> @@ -27,6 +27,13 @@
>  #include "util/hash_table.h"
>  #include "util/ralloc.h"
>  
> +static void
> +remove_from_ht(struct hash_table *ht, void *key)
> +{
> +        struct hash_entry *entry = _mesa_hash_table_search(ht, key);
> +        _mesa_hash_table_remove(ht, entry);
> +}
> +

This is the same as _mesa_hash_table_remove_key(), no?

>  struct panfrost_job *
>  panfrost_create_job(struct panfrost_context *ctx)
>  {
> @@ -35,9 +42,32 @@ panfrost_create_job(struct panfrost_context *ctx)
>  
>          job->ctx = ctx;
>  
> +        job->bos = _mesa_set_create(job,
> +                                    _mesa_hash_pointer,
> +                                    _mesa_key_pointer_equal);
> + 
>          return job;
>  }
>  
> +void
> +panfrost_free_job(struct panfrost_context *ctx, struct panfrost_job
> *job)
> +{
> +        if (!job)
> +                return;
> +
> +        set_foreach(job->bos, entry) {
> +                struct panfrost_bo *bo = (struct panfrost_bo
> *)entry->key;
> +                panfrost_bo_unreference(ctx->base.screen, bo);
> +        }
> +
> +        remove_from_ht(ctx->jobs, &job->key);
> +
> +        if (ctx->job == job)
> +                ctx->job = NULL;
> +
> +        ralloc_free(job);
> +}
> +
>  struct panfrost_job *
>  panfrost_get_job(struct panfrost_context *ctx,
>                  struct pipe_surface **cbufs, struct pipe_surface
> *zsbuf)
> @@ -90,6 +120,53 @@ panfrost_get_job_for_fbo(struct panfrost_context
> *ctx)
>          return job;
>  }
>  
> +void
> +panfrost_job_add_bo(struct panfrost_job *job, struct panfrost_bo
> *bo)
> +{
> +        if (!bo)
> +                return;
> +
> +        if (_mesa_set_search(job->bos, bo))
> +                return;
> +
> +        panfrost_bo_reference(bo);
> +        _mesa_set_add(job->bos, bo);
> +}
> +
> +void
> +panfrost_flush_jobs_writing_resource(struct panfrost_context
> *panfrost,
> +                                struct pipe_resource *prsc)
> +{
> +#if 0
> +        struct hash_entry *entry = _mesa_hash_table_search(panfrost-
> >write_jobs,
> +                                                           prsc);
> +        if (entry) {
> +                struct panfrost_job *job = entry->data;
> +                panfrost_job_submit(panfrost, job);
> +        }
> +#endif
> +        /* TODO stub */

Did you mean to leave this #if'ed out?

> +}
> +
> +void
> +panfrost_flush_jobs_reading_resource(struct panfrost_context
> *panfrost,
> +                                struct pipe_resource *prsc)
> +{
> +        struct panfrost_resource *rsc = pan_resource(prsc);
> +
> +        panfrost_flush_jobs_writing_resource(panfrost, prsc);
> +
> +        hash_table_foreach(panfrost->jobs, entry) {
> +                struct panfrost_job *job = entry->data;
> +
> +                if (_mesa_set_search(job->bos, rsc->bo)) {
> +                        printf("TODO: submit job for flush\n");
> +                        //panfrost_job_submit(panfrost, job);
> +                        continue;
> +                }
> +        }
> +}
> +
>  static bool
>  panfrost_job_compare(const void *a, const void *b)
>  {
> @@ -109,4 +186,9 @@ panfrost_job_init(struct panfrost_context *ctx)
>          ctx->jobs = _mesa_hash_table_create(NULL,
>                                              panfrost_job_hash,
>                                              panfrost_job_compare);
> +
> +        ctx->write_jobs = _mesa_hash_table_create(NULL,
> +                                            _mesa_hash_pointer,
> +                                            _mesa_key_pointer_equal)
> ;
> +
>  }
> diff --git a/src/gallium/drivers/panfrost/pan_job.h
> b/src/gallium/drivers/panfrost/pan_job.h
> index 30f1cf4bd5c..1b28084c599 100644
> --- a/src/gallium/drivers/panfrost/pan_job.h
> +++ b/src/gallium/drivers/panfrost/pan_job.h
> @@ -55,6 +55,8 @@ struct panfrost_job {
>           * bitmask) */
>          unsigned requirements;
>  
> +        /* BOs referenced -- will be used for flushing logic */
> +        struct set *bos;
>  };
>  
>  /* Functions for managing the above */
> @@ -62,6 +64,9 @@ struct panfrost_job {
>  struct panfrost_job *
>  panfrost_create_job(struct panfrost_context *ctx);
>  
> +void
> +panfrost_free_job(struct panfrost_context *ctx, struct panfrost_job
> *job);
> +
>  struct panfrost_job *
>  panfrost_get_job(struct panfrost_context *ctx,
>                  struct pipe_surface **cbufs, struct pipe_surface
> *zsbuf);
> @@ -72,4 +77,15 @@ panfrost_get_job_for_fbo(struct panfrost_context
> *ctx);
>  void
>  panfrost_job_init(struct panfrost_context *ctx);
>  
> +void
> +panfrost_job_add_bo(struct panfrost_job *job, struct panfrost_bo
> *bo);
> +
> +void
> +panfrost_flush_jobs_writing_resource(struct panfrost_context
> *panfrost,
> +                                struct pipe_resource *prsc);
> +
> +void
> +panfrost_flush_jobs_reading_resource(struct panfrost_context
> *panfrost,
> +                                struct pipe_resource *prsc);
> +
>  #endif
> diff --git a/src/gallium/drivers/panfrost/pan_resource.c
> b/src/gallium/drivers/panfrost/pan_resource.c
> index 15d522f1963..a0fc64fa1c1 100644
> --- a/src/gallium/drivers/panfrost/pan_resource.c
> +++ b/src/gallium/drivers/panfrost/pan_resource.c
> @@ -228,6 +228,7 @@ static struct panfrost_bo *
>  panfrost_create_bo(struct panfrost_screen *screen, const struct
> pipe_resource *template)
>  {
>  	struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
> +        panfrost_bo_reference(bo);
>  
>          /* Based on the usage, figure out what storing will be used.
> There are
>           * various tradeoffs:
> @@ -297,6 +298,8 @@ panfrost_resource_create(struct pipe_screen
> *screen,
>                          assert(0);
>          }
>  
> +        util_range_init(&so->valid_buffer_range);
> +
>          if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
>              template->bind & PIPE_BIND_SCANOUT ||
>              template->bind & PIPE_BIND_SHARED) {
> @@ -359,6 +362,25 @@ panfrost_destroy_bo(struct panfrost_screen
> *screen, struct panfrost_bo *pbo)
>          }
>  }
>  
> +void
> +panfrost_bo_reference(struct panfrost_bo *bo)
> +{
> +        p_atomic_inc(&bo->reference_count);
> +}
> +
> +void
> +panfrost_bo_unreference(struct pipe_screen *screen, struct
> panfrost_bo *bo)
> +{
> +        /* Check for double free errors */
> +        assert(bo->reference_count);
> +
> +        /* When the reference count goes to zero, we need to cleanup
> */
> +
> +        if (p_atomic_dec_zero(&bo->reference_count)) {
> +                panfrost_destroy_bo(pan_screen(screen), bo);
> +        }
> +}
> +

Why not use pipe_reference instead of open-coding? That helper contains
some neat debug-helpers etc...

>  static void
>  panfrost_resource_destroy(struct pipe_screen *screen,
>                            struct pipe_resource *pt)
> @@ -370,8 +392,9 @@ panfrost_resource_destroy(struct pipe_screen
> *screen,
>  		renderonly_scanout_destroy(rsrc->scanout, pscreen->ro);
>  
>  	if (rsrc->bo)
> -		panfrost_destroy_bo(pscreen, rsrc->bo);
> +                panfrost_bo_unreference(screen, rsrc->bo);
>  
> +        util_range_destroy(&rsrc->valid_buffer_range);
>  	FREE(rsrc);
>  }
>  
> @@ -384,7 +407,8 @@ panfrost_transfer_map(struct pipe_context *pctx,
>                        struct pipe_transfer **out_transfer)
>  {
>          int bytes_per_pixel = util_format_get_blocksize(resource-
> >format);
> -        struct panfrost_bo *bo = pan_resource(resource)->bo;
> +        struct panfrost_resource *rsrc = pan_resource(resource);
> +        struct panfrost_bo *bo = rsrc->bo;
>  
>          struct panfrost_gtransfer *transfer =
> CALLOC_STRUCT(panfrost_gtransfer);
>          transfer->base.level = level;
> @@ -405,6 +429,25 @@ panfrost_transfer_map(struct pipe_context *pctx,
>                  panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME);
>          }
>  
> +        if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
> +                /* TODO: reallocate */
> +                //printf("debug: Missed reallocate\n");
> +        } else if ((usage & PIPE_TRANSFER_WRITE)
> +                        && resource->target == PIPE_BUFFER
> +                        && !util_ranges_intersect(&rsrc-
> >valid_buffer_range, box->x, box->x + box->width)) {
> +                /* No flush for writes to uninitialized */
> +        } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
> +                if (usage & PIPE_TRANSFER_WRITE) {
> +                        /* STUB: flush reading */
> +                        //printf("debug: missed reading flush %d\n",
> resource->target);
> +                } else if (usage & PIPE_TRANSFER_READ) {
> +                        /* STUB: flush writing */
> +                        //printf("debug: missed writing flush %d
> (%d-%d)\n", resource->target, box->x, box->x + box->width);
> +                } else {
> +                        /* Why are you even mapping?! */
> +                }
> +        }
> +
>          if (bo->layout != PAN_LINEAR) {
>                  /* Non-linear resources need to be indirectly mapped
> */
>  
> @@ -460,9 +503,9 @@ panfrost_transfer_unmap(struct pipe_context
> *pctx,
>          /* Gallium expects writeback here, so we tile */
>  
>          struct panfrost_gtransfer *trans = pan_transfer(transfer);
> +        struct panfrost_resource *prsrc = (struct panfrost_resource
> *) transfer->resource;
>  
>          if (trans->map) {
> -                struct panfrost_resource *prsrc = (struct
> panfrost_resource *) transfer->resource;
>                  struct panfrost_bo *bo = prsrc->bo;
>  
>                  if (transfer->usage & PIPE_TRANSFER_WRITE) {
> @@ -480,6 +523,11 @@ panfrost_transfer_unmap(struct pipe_context
> *pctx,
>                  free(trans->map);
>          }
>  
> +
> +	util_range_add(&prsrc->valid_buffer_range,
> +                        transfer->box.x,
> +                        transfer->box.x + transfer->box.width);
> +
>          /* Derefence the resource */
>          pipe_resource_reference(&transfer->resource, NULL);
>  
> @@ -487,6 +535,20 @@ panfrost_transfer_unmap(struct pipe_context
> *pctx,
>          free(transfer);
>  }
>  
> +static void
> +panfrost_transfer_flush_region(struct pipe_context *pctx,
> +		struct pipe_transfer *transfer,
> +		const struct pipe_box *box)
> +{
> +	struct panfrost_resource *rsc = pan_resource(transfer-
> >resource);
> +
> +	if (transfer->resource->target == PIPE_BUFFER) {
> +		util_range_add(&rsc->valid_buffer_range,
> +					   transfer->box.x + box->x,
> +					   transfer->box.x + box->x +
> box->width);
> +        }
> +}
> +
>  static struct pb_slab *
>  panfrost_slab_alloc(void *priv, unsigned heap, unsigned entry_size,
> unsigned group_index)
>  {
> @@ -564,7 +626,7 @@ static const struct u_transfer_vtbl transfer_vtbl
> = {
>          .resource_destroy         = panfrost_resource_destroy,
>          .transfer_map             = panfrost_transfer_map,
>          .transfer_unmap           = panfrost_transfer_unmap,
> -        .transfer_flush_region    = u_default_transfer_flush_region,
> +        .transfer_flush_region    = panfrost_transfer_flush_region,
>          .get_internal_format      =
> panfrost_resource_get_internal_format,
>          .set_stencil              = panfrost_resource_set_stencil,
>          .get_stencil              = panfrost_resource_get_stencil,
> diff --git a/src/gallium/drivers/panfrost/pan_resource.h
> b/src/gallium/drivers/panfrost/pan_resource.h
> index a1315ab1b43..b9d6cd2b023 100644
> --- a/src/gallium/drivers/panfrost/pan_resource.h
> +++ b/src/gallium/drivers/panfrost/pan_resource.h
> @@ -30,6 +30,7 @@
>  #include "pan_screen.h"
>  #include "pan_allocate.h"
>  #include "drm-uapi/drm.h"
> +#include "util/u_range.h"
>  
>  /* Describes the memory layout of a BO */
>  
> @@ -45,6 +46,10 @@ struct panfrost_slice {
>  };
>  
>  struct panfrost_bo {
> +        /* Reference count */
> +        unsigned reference_count;
> +
> +        /* Description of the mip levels */
>          struct panfrost_slice slices[MAX_MIP_LEVELS];
>  
>          /* Mapping for the entire object (all levels) */
> @@ -83,6 +88,12 @@ struct panfrost_bo {
>          int gem_handle;
>  };
>  
> +void
> +panfrost_bo_reference(struct panfrost_bo *bo);
> +
> +void
> +panfrost_bo_unreference(struct pipe_screen *screen, struct
> panfrost_bo *bo);
> +
>  struct panfrost_resource {
>          struct pipe_resource base;
>  
> @@ -90,6 +101,8 @@ struct panfrost_resource {
>          struct renderonly_scanout *scanout;
>  
>          struct panfrost_resource *separate_stencil;
> +
> +        struct util_range valid_buffer_range;
>  };
>  
>  static inline struct panfrost_resource *
> diff --git a/src/gallium/drivers/panfrost/pan_screen.c
> b/src/gallium/drivers/panfrost/pan_screen.c
> index 71c6175d069..6d3aca594f1 100644
> --- a/src/gallium/drivers/panfrost/pan_screen.c
> +++ b/src/gallium/drivers/panfrost/pan_screen.c
> @@ -597,8 +597,8 @@ panfrost_create_screen(int fd, struct renderonly
> *ro)
>          screen->base.fence_reference = panfrost_fence_reference;
>          screen->base.fence_finish = panfrost_fence_finish;
>  
> -	screen->last_fragment_id = -1;
>  	screen->last_fragment_flushed = true;
> +        screen->last_job = NULL;
>  
>          panfrost_resource_screen_init(screen);
>  
> diff --git a/src/gallium/drivers/panfrost/pan_screen.h
> b/src/gallium/drivers/panfrost/pan_screen.h
> index cbadf813675..4e5efa91f22 100644
> --- a/src/gallium/drivers/panfrost/pan_screen.h
> +++ b/src/gallium/drivers/panfrost/pan_screen.h
> @@ -92,8 +92,11 @@ struct panfrost_screen {
>          /* TODO: Where? */
>          struct panfrost_resource *display_target;
>  
> -	int last_fragment_id;
> +        /* While we're busy building up the job for frame N, the GPU
> is
> +         * still busy executing frame N-1. So hold a reference to
> +         * yesterjob */
>  	int last_fragment_flushed;
> +        struct panfrost_job *last_job;
>  };
>  
>  #endif /* PAN_SCREEN_H */



More information about the mesa-dev mailing list