Skip to content

Commit d19e00e

Browse files
committed
drm/vc4: crtc: Fix out of order frames during asynchronous page flips
When doing an asynchronous page flip (PAGE_FLIP ioctl with the DRM_MODE_PAGE_FLIP_ASYNC flag set), the current code waits for the possible GPU buffer being rendered through a call to vc4_queue_seqno_cb(). On the BCM2835-37, the GPU driver is part of the vc4 driver and that function is defined in vc4_gem.c to wait for the buffer to be rendered, and once it's done, call a callback. However, on the BCM2711 used on the RaspberryPi4, the GPU driver is separate (v3d) and that function won't do anything. This was working because we were going into a path, due to uninitialized variables, that was always scheduling the callback. However, we were never actually waiting for the buffer to be rendered which was resulting in frames being displayed out of order. The generic API to signal those kind of completion in the kernel are the DMA fences, and fortunately the v3d drivers supports them and signal when its job is done. That API also provides an equivalent function that allows to have a callback being executed when the fence is signalled as done. Let's change our driver a bit to rely on the previous function for the older SoCs, and on DMA fences for the BCM2711. Signed-off-by: Maxime Ripard <maxime@cerno.tech> Reviewed-by: Melissa Wen <mwen@igalia.com> Link: https://lore.kernel.org/r/20220610115149.964394-14-maxime@cerno.tech
1 parent d87db1c commit d19e00e

1 file changed

Lines changed: 46 additions & 4 deletions

File tree

drivers/gpu/drm/vc4/vc4_crtc.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ struct vc4_async_flip_state {
776776
struct drm_pending_vblank_event *event;
777777

778778
union {
779+
struct dma_fence_cb fence;
779780
struct vc4_seqno_cb seqno;
780781
} cb;
781782
};
@@ -835,6 +836,50 @@ static void vc4_async_page_flip_seqno_complete(struct vc4_seqno_cb *cb)
835836
vc4_bo_dec_usecnt(bo);
836837
}
837838

839+
static void vc4_async_page_flip_fence_complete(struct dma_fence *fence,
840+
struct dma_fence_cb *cb)
841+
{
842+
struct vc4_async_flip_state *flip_state =
843+
container_of(cb, struct vc4_async_flip_state, cb.fence);
844+
845+
vc4_async_page_flip_complete(flip_state);
846+
dma_fence_put(fence);
847+
}
848+
849+
static int vc4_async_set_fence_cb(struct drm_device *dev,
850+
struct vc4_async_flip_state *flip_state)
851+
{
852+
struct drm_framebuffer *fb = flip_state->fb;
853+
struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
854+
struct vc4_dev *vc4 = to_vc4_dev(dev);
855+
struct dma_fence *fence;
856+
int ret;
857+
858+
if (!vc4->is_vc5) {
859+
struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
860+
861+
return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno,
862+
vc4_async_page_flip_seqno_complete);
863+
}
864+
865+
ret = dma_resv_get_singleton(cma_bo->base.resv, DMA_RESV_USAGE_READ, &fence);
866+
if (ret)
867+
return ret;
868+
869+
/* If there's no fence, complete the page flip immediately */
870+
if (!fence) {
871+
vc4_async_page_flip_fence_complete(fence, &flip_state->cb.fence);
872+
return 0;
873+
}
874+
875+
/* If the fence has already been completed, complete the page flip */
876+
if (dma_fence_add_callback(fence, &flip_state->cb.fence,
877+
vc4_async_page_flip_fence_complete))
878+
vc4_async_page_flip_fence_complete(fence, &flip_state->cb.fence);
879+
880+
return 0;
881+
}
882+
838883
static int
839884
vc4_async_page_flip_common(struct drm_crtc *crtc,
840885
struct drm_framebuffer *fb,
@@ -844,8 +889,6 @@ vc4_async_page_flip_common(struct drm_crtc *crtc,
844889
struct drm_device *dev = crtc->dev;
845890
struct drm_plane *plane = crtc->primary;
846891
struct vc4_async_flip_state *flip_state;
847-
struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
848-
struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
849892

850893
flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
851894
if (!flip_state)
@@ -876,8 +919,7 @@ vc4_async_page_flip_common(struct drm_crtc *crtc,
876919
*/
877920
drm_atomic_set_fb_for_plane(plane->state, fb);
878921

879-
vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno,
880-
vc4_async_page_flip_seqno_complete);
922+
vc4_async_set_fence_cb(dev, flip_state);
881923

882924
/* Driver takes ownership of state on successful async commit. */
883925
return 0;

0 commit comments

Comments
 (0)