diff options
author | Eric Anholt <eric@anholt.net> | 2015-06-29 13:55:30 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2015-06-29 15:37:14 -0700 |
commit | e87405ac875a260133b9f9b28e672b7bce077a28 (patch) | |
tree | ecbbd3be671fb4ee6a90ae1de76ee6318ceba268 | |
parent | 2422739db1e6cb7d88f5bc3739ccd9282514efd3 (diff) | |
download | linux-e87405ac875a260133b9f9b28e672b7bce077a28.tar.gz |
drm/vc4: Implement custom atomic commit in vc4.
This is just drm_atomic_helper_commit(), with wait_for_fence replaced
with V3D seqno waits based on msm's atomic commit's wait loop.
This means we now synchronize to our own rendering. The old
wait_for_fence loop did nothing since we never attached a dmabuf fence
to our plane state.
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_kms.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 98b57bd0fc80..e498696fe21f 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -7,15 +7,104 @@ */ #include "drm_crtc.h" +#include "drm_atomic.h" #include "drm_atomic_helper.h" #include "drm_crtc_helper.h" #include "drm_plane_helper.h" #include "drm_fb_cma_helper.h" #include "vc4_drv.h" + +/** + * vc4_atomic_commit - commit validated state object + * @dev: DRM device + * @state: the driver state object + * @async: asynchronous commit + * + * This function commits a with drm_atomic_helper_check() pre-validated state + * object. This can still fail when e.g. the framebuffer reservation fails. For + * now this doesn't implement asynchronous commits. + * + * RETURNS + * Zero for success or -errno. + */ +static int vc4_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + int ret; + int i; + uint64_t wait_seqno = 0; + + if (async) { + DRM_ERROR("async\n"); + return -EBUSY; + } + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + for (i = 0; i < dev->mode_config.num_total_plane; i++) { + struct drm_plane *plane = state->planes[i]; + struct drm_plane_state *new_state = state->plane_states[i]; + + if (!plane) + continue; + + if ((plane->state->fb != new_state->fb) && new_state->fb) { + struct drm_gem_cma_object *cma_bo; + struct vc4_bo *bo; + cma_bo = drm_fb_cma_get_gem_obj(plane->state->fb, 0); + bo = to_vc4_bo(&cma_bo->base); + wait_seqno = max(bo->seqno, wait_seqno); + } + } + + /* + * This is the point of no return - everything below never fails except + * when the hw goes bonghits. Which means we can commit the new state on + * the software side now. + */ + + drm_atomic_helper_swap_state(dev, state); + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one condition: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout. + */ + + vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false); + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + drm_atomic_state_free(state); + + return 0; +} + static const struct drm_mode_config_funcs vc4_mode_funcs = { .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, + .atomic_commit = vc4_atomic_commit, .fb_create = drm_fb_cma_create, }; |