summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/msm_fb.c
diff options
context:
space:
mode:
authorRob Clark <robdclark@chromium.org>2022-02-23 22:11:08 +0300
committerRob Clark <robdclark@chromium.org>2022-02-25 18:59:58 +0300
commit9e4dde28e9cd34ee13a6b7247f0857fb49fd3f19 (patch)
tree17fee6c9091477bc662c43c372e91dfa203539f9 /drivers/gpu/drm/msm/msm_fb.c
parentdb22583d6c7da2b20965514a123705cf753c931a (diff)
downloadlinux-9e4dde28e9cd34ee13a6b7247f0857fb49fd3f19.tar.xz
drm/msm: Avoid dirtyfb stalls on video mode displays (v2)
Someone on IRC once asked an innocent enough sounding question: Why with xf86-video-modesetting is es2gears limited at 120fps. So I broke out the perfetto tracing mesa MR and took a look. It turns out the problem was drm_atomic_helper_dirtyfb(), which would end up waiting for vblank.. es2gears would rapidly push two frames to Xorg, which would blit them to screen and in idle hook (I assume) call the DIRTYFB ioctl. Which in turn would do an atomic update to flush the dirty rects, which would stall until the next vblank. And then the whole process would repeat. But this is a bit silly, we only need dirtyfb for command mode DSI panels. So track in plane state whether dirtyfb is required, and track in the fb how many attached planes require dirtyfb so that we can skip it when not required. (Note, mdp4 does not actually have cmd mode support.) Signed-off-by: Rob Clark <robdclark@chromium.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20220223191118.881321-1-robdclark@gmail.com Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/msm_fb.c')
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c41
1 files changed, 34 insertions, 7 deletions
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 4d34df5354e0..96b379a08327 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -18,16 +18,36 @@
struct msm_framebuffer {
struct drm_framebuffer base;
const struct msm_format *format;
+
+ /* Count of # of attached planes which need dirtyfb: */
+ refcount_t dirtyfb;
};
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb,
+ struct drm_file *file_priv, unsigned int flags,
+ unsigned int color, struct drm_clip_rect *clips,
+ unsigned int num_clips)
+{
+ struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+
+ /* If this fb is not used on any display requiring pixel data to be
+ * flushed, then skip dirtyfb
+ */
+ if (refcount_read(&msm_fb->dirtyfb) == 0)
+ return 0;
+
+ return drm_atomic_helper_dirtyfb(fb, file_priv, flags, color,
+ clips, num_clips);
+}
+
static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
.create_handle = drm_gem_fb_create_handle,
.destroy = drm_gem_fb_destroy,
- .dirty = drm_atomic_helper_dirtyfb,
+ .dirty = msm_framebuffer_dirtyfb,
};
#ifdef CONFIG_DEBUG_FS
@@ -48,17 +68,19 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
}
#endif
-/* prepare/pin all the fb's bo's for scanout. Note that it is not valid
- * to prepare an fb more multiple different initiator 'id's. But that
- * should be fine, since only the scanout (mdpN) side of things needs
- * this, the gpu doesn't care about fb's.
+/* prepare/pin all the fb's bo's for scanout.
*/
int msm_framebuffer_prepare(struct drm_framebuffer *fb,
- struct msm_gem_address_space *aspace)
+ struct msm_gem_address_space *aspace,
+ bool needs_dirtyfb)
{
+ struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
int ret, i, n = fb->format->num_planes;
uint64_t iova;
+ if (needs_dirtyfb)
+ refcount_inc(&msm_fb->dirtyfb);
+
for (i = 0; i < n; i++) {
ret = msm_gem_get_and_pin_iova(fb->obj[i], aspace, &iova);
drm_dbg_state(fb->dev, "FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret);
@@ -70,10 +92,15 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb,
}
void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
- struct msm_gem_address_space *aspace)
+ struct msm_gem_address_space *aspace,
+ bool needed_dirtyfb)
{
+ struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
int i, n = fb->format->num_planes;
+ if (needed_dirtyfb)
+ refcount_dec(&msm_fb->dirtyfb);
+
for (i = 0; i < n; i++)
msm_gem_unpin_iova(fb->obj[i], aspace);
}