From: Michel Dänzer michel.daenzer@amd.com
The cursor_set2 hook provides the cursor hotspot position within the cursor image. When the hotspot position changes, we can adjust the cursor position such that the hotspot doesn't move on the screen. This prevents the cursor from appearing to intermittently jump around on the screen when the position of the hotspot within the cursor image changes.
Reviewed-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Michel Dänzer michel.daenzer@amd.com --- drivers/gpu/drm/radeon/radeon_cursor.c | 51 ++++++++++++++++++++++++++------- drivers/gpu/drm/radeon/radeon_display.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 16 +++++++---- 3 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 9630e8d..fd4bddf 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -117,8 +117,10 @@ static void radeon_show_cursor(struct drm_crtc *crtc) } }
+static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y); + static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, - uint64_t gpu_addr) + uint64_t gpu_addr, int hot_x, int hot_y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -142,13 +144,28 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, /* offset is from DISP(2)_BASE_ADDRESS */ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); } + + if (hot_x != radeon_crtc->cursor_hot_x || + hot_y != radeon_crtc->cursor_hot_y) { + int x, y; + + x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x; + y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y; + + radeon_cursor_move_locked(crtc, x, y); + + radeon_crtc->cursor_hot_x = hot_x; + radeon_crtc->cursor_hot_y = hot_y; + } }
-int radeon_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +int radeon_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -192,7 +209,7 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, radeon_crtc->cursor_height = height;
radeon_lock_cursor(crtc, true); - radeon_set_cursor(crtc, obj, gpu_addr); + radeon_set_cursor(crtc, obj, gpu_addr, hot_x, hot_y); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false);
@@ -215,8 +232,7 @@ fail: return ret; }
-int radeon_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) +static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -281,7 +297,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, } }
- radeon_lock_cursor(crtc, true); if (ASIC_IS_DCE4(rdev)) { WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); @@ -308,7 +323,21 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + (yorigin * 256))); } - radeon_lock_cursor(crtc, false); + + radeon_crtc->cursor_x = x; + radeon_crtc->cursor_y = y;
return 0; } + +int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + radeon_lock_cursor(crtc, true); + ret = radeon_cursor_move_locked(crtc, x, y); + radeon_lock_cursor(crtc, false); + + return ret; +} diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 00ead8c..b233dcd 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -634,7 +634,7 @@ radeon_crtc_set_config(struct drm_mode_set *set) return ret; } static const struct drm_crtc_funcs radeon_crtc_funcs = { - .cursor_set = radeon_crtc_cursor_set, + .cursor_set2 = radeon_crtc_cursor_set2, .cursor_move = radeon_crtc_cursor_move, .gamma_set = radeon_crtc_gamma_set, .set_config = radeon_crtc_set_config, diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 04db2fd..de1b0d6 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -321,6 +321,10 @@ struct radeon_crtc { uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr; + int cursor_x; + int cursor_y; + int cursor_hot_x; + int cursor_hot_y; int cursor_width; int cursor_height; int max_cursor_width; @@ -802,11 +806,13 @@ extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, int atomic); -extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height); +extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y); extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
From: Michel Dänzer michel.daenzer@amd.com
No functional change.
Signed-off-by: Michel Dänzer michel.daenzer@amd.com --- drivers/gpu/drm/radeon/radeon_cursor.c | 220 ++++++++++++++++----------------- 1 file changed, 109 insertions(+), 111 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index fd4bddf..85f38ee 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -117,7 +117,115 @@ static void radeon_show_cursor(struct drm_crtc *crtc) } }
-static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y); +static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + int xorigin = 0, yorigin = 0; + int w = radeon_crtc->cursor_width; + + if (ASIC_IS_AVIVO(rdev)) { + /* avivo cursor are offset into the total surface */ + x += crtc->x; + y += crtc->y; + } + DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); + + if (x < 0) { + xorigin = min(-x, radeon_crtc->max_cursor_width - 1); + x = 0; + } + if (y < 0) { + yorigin = min(-y, radeon_crtc->max_cursor_height - 1); + y = 0; + } + + /* fixed on DCE6 and newer */ + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { + int i = 0; + struct drm_crtc *crtc_p; + + /* + * avivo cursor image can't end on 128 pixel boundary or + * go past the end of the frame if both crtcs are enabled + * + * NOTE: It is safe to access crtc->enabled of other crtcs + * without holding either the mode_config lock or the other + * crtc's lock as long as write access to this flag _always_ + * grabs all locks. + */ + list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { + if (crtc_p->enabled) + i++; + } + if (i > 1) { + int cursor_end, frame_end; + + cursor_end = x - xorigin + w; + frame_end = crtc->x + crtc->mode.crtc_hdisplay; + if (cursor_end >= frame_end) { + w = w - (cursor_end - frame_end); + if (!(frame_end & 0x7f)) + w--; + } else { + if (!(cursor_end & 0x7f)) + w--; + } + if (w <= 0) { + w = 1; + cursor_end = x - xorigin + w; + if (!(cursor_end & 0x7f)) { + x--; + WARN_ON_ONCE(x < 0); + } + } + } + } + + if (ASIC_IS_DCE4(rdev)) { + WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); + WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, + ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); + } else if (ASIC_IS_AVIVO(rdev)) { + WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); + WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, + ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); + } else { + if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) + y *= 2; + + WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, + (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, + (RADEON_CUR_LOCK + | (x << 16) + | y)); + /* offset is from DISP(2)_BASE_ADDRESS */ + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + + (yorigin * 256))); + } + + radeon_crtc->cursor_x = x; + radeon_crtc->cursor_y = y; + + return 0; +} + +int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + radeon_lock_cursor(crtc, true); + ret = radeon_cursor_move_locked(crtc, x, y); + radeon_lock_cursor(crtc, false); + + return ret; +}
static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, uint64_t gpu_addr, int hot_x, int hot_y) @@ -231,113 +339,3 @@ fail:
return ret; } - -static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_device *rdev = crtc->dev->dev_private; - int xorigin = 0, yorigin = 0; - int w = radeon_crtc->cursor_width; - - if (ASIC_IS_AVIVO(rdev)) { - /* avivo cursor are offset into the total surface */ - x += crtc->x; - y += crtc->y; - } - DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); - - if (x < 0) { - xorigin = min(-x, radeon_crtc->max_cursor_width - 1); - x = 0; - } - if (y < 0) { - yorigin = min(-y, radeon_crtc->max_cursor_height - 1); - y = 0; - } - - /* fixed on DCE6 and newer */ - if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { - int i = 0; - struct drm_crtc *crtc_p; - - /* - * avivo cursor image can't end on 128 pixel boundary or - * go past the end of the frame if both crtcs are enabled - * - * NOTE: It is safe to access crtc->enabled of other crtcs - * without holding either the mode_config lock or the other - * crtc's lock as long as write access to this flag _always_ - * grabs all locks. - */ - list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { - if (crtc_p->enabled) - i++; - } - if (i > 1) { - int cursor_end, frame_end; - - cursor_end = x - xorigin + w; - frame_end = crtc->x + crtc->mode.crtc_hdisplay; - if (cursor_end >= frame_end) { - w = w - (cursor_end - frame_end); - if (!(frame_end & 0x7f)) - w--; - } else { - if (!(cursor_end & 0x7f)) - w--; - } - if (w <= 0) { - w = 1; - cursor_end = x - xorigin + w; - if (!(cursor_end & 0x7f)) { - x--; - WARN_ON_ONCE(x < 0); - } - } - } - } - - if (ASIC_IS_DCE4(rdev)) { - WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); - WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); - WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, - ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); - } else if (ASIC_IS_AVIVO(rdev)) { - WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); - WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); - WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, - ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); - } else { - if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) - y *= 2; - - WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, - (RADEON_CUR_LOCK - | (xorigin << 16) - | yorigin)); - WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, - (RADEON_CUR_LOCK - | (x << 16) - | y)); - /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + - (yorigin * 256))); - } - - radeon_crtc->cursor_x = x; - radeon_crtc->cursor_y = y; - - return 0; -} - -int radeon_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) -{ - int ret; - - radeon_lock_cursor(crtc, true); - ret = radeon_cursor_move_locked(crtc, x, y); - radeon_lock_cursor(crtc, false); - - return ret; -}
On Tue, Nov 18, 2014 at 4:00 AM, Michel Dänzer michel@daenzer.net wrote:
From: Michel Dänzer michel.daenzer@amd.com
The cursor_set2 hook provides the cursor hotspot position within the cursor image. When the hotspot position changes, we can adjust the cursor position such that the hotspot doesn't move on the screen. This prevents the cursor from appearing to intermittently jump around on the screen when the position of the hotspot within the cursor image changes.
Reviewed-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Michel Dänzer michel.daenzer@amd.com
Series applied to my -next tree.
Thanks!
Alex
drivers/gpu/drm/radeon/radeon_cursor.c | 51 ++++++++++++++++++++++++++------- drivers/gpu/drm/radeon/radeon_display.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 16 +++++++---- 3 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 9630e8d..fd4bddf 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -117,8 +117,10 @@ static void radeon_show_cursor(struct drm_crtc *crtc) } }
+static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y);
static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
uint64_t gpu_addr)
uint64_t gpu_addr, int hot_x, int hot_y)
{ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -142,13 +144,28 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, /* offset is from DISP(2)_BASE_ADDRESS */ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); }
if (hot_x != radeon_crtc->cursor_hot_x ||
hot_y != radeon_crtc->cursor_hot_y) {
int x, y;
x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
radeon_cursor_move_locked(crtc, x, y);
radeon_crtc->cursor_hot_x = hot_x;
radeon_crtc->cursor_hot_y = hot_y;
}
}
-int radeon_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
uint32_t width,
uint32_t height)
+int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
uint32_t width,
uint32_t height,
int32_t hot_x,
int32_t hot_y)
{ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -192,7 +209,7 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, radeon_crtc->cursor_height = height;
radeon_lock_cursor(crtc, true);
radeon_set_cursor(crtc, obj, gpu_addr);
radeon_set_cursor(crtc, obj, gpu_addr, hot_x, hot_y); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false);
@@ -215,8 +232,7 @@ fail: return ret; }
-int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y)
+static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -281,7 +297,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, } }
radeon_lock_cursor(crtc, true); if (ASIC_IS_DCE4(rdev)) { WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
@@ -308,7 +323,21 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + (yorigin * 256))); }
radeon_lock_cursor(crtc, false);
radeon_crtc->cursor_x = x;
radeon_crtc->cursor_y = y; return 0;
}
+int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y)
+{
int ret;
radeon_lock_cursor(crtc, true);
ret = radeon_cursor_move_locked(crtc, x, y);
radeon_lock_cursor(crtc, false);
return ret;
+} diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 00ead8c..b233dcd 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -634,7 +634,7 @@ radeon_crtc_set_config(struct drm_mode_set *set) return ret; } static const struct drm_crtc_funcs radeon_crtc_funcs = {
.cursor_set = radeon_crtc_cursor_set,
.cursor_set2 = radeon_crtc_cursor_set2, .cursor_move = radeon_crtc_cursor_move, .gamma_set = radeon_crtc_gamma_set, .set_config = radeon_crtc_set_config,
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 04db2fd..de1b0d6 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -321,6 +321,10 @@ struct radeon_crtc { uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr;
int cursor_x;
int cursor_y;
int cursor_hot_x;
int cursor_hot_y; int cursor_width; int cursor_height; int max_cursor_width;
@@ -802,11 +806,13 @@ extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, int atomic); -extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
uint32_t width,
uint32_t height);
+extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
uint32_t width,
uint32_t height,
int32_t hot_x,
int32_t hot_y);
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
-- 2.1.3
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
dri-devel@lists.freedesktop.org