Hi On Thu, Mar 5, 2015 at 3:26 AM, Haixia Shi <hshi@xxxxxxxxxxxx> wrote: > Signed-off-by: Haixia Shi <hshi@xxxxxxxxxxxx> > Reviewed-by: Stéphane Marchesin <marcheu@xxxxxxxxxxxx> > Tested-by: Haixia Shi <hshi@xxxxxxxxxxxx> > --- > drivers/gpu/drm/udl/Makefile | 2 +- > drivers/gpu/drm/udl/udl_cursor.c | 156 +++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/udl/udl_cursor.h | 46 +++++++++++ > drivers/gpu/drm/udl/udl_drv.h | 4 + > drivers/gpu/drm/udl/udl_fb.c | 31 ++++---- > drivers/gpu/drm/udl/udl_gem.c | 3 + > drivers/gpu/drm/udl/udl_main.c | 10 +++ > drivers/gpu/drm/udl/udl_modeset.c | 45 +++++++++++ > drivers/gpu/drm/udl/udl_transfer.c | 36 ++++++++- > 9 files changed, 317 insertions(+), 16 deletions(-) > create mode 100644 drivers/gpu/drm/udl/udl_cursor.c > create mode 100644 drivers/gpu/drm/udl/udl_cursor.h Why pretend the hw supports cursors if it clearly does not? I don't see why we cannot leave this to user-space (which can apply optimizations for software-only devices, which the kernel cannot). And a commit-message would also be nice. Thanks David > diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile > index 195bcac..67ccab4 100644 > --- a/drivers/gpu/drm/udl/Makefile > +++ b/drivers/gpu/drm/udl/Makefile > @@ -1,6 +1,6 @@ > > ccflags-y := -Iinclude/drm > > -udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o udl_dmabuf.o > +udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o udl_dmabuf.o udl_cursor.o > > obj-$(CONFIG_DRM_UDL) := udl.o > diff --git a/drivers/gpu/drm/udl/udl_cursor.c b/drivers/gpu/drm/udl/udl_cursor.c > new file mode 100644 > index 0000000..3b38ef5 > --- /dev/null > +++ b/drivers/gpu/drm/udl/udl_cursor.c > @@ -0,0 +1,156 @@ > +/* > + * udl_cursor.c > + * > + * Copyright (c) 2015 The Chromium OS Authors > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > + > +#include "udl_cursor.h" > +#include "udl_drv.h" > + > +#define UDL_CURSOR_W 64 > +#define UDL_CURSOR_H 64 > +#define UDL_CURSOR_BUF (UDL_CURSOR_W * UDL_CURSOR_H) > + > +/* > + * UDL drm cursor private structure. > + */ > +struct udl_cursor { > + uint32_t buffer[UDL_CURSOR_BUF]; > + bool enabled; > + int x; > + int y; > +}; > + > +int udl_cursor_alloc(struct udl_cursor **cursor) > +{ > + struct udl_cursor *new_cursor = kzalloc(sizeof(struct udl_cursor), > + GFP_KERNEL); > + if (!new_cursor) > + return -ENOMEM; > + *cursor = new_cursor; > + return 0; > +} > + > +void udl_cursor_free(struct udl_cursor *cursor) > +{ > + BUG_ON(!cursor); > + kfree(cursor); > +} > + > +void udl_cursor_copy(struct udl_cursor *dst, struct udl_cursor *src) > +{ > + memcpy(dst, src, sizeof(struct udl_cursor)); > +} > + > +bool udl_cursor_enabled(struct udl_cursor *cursor) > +{ > + return cursor->enabled; > +} > + > +void udl_cursor_get_hline(struct udl_cursor *cursor, int x, int y, > + struct udl_cursor_hline *hline) > +{ > + if (!cursor || !cursor->enabled || > + x >= cursor->x + UDL_CURSOR_W || > + y < cursor->y || y >= cursor->y + UDL_CURSOR_H) { > + hline->buffer = NULL; > + return; > + } > + > + hline->buffer = &cursor->buffer[UDL_CURSOR_W * (y - cursor->y)]; > + hline->width = UDL_CURSOR_W; > + hline->offset = x - cursor->x; > +} > + > +/* > + * Return pre-computed cursor blend value defined as: > + * R: 5 bits (bit 0:4) > + * G: 6 bits (bit 5:10) > + * B: 5 bits (bit 11:15) > + * A: 7 bits (bit 16:22) > + */ > +static uint32_t cursor_blend_val32(uint32_t pix) > +{ > + /* range of alpha_scaled is 0..64 */ > + uint32_t alpha_scaled = ((pix >> 24) * 65) >> 8; > + return ((pix >> 3) & 0x1f) | > + ((pix >> 5) & 0x7e0) | > + ((pix >> 8) & 0xf800) | > + (alpha_scaled << 16); > +} > + > +static int udl_cursor_download(struct udl_cursor *cursor, > + struct drm_gem_object *obj) > +{ > + struct udl_gem_object *udl_gem_obj = to_udl_bo(obj); > + uint32_t *src_ptr, *dst_ptr; > + size_t i; > + > + int ret = udl_gem_vmap(udl_gem_obj); > + if (ret != 0) { > + DRM_ERROR("failed to vmap cursor\n"); > + return ret; > + } > + > + src_ptr = udl_gem_obj->vmapping; > + dst_ptr = cursor->buffer; > + for (i = 0; i < UDL_CURSOR_BUF; ++i) > + dst_ptr[i] = cursor_blend_val32(le32_to_cpu(src_ptr[i])); > + return 0; > +} > + > +int udl_cursor_set(struct drm_crtc *crtc, struct drm_file *file, > + uint32_t handle, uint32_t width, uint32_t height, > + struct udl_cursor *cursor) > +{ > + if (handle) { > + struct drm_gem_object *obj; > + int err; > + /* Currently we only support 64x64 cursors */ > + if (width != UDL_CURSOR_W || height != UDL_CURSOR_H) { > + DRM_ERROR("we currently only support %dx%d cursors\n", > + UDL_CURSOR_W, UDL_CURSOR_H); > + return -EINVAL; > + } > + obj = drm_gem_object_lookup(crtc->dev, file, handle); > + if (!obj) { > + DRM_ERROR("failed to lookup gem object.\n"); > + return -EINVAL; > + } > + err = udl_cursor_download(cursor, obj); > + drm_gem_object_unreference(obj); > + if (err != 0) { > + DRM_ERROR("failed to copy cursor.\n"); > + return err; > + } > + cursor->enabled = true; > + } else { > + cursor->enabled = false; > + } > + > + return 0; > +} > + > +int udl_cursor_move(struct drm_crtc *crtc, int x, int y, > + struct udl_cursor *cursor) > +{ > + cursor->x = x; > + cursor->y = y; > + return 0; > +} > diff --git a/drivers/gpu/drm/udl/udl_cursor.h b/drivers/gpu/drm/udl/udl_cursor.h > new file mode 100644 > index 0000000..4b83f5b > --- /dev/null > +++ b/drivers/gpu/drm/udl/udl_cursor.h > @@ -0,0 +1,46 @@ > +/* > + * udl_cursor.h > + * > + * Copyright (c) 2015 The Chromium OS Authors > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef _UDL_CURSOR_H_ > +#define _UDL_CURSOR_H_ > + > +#include <linux/module.h> > +#include <drm/drmP.h> > +#include <drm/drm_crtc.h> > + > +struct udl_cursor; > +struct udl_cursor_hline { > + uint32_t *buffer; > + int width; > + int offset; > +}; > + > +extern int udl_cursor_alloc(struct udl_cursor **cursor); > +extern void udl_cursor_free(struct udl_cursor *cursor); > +extern void udl_cursor_copy(struct udl_cursor *dst, struct udl_cursor *src); > +extern bool udl_cursor_enabled(struct udl_cursor *cursor); > +extern void udl_cursor_get_hline(struct udl_cursor *cursor, int x, int y, > + struct udl_cursor_hline *hline); > +extern int udl_cursor_set(struct drm_crtc *crtc, struct drm_file *file, > + uint32_t handle, uint32_t width, uint32_t height, > + struct udl_cursor *cursor); > +extern int udl_cursor_move(struct drm_crtc *crtc, int x, int y, > + struct udl_cursor *cursor); > + > +#endif > diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h > index b1e9fae..9fe4520 100644 > --- a/drivers/gpu/drm/udl/udl_drv.h > +++ b/drivers/gpu/drm/udl/udl_drv.h > @@ -47,6 +47,8 @@ struct urb_list { > }; > > struct udl_fbdev; > +struct udl_cursor; > +struct udl_cursor_hline; > struct udl_flip_queue; > > struct udl_device { > @@ -60,6 +62,7 @@ struct udl_device { > atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */ > > struct udl_fbdev *fbdev; > + struct udl_cursor *cursor; > char mode_buf[1024]; > uint32_t mode_buf_len; > atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */ > @@ -116,6 +119,7 @@ udl_fb_user_fb_create(struct drm_device *dev, > int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, > const char *front, char **urb_buf_ptr, > u32 byte_offset, u32 device_byte_offset, u32 byte_width, > + struct udl_cursor_hline *cursor_hline, > int *ident_ptr, int *sent_ptr); > > int udl_dumb_create(struct drm_file *file_priv, > diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c > index 5fc16ce..a4ccbc1 100644 > --- a/drivers/gpu/drm/udl/udl_fb.c > +++ b/drivers/gpu/drm/udl/udl_fb.c > @@ -19,6 +19,7 @@ > #include <drm/drm_crtc.h> > #include <drm/drm_crtc_helper.h> > #include "udl_drv.h" > +#include "udl_cursor.h" > > #include <drm/drm_fb_helper.h> > > @@ -116,8 +117,8 @@ static void udlfb_dpy_deferred_io(struct fb_info *info, > if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8), > &urb, (char *) info->fix.smem_start, > &cmd, cur->index << PAGE_SHIFT, > - cur->index << PAGE_SHIFT, > - PAGE_SIZE, &bytes_identical, &bytes_sent)) > + cur->index << PAGE_SHIFT, PAGE_SIZE, NULL, > + &bytes_identical, &bytes_sent)) > goto error; > bytes_rendered += PAGE_SIZE; > } > @@ -156,20 +157,15 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, > int x2, y2; > bool store_for_later = false; > unsigned long flags; > + struct udl_cursor *cursor_copy = NULL; > > if (!fb->active_16) > return 0; > > - if (!fb->obj->vmapping) { > - ret = udl_gem_vmap(fb->obj); > - if (ret == -ENOMEM) { > - DRM_ERROR("failed to vmap fb\n"); > - return 0; > - } > - if (!fb->obj->vmapping) { > - DRM_ERROR("failed to vmapping\n"); > - return 0; > - } > + ret = udl_gem_vmap(fb->obj); > + if (ret) { > + DRM_ERROR("failed to vmap fb\n"); > + return 0; > } > > aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); > @@ -220,14 +216,21 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, > return 0; > cmd = urb->transfer_buffer; > > + mutex_lock(&dev->struct_mutex); > + if (udl_cursor_alloc(&cursor_copy) == 0) > + udl_cursor_copy(cursor_copy, udl->cursor); > + mutex_unlock(&dev->struct_mutex); > + > for (i = y; i <= y2 ; i++) { > const int line_offset = fb->base.pitches[0] * i; > const int byte_offset = line_offset + (x * bpp); > const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); > + struct udl_cursor_hline cursor_hline; > + udl_cursor_get_hline(cursor_copy, x, i, &cursor_hline); > if (udl_render_hline(dev, bpp, &urb, > (char *) fb->obj->vmapping, > &cmd, byte_offset, dev_byte_offset, > - (x2 - x + 1) * bpp, > + (x2 - x + 1) * bpp, &cursor_hline, > &bytes_identical, &bytes_sent)) > goto error; > } > @@ -241,6 +244,8 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, > udl_urb_completion(urb); > > error: > + if (cursor_copy) > + udl_cursor_free(cursor_copy); > atomic_add(bytes_sent, &udl->bytes_sent); > atomic_add(bytes_identical, &udl->bytes_identical); > atomic_add(width*height*bpp, &udl->bytes_rendered); > diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c > index 2a0a784..9d950ae 100644 > --- a/drivers/gpu/drm/udl/udl_gem.c > +++ b/drivers/gpu/drm/udl/udl_gem.c > @@ -160,6 +160,9 @@ int udl_gem_vmap(struct udl_gem_object *obj) > int page_count = obj->base.size / PAGE_SIZE; > int ret; > > + if (obj->vmapping) > + return 0; > + > if (obj->base.import_attach) { > obj->vmapping = dma_buf_vmap(obj->base.import_attach->dmabuf); > if (!obj->vmapping) > diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c > index 33dbfb2..1f86779 100644 > --- a/drivers/gpu/drm/udl/udl_main.c > +++ b/drivers/gpu/drm/udl/udl_main.c > @@ -12,6 +12,7 @@ > */ > #include <drm/drmP.h> > #include "udl_drv.h" > +#include "udl_cursor.h" > > /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */ > #define BULK_SIZE 512 > @@ -307,6 +308,10 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) > } > > DRM_DEBUG("\n"); > + ret = udl_cursor_alloc(&udl->cursor); > + if (ret) > + goto err; > + > ret = udl_modeset_init(dev); > if (ret) > goto err; > @@ -325,6 +330,8 @@ err_fb: > err: > if (udl->urbs.count) > udl_free_urb_list(dev); > + if (udl->cursor) > + udl_cursor_free(udl->cursor); > kfree(udl); > DRM_ERROR("%d\n", ret); > return ret; > @@ -345,6 +352,9 @@ int udl_driver_unload(struct drm_device *dev) > if (udl->urbs.count) > udl_free_urb_list(dev); > > + if (udl->cursor) > + udl_cursor_free(udl->cursor); > + > udl_fbdev_cleanup(dev); > udl_modeset_cleanup(dev); > kfree(udl); > diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c > index f3804b4..d464286 100644 > --- a/drivers/gpu/drm/udl/udl_modeset.c > +++ b/drivers/gpu/drm/udl/udl_modeset.c > @@ -16,6 +16,7 @@ > #include <drm/drm_crtc_helper.h> > #include <drm/drm_plane_helper.h> > #include "udl_drv.h" > +#include "udl_cursor.h" > > /* > * All DisplayLink bulk operations start with 0xAF, followed by specific code > @@ -471,6 +472,48 @@ static void udl_crtc_commit(struct drm_crtc *crtc) > udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON); > } > > +static int udl_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file, > + uint32_t handle, uint32_t width, uint32_t height) > +{ > + struct drm_device *dev = crtc->dev; > + struct udl_device *udl = dev->dev_private; > + int ret; > + > + mutex_lock(&dev->struct_mutex); > + ret = udl_cursor_set(crtc, file, handle, width, height, udl->cursor); > + mutex_unlock(&dev->struct_mutex); > + > + if (ret) { > + DRM_ERROR("Failed to set UDL cursor\n"); > + return ret; > + } > + > + return udl_crtc_page_flip(crtc, NULL, NULL, 0); > +} > + > +static int udl_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) > +{ > + struct drm_device *dev = crtc->dev; > + struct udl_device *udl = dev->dev_private; > + int ret = 0; > + > + mutex_lock(&dev->struct_mutex); > + if (!udl_cursor_enabled(udl->cursor)) > + goto error; > + ret = udl_cursor_move(crtc, x, y, udl->cursor); > + if (ret) { > + DRM_ERROR("Failed to move UDL cursor\n"); > + goto error; > + } > + mutex_unlock(&dev->struct_mutex); > + > + return udl_crtc_page_flip(crtc, NULL, NULL, 0); > + > +error: > + mutex_unlock(&dev->struct_mutex); > + return ret; > +} > + > static struct drm_crtc_helper_funcs udl_helper_funcs = { > .dpms = udl_crtc_dpms, > .mode_fixup = udl_crtc_mode_fixup, > @@ -484,6 +527,8 @@ static const struct drm_crtc_funcs udl_crtc_funcs = { > .set_config = drm_crtc_helper_set_config, > .destroy = udl_crtc_destroy, > .page_flip = udl_crtc_page_flip, > + .cursor_set = udl_crtc_cursor_set, > + .cursor_move = udl_crtc_cursor_move, > }; > > static int udl_crtc_init(struct drm_device *dev) > diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c > index 917dcb9..2f59603 100644 > --- a/drivers/gpu/drm/udl/udl_transfer.c > +++ b/drivers/gpu/drm/udl/udl_transfer.c > @@ -17,6 +17,7 @@ > > #include <drm/drmP.h> > #include "udl_drv.h" > +#include "udl_cursor.h" > > #define MAX_CMD_PIXELS 255 > > @@ -92,6 +93,19 @@ static inline u16 get_pixel_val16(const uint8_t *pixel, int bpp) > return pixel_val16; > } > > +static inline u16 blend_alpha(const uint16_t pixel_val16, uint32_t blend_val32) > +{ > + uint32_t alpha = (blend_val32 >> 16); > + uint32_t alpha_inv = 64 - alpha; > + > + return (((pixel_val16 & 0x1f) * alpha_inv + > + (blend_val32 & 0x1f) * alpha) >> 6) | > + ((((pixel_val16 & 0x7e0) * alpha_inv + > + (blend_val32 & 0x7e0) * alpha) >> 6) & 0x7e0) | > + ((((pixel_val16 & 0xf800) * alpha_inv + > + (blend_val32 & 0xf800) * alpha) >> 6) & 0xf800); > +} > + > /* > * Render a command stream for an encoded horizontal line segment of pixels. > * > @@ -123,12 +137,16 @@ static void udl_compress_hline16( > const u8 **pixel_start_ptr, > const u8 *const pixel_end, > uint32_t *device_address_ptr, > + struct udl_cursor_hline *cursor_hline, > uint8_t **command_buffer_ptr, > const uint8_t *const cmd_buffer_end, int bpp) > { > const u8 *pixel = *pixel_start_ptr; > uint32_t dev_addr = *device_address_ptr; > uint8_t *cmd = *command_buffer_ptr; > + const uint32_t *cursor_buf = cursor_hline ? cursor_hline->buffer : NULL; > + int cursor_pos = cursor_buf ? cursor_hline->offset : 0; > + int cursor_width = cursor_buf ? cursor_hline->width : 0; > > while ((pixel_end > pixel) && > (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) { > @@ -158,6 +176,11 @@ static void udl_compress_hline16( > > prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); > pixel_val16 = get_pixel_val16(pixel, bpp); > + if (cursor_buf && cursor_pos >= 0 && > + cursor_pos < cursor_width) { > + pixel_val16 = blend_alpha(pixel_val16, > + cursor_buf[cursor_pos]); > + } > > while (pixel < cmd_pixel_end) { > const u8 *const start = pixel; > @@ -167,12 +190,19 @@ static void udl_compress_hline16( > > cmd += 2; > pixel += bpp; > + cursor_pos++; > > while (pixel < cmd_pixel_end) { > pixel_val16 = get_pixel_val16(pixel, bpp); > + if (cursor_buf && cursor_pos >= 0 && > + cursor_pos < cursor_width) { > + pixel_val16 = blend_alpha(pixel_val16, > + cursor_buf[cursor_pos]); > + } > if (pixel_val16 != repeating_pixel_val16) > break; > pixel += bpp; > + cursor_pos++; > } > > if (unlikely(pixel > start + bpp)) { > @@ -208,6 +238,8 @@ static void udl_compress_hline16( > *command_buffer_ptr = cmd; > *pixel_start_ptr = pixel; > *device_address_ptr = dev_addr; > + if (cursor_buf) > + cursor_hline->offset = cursor_pos; > > return; > } > @@ -221,7 +253,7 @@ static void udl_compress_hline16( > int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, > const char *front, char **urb_buf_ptr, > u32 byte_offset, u32 device_byte_offset, > - u32 byte_width, > + u32 byte_width, struct udl_cursor_hline *cursor_hline, > int *ident_ptr, int *sent_ptr) > { > const u8 *line_start, *line_end, *next_pixel; > @@ -239,7 +271,7 @@ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, > while (next_pixel < line_end) { > > udl_compress_hline16(&next_pixel, > - line_end, &base16, > + line_end, &base16, cursor_hline, > (u8 **) &cmd, (u8 *) cmd_end, bpp); > > if (cmd >= cmd_end) { > -- > 2.2.0.rc0.207.ga3a616c > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel