Before freeing a framebuffer, we call complete_scanout encoder function which just calls wait for vblank of all the encoders. This is not a very optimized method since a framebuffer might not be in use by a crtc and we end up waiting for vblank unnecessarily. Instead, this patch modifies the wait_for_vblank interface to complete_scanout interface. In this function, each crtc must check if the fb is currently being used. If it is being used, it must wait for vsync (or even disable a window if necessary) and ensure that the buffer is no longer used by crtc before returning. So if a crtc is not actually reading from the buffer, the complete scanout function will just return and not wait for vsync. Signed-off-by: Prathyush K <prathyush.k@xxxxxxxxxxx> --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 7 ++++--- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 23 +++++++++++------------ drivers/gpu/drm/exynos/exynos_drm_encoder.h | 4 +++- drivers/gpu/drm/exynos/exynos_drm_fb.c | 13 +++++++++++-- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b9e51bc..d351daf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -167,8 +167,7 @@ struct exynos_drm_display_ops { * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt. - * @wait_for_vblank: wait for vblank interrupt to make sure that - * hardware overlay is updated. + * @complete_scanout: complete scan of buffer so that it can be freed. */ struct exynos_drm_manager_ops { void (*dpms)(struct device *subdrv_dev, int mode); @@ -183,7 +182,9 @@ struct exynos_drm_manager_ops { void (*commit)(struct device *subdrv_dev); int (*enable_vblank)(struct device *subdrv_dev); void (*disable_vblank)(struct device *subdrv_dev); - void (*wait_for_vblank)(struct device *subdrv_dev); + void (*complete_scanout)(struct device *subdrv_dev, + dma_addr_t dma_addr, + unsigned long size); }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index c63721f..7e772ed 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -220,28 +220,27 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) exynos_encoder->dpms = DRM_MODE_DPMS_ON; } -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb) +void exynos_drm_encoder_complete_scanout(struct drm_device *drm_dev, + dma_addr_t dma_addr, + unsigned long size) { struct exynos_drm_encoder *exynos_encoder; struct exynos_drm_manager_ops *ops; - struct drm_device *dev = fb->dev; struct drm_encoder *encoder; + struct device *dev; - /* - * make sure that overlay data are updated to real hardware - * for all encoders. - */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + /* make sure that current framebuffer is not in use for all encoders */ + list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list, head) { exynos_encoder = to_exynos_encoder(encoder); ops = exynos_encoder->manager->ops; + dev = exynos_encoder->manager->dev; /* - * wait for vblank interrupt - * - this makes sure that overlay data are updated to - * real hardware. + * complete_scanout + * - this makes sure that framebuffer is not in use. */ - if (ops->wait_for_vblank) - ops->wait_for_vblank(exynos_encoder->manager->dev); + if (ops->complete_scanout) + ops->complete_scanout(dev, dma_addr, size); } } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h index 89e2fb0..b85211b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h @@ -32,6 +32,8 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data); void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data); void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data); void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb); +void exynos_drm_encoder_complete_scanout(struct drm_device *drm_dev, + dma_addr_t dma_addr, + unsigned long size); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 294c051..1ef684a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -69,11 +69,20 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); unsigned int i; + dma_addr_t dma_addr; + unsigned long size; DRM_DEBUG_KMS("%s\n", __FILE__); - /* make sure that overlay data are updated before relesing fb. */ - exynos_drm_encoder_complete_scanout(fb); + for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { + if (exynos_fb->exynos_gem_obj[i] == NULL) + continue; + + dma_addr = exynos_fb->exynos_gem_obj[i]->buffer->dma_addr; + size = exynos_fb->exynos_gem_obj[i]->buffer->size; + + exynos_drm_encoder_complete_scanout(fb->dev, dma_addr, size); + } drm_framebuffer_cleanup(fb); -- 1.8.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel