Skip to content

Commit 674e78a

Browse files
Nicholas Kazlauskasalexdeucher
authored andcommitted
drm/amd/display: Add fast path for cursor plane updates
[Why] Legacy cursor plane updates from drm helpers go through the full atomic codepath. A high volume of cursor updates through this slow code path can cause subsequent page-flips to skip vblank intervals since each individual update is slow. This problem is particularly noticeable for the compton compositor. [How] A fast path for cursor plane updates is added by using DRM asynchronous commit support provided by async_check and async_update. These don't do a full state/flip_done dependency stall and they don't block other commit work. However, DC still expects itself to be single-threaded for anything that can issue register writes. Screen corruption or hangs can occur if write sequences overlap. Every call that potentially perform register writes needs to be guarded for asynchronous updates to work. The dc_lock mutex was added for this. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106175 Signed-off-by: Nicholas Kazlauskas <[email protected]> Acked-by: Andrey Grodzovsky <[email protected]> Reviewed-by Leo Li <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent fc42d47 commit 674e78a

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757

5858
#include <drm/drmP.h>
5959
#include <drm/drm_atomic.h>
60+
#include <drm/drm_atomic_uapi.h>
6061
#include <drm/drm_atomic_helper.h>
6162
#include <drm/drm_dp_mst_helper.h>
6263
#include <drm/drm_fb_helper.h>
@@ -133,6 +134,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
133134
static int amdgpu_dm_atomic_check(struct drm_device *dev,
134135
struct drm_atomic_state *state);
135136

137+
static void handle_cursor_update(struct drm_plane *plane,
138+
struct drm_plane_state *old_plane_state);
136139

137140

138141

@@ -402,6 +405,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
402405
/* Zero all the fields */
403406
memset(&init_data, 0, sizeof(init_data));
404407

408+
mutex_init(&adev->dm.dc_lock);
409+
405410
if(amdgpu_dm_irq_init(adev)) {
406411
DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
407412
goto error;
@@ -516,6 +521,9 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
516521
/* DC Destroy TODO: Replace destroy DAL */
517522
if (adev->dm.dc)
518523
dc_destroy(&adev->dm.dc);
524+
525+
mutex_destroy(&adev->dm.dc_lock);
526+
519527
return;
520528
}
521529

@@ -3617,10 +3625,43 @@ static int dm_plane_atomic_check(struct drm_plane *plane,
36173625
return -EINVAL;
36183626
}
36193627

3628+
static int dm_plane_atomic_async_check(struct drm_plane *plane,
3629+
struct drm_plane_state *new_plane_state)
3630+
{
3631+
/* Only support async updates on cursor planes. */
3632+
if (plane->type != DRM_PLANE_TYPE_CURSOR)
3633+
return -EINVAL;
3634+
3635+
return 0;
3636+
}
3637+
3638+
static void dm_plane_atomic_async_update(struct drm_plane *plane,
3639+
struct drm_plane_state *new_state)
3640+
{
3641+
struct drm_plane_state *old_state =
3642+
drm_atomic_get_old_plane_state(new_state->state, plane);
3643+
3644+
if (plane->state->fb != new_state->fb)
3645+
drm_atomic_set_fb_for_plane(plane->state, new_state->fb);
3646+
3647+
plane->state->src_x = new_state->src_x;
3648+
plane->state->src_y = new_state->src_y;
3649+
plane->state->src_w = new_state->src_w;
3650+
plane->state->src_h = new_state->src_h;
3651+
plane->state->crtc_x = new_state->crtc_x;
3652+
plane->state->crtc_y = new_state->crtc_y;
3653+
plane->state->crtc_w = new_state->crtc_w;
3654+
plane->state->crtc_h = new_state->crtc_h;
3655+
3656+
handle_cursor_update(plane, old_state);
3657+
}
3658+
36203659
static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
36213660
.prepare_fb = dm_plane_helper_prepare_fb,
36223661
.cleanup_fb = dm_plane_helper_cleanup_fb,
36233662
.atomic_check = dm_plane_atomic_check,
3663+
.atomic_async_check = dm_plane_atomic_async_check,
3664+
.atomic_async_update = dm_plane_atomic_async_update
36243665
};
36253666

36263667
/*
@@ -4309,6 +4350,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
43094350
static void handle_cursor_update(struct drm_plane *plane,
43104351
struct drm_plane_state *old_plane_state)
43114352
{
4353+
struct amdgpu_device *adev = plane->dev->dev_private;
43124354
struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
43134355
struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
43144356
struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
@@ -4333,9 +4375,12 @@ static void handle_cursor_update(struct drm_plane *plane,
43334375

43344376
if (!position.enable) {
43354377
/* turn off cursor */
4336-
if (crtc_state && crtc_state->stream)
4378+
if (crtc_state && crtc_state->stream) {
4379+
mutex_lock(&adev->dm.dc_lock);
43374380
dc_stream_set_cursor_position(crtc_state->stream,
43384381
&position);
4382+
mutex_unlock(&adev->dm.dc_lock);
4383+
}
43394384
return;
43404385
}
43414386

@@ -4353,13 +4398,15 @@ static void handle_cursor_update(struct drm_plane *plane,
43534398
attributes.pitch = attributes.width;
43544399

43554400
if (crtc_state->stream) {
4401+
mutex_lock(&adev->dm.dc_lock);
43564402
if (!dc_stream_set_cursor_attributes(crtc_state->stream,
43574403
&attributes))
43584404
DRM_ERROR("DC failed to set cursor attributes\n");
43594405

43604406
if (!dc_stream_set_cursor_position(crtc_state->stream,
43614407
&position))
43624408
DRM_ERROR("DC failed to set cursor position\n");
4409+
mutex_unlock(&adev->dm.dc_lock);
43634410
}
43644411
}
43654412

@@ -4575,13 +4622,15 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
45754622
&acrtc_state->stream->vrr_infopacket;
45764623
}
45774624

4625+
mutex_lock(&adev->dm.dc_lock);
45784626
dc_commit_updates_for_stream(adev->dm.dc,
45794627
surface_updates,
45804628
1,
45814629
acrtc_state->stream,
45824630
&stream_update,
45834631
&surface_updates->surface,
45844632
state);
4633+
mutex_unlock(&adev->dm.dc_lock);
45854634

45864635
DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
45874636
__func__,
@@ -4596,6 +4645,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
45964645
* with a dc_plane_state and follow the atomic model a bit more closely here.
45974646
*/
45984647
static bool commit_planes_to_stream(
4648+
struct amdgpu_display_manager *dm,
45994649
struct dc *dc,
46004650
struct dc_plane_state **plane_states,
46014651
uint8_t new_plane_count,
@@ -4672,11 +4722,13 @@ static bool commit_planes_to_stream(
46724722
updates[i].scaling_info = &scaling_info[i];
46734723
}
46744724

4725+
mutex_lock(&dm->dc_lock);
46754726
dc_commit_updates_for_stream(
46764727
dc,
46774728
updates,
46784729
new_plane_count,
46794730
dc_stream, stream_update, plane_states, state);
4731+
mutex_unlock(&dm->dc_lock);
46804732

46814733
kfree(flip_addr);
46824734
kfree(plane_info);
@@ -4782,7 +4834,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
47824834

47834835
dc_stream_attach->abm_level = acrtc_state->abm_level;
47844836

4785-
if (false == commit_planes_to_stream(dm->dc,
4837+
if (false == commit_planes_to_stream(dm,
4838+
dm->dc,
47864839
plane_states_constructed,
47874840
planes_count,
47884841
acrtc_state,
@@ -4952,7 +5005,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
49525005

49535006
if (dc_state) {
49545007
dm_enable_per_frame_crtc_master_sync(dc_state);
5008+
mutex_lock(&dm->dc_lock);
49555009
WARN_ON(!dc_commit_state(dm->dc, dc_state));
5010+
mutex_unlock(&dm->dc_lock);
49565011
}
49575012

49585013
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
@@ -5014,6 +5069,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
50145069

50155070
/*TODO How it works with MPO ?*/
50165071
if (!commit_planes_to_stream(
5072+
dm,
50175073
dm->dc,
50185074
status->plane_states,
50195075
status->plane_count,
@@ -5906,6 +5962,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
59065962
ret = -EINVAL;
59075963
goto fail;
59085964
}
5965+
} else if (state->legacy_cursor_update) {
5966+
/*
5967+
* This is a fast cursor update coming from the plane update
5968+
* helper, check if it can be done asynchronously for better
5969+
* performance.
5970+
*/
5971+
state->async_update = !drm_atomic_helper_async_check(dev, state);
59095972
}
59105973

59115974
/* Must be success */

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ struct amdgpu_display_manager {
134134

135135
struct drm_modeset_lock atomic_obj_lock;
136136

137+
/**
138+
* @dc_lock:
139+
*
140+
* Guards access to DC functions that can issue register write
141+
* sequences.
142+
*/
143+
struct mutex dc_lock;
144+
137145
/**
138146
* @irq_handler_list_low_tab:
139147
*

0 commit comments

Comments
 (0)