Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: add FB_DAMAGE_CLIPS support

Currently, userspace doesn't have a way to communicate selective updates
to displays. So, enable support for FB_DAMAGE_CLIPS for DCN ASICs newer
than DCN301, convert DRM damage clips to dc dirty rectangles and fill
them into dirty_rects in fill_dc_dirty_rects().

Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Hamza Mahfooz and committed by
Alex Deucher
30ebe415 fed58c70

+87 -45
+83 -45
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 4869 4869 return 0; 4870 4870 } 4871 4871 4872 + static inline void fill_dc_dirty_rect(struct drm_plane *plane, 4873 + struct rect *dirty_rect, int32_t x, 4874 + int32_t y, int32_t width, int32_t height, 4875 + int *i, bool ffu) 4876 + { 4877 + if (*i > DC_MAX_DIRTY_RECTS) 4878 + return; 4879 + 4880 + if (*i == DC_MAX_DIRTY_RECTS) 4881 + goto out; 4882 + 4883 + dirty_rect->x = x; 4884 + dirty_rect->y = y; 4885 + dirty_rect->width = width; 4886 + dirty_rect->height = height; 4887 + 4888 + if (ffu) 4889 + drm_dbg(plane->dev, 4890 + "[PLANE:%d] PSR FFU dirty rect size (%d, %d)\n", 4891 + plane->base.id, width, height); 4892 + else 4893 + drm_dbg(plane->dev, 4894 + "[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)", 4895 + plane->base.id, x, y, width, height); 4896 + 4897 + out: 4898 + (*i)++; 4899 + } 4900 + 4872 4901 /** 4873 4902 * fill_dc_dirty_rects() - Fill DC dirty regions for PSR selective updates 4874 4903 * ··· 4918 4889 * addition, certain use cases - such as cursor and multi-plane overlay (MPO) - 4919 4890 * implicitly provide damage clips without any client support via the plane 4920 4891 * bounds. 4921 - * 4922 - * Today, amdgpu_dm only supports the MPO and cursor usecase. 4923 - * 4924 - * TODO: Also enable for FB_DAMAGE_CLIPS 4925 4892 */ 4926 4893 static void fill_dc_dirty_rects(struct drm_plane *plane, 4927 4894 struct drm_plane_state *old_plane_state, ··· 4928 4903 struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); 4929 4904 struct rect *dirty_rects = flip_addrs->dirty_rects; 4930 4905 uint32_t num_clips; 4906 + struct drm_mode_rect *clips; 4931 4907 bool bb_changed; 4932 4908 bool fb_changed; 4933 4909 uint32_t i = 0; 4934 - 4935 - flip_addrs->dirty_rect_count = 0; 4936 4910 4937 4911 /* 4938 4912 * Cursor plane has it's own dirty rect update interface. See ··· 4940 4916 if (plane->type == DRM_PLANE_TYPE_CURSOR) 4941 4917 return; 4942 4918 4943 - /* 4944 - * Today, we only consider MPO use-case for PSR SU. If MPO not 4945 - * requested, and there is a plane update, do FFU. 4946 - */ 4919 + num_clips = drm_plane_get_damage_clips_count(new_plane_state); 4920 + clips = drm_plane_get_damage_clips(new_plane_state); 4921 + 4947 4922 if (!dm_crtc_state->mpo_requested) { 4948 - dirty_rects[0].x = 0; 4949 - dirty_rects[0].y = 0; 4950 - dirty_rects[0].width = dm_crtc_state->base.mode.crtc_hdisplay; 4951 - dirty_rects[0].height = dm_crtc_state->base.mode.crtc_vdisplay; 4952 - flip_addrs->dirty_rect_count = 1; 4953 - DRM_DEBUG_DRIVER("[PLANE:%d] PSR FFU dirty rect size (%d, %d)\n", 4954 - new_plane_state->plane->base.id, 4955 - dm_crtc_state->base.mode.crtc_hdisplay, 4956 - dm_crtc_state->base.mode.crtc_vdisplay); 4923 + if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS) 4924 + goto ffu; 4925 + 4926 + for (; flip_addrs->dirty_rect_count < num_clips; clips++) 4927 + fill_dc_dirty_rect(new_plane_state->plane, 4928 + &dirty_rects[i], clips->x1, 4929 + clips->y1, clips->x2 - clips->x1, 4930 + clips->y2 - clips->y1, 4931 + &flip_addrs->dirty_rect_count, 4932 + false); 4957 4933 return; 4958 4934 } 4959 4935 ··· 4964 4940 * If plane is moved or resized, also add old bounding box to dirty 4965 4941 * rects. 4966 4942 */ 4967 - num_clips = drm_plane_get_damage_clips_count(new_plane_state); 4968 4943 fb_changed = old_plane_state->fb->base.id != 4969 4944 new_plane_state->fb->base.id; 4970 4945 bb_changed = (old_plane_state->crtc_x != new_plane_state->crtc_x || ··· 4971 4948 old_plane_state->crtc_w != new_plane_state->crtc_w || 4972 4949 old_plane_state->crtc_h != new_plane_state->crtc_h); 4973 4950 4974 - DRM_DEBUG_DRIVER("[PLANE:%d] PSR bb_changed:%d fb_changed:%d num_clips:%d\n", 4975 - new_plane_state->plane->base.id, 4976 - bb_changed, fb_changed, num_clips); 4951 + drm_dbg(plane->dev, 4952 + "[PLANE:%d] PSR bb_changed:%d fb_changed:%d num_clips:%d\n", 4953 + new_plane_state->plane->base.id, 4954 + bb_changed, fb_changed, num_clips); 4977 4955 4978 - if (num_clips || fb_changed || bb_changed) { 4979 - dirty_rects[i].x = new_plane_state->crtc_x; 4980 - dirty_rects[i].y = new_plane_state->crtc_y; 4981 - dirty_rects[i].width = new_plane_state->crtc_w; 4982 - dirty_rects[i].height = new_plane_state->crtc_h; 4983 - DRM_DEBUG_DRIVER("[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)\n", 4984 - new_plane_state->plane->base.id, 4985 - dirty_rects[i].x, dirty_rects[i].y, 4986 - dirty_rects[i].width, dirty_rects[i].height); 4987 - i += 1; 4988 - } 4989 - 4990 - /* Add old plane bounding-box if plane is moved or resized */ 4991 4956 if (bb_changed) { 4992 - dirty_rects[i].x = old_plane_state->crtc_x; 4993 - dirty_rects[i].y = old_plane_state->crtc_y; 4994 - dirty_rects[i].width = old_plane_state->crtc_w; 4995 - dirty_rects[i].height = old_plane_state->crtc_h; 4996 - DRM_DEBUG_DRIVER("[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)\n", 4997 - old_plane_state->plane->base.id, 4998 - dirty_rects[i].x, dirty_rects[i].y, 4999 - dirty_rects[i].width, dirty_rects[i].height); 5000 - i += 1; 4957 + fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i], 4958 + new_plane_state->crtc_x, 4959 + new_plane_state->crtc_y, 4960 + new_plane_state->crtc_w, 4961 + new_plane_state->crtc_h, &i, false); 4962 + 4963 + /* Add old plane bounding-box if plane is moved or resized */ 4964 + fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i], 4965 + old_plane_state->crtc_x, 4966 + old_plane_state->crtc_y, 4967 + old_plane_state->crtc_w, 4968 + old_plane_state->crtc_h, &i, false); 5001 4969 } 4970 + 4971 + if (num_clips) { 4972 + for (; i < num_clips; clips++) 4973 + fill_dc_dirty_rect(new_plane_state->plane, 4974 + &dirty_rects[i], clips->x1, 4975 + clips->y1, clips->x2 - clips->x1, 4976 + clips->y2 - clips->y1, &i, false); 4977 + } else if (fb_changed && !bb_changed) { 4978 + fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i], 4979 + new_plane_state->crtc_x, 4980 + new_plane_state->crtc_y, 4981 + new_plane_state->crtc_w, 4982 + new_plane_state->crtc_h, &i, false); 4983 + } 4984 + 4985 + if (i > DC_MAX_DIRTY_RECTS) 4986 + goto ffu; 5002 4987 5003 4988 flip_addrs->dirty_rect_count = i; 4989 + return; 4990 + 4991 + ffu: 4992 + fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[0], 0, 0, 4993 + dm_crtc_state->base.mode.crtc_hdisplay, 4994 + dm_crtc_state->base.mode.crtc_vdisplay, 4995 + &flip_addrs->dirty_rect_count, true); 5004 4996 } 5005 4997 5006 4998 static void update_stream_scaling_settings(const struct drm_display_mode *mode,
+4
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
··· 1600 1600 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, 1601 1601 supported_rotations); 1602 1602 1603 + if (dm->adev->ip_versions[DCE_HWIP][0] > IP_VERSION(3, 0, 1) && 1604 + plane->type != DRM_PLANE_TYPE_CURSOR) 1605 + drm_plane_enable_fb_damage_clips(plane); 1606 + 1603 1607 drm_plane_helper_add(plane, &dm_plane_helper_funcs); 1604 1608 1605 1609 #ifdef CONFIG_DRM_AMD_DC_HDR