Skip to content

Commit

Permalink
Add cursor compositing
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianPasin committed Feb 25, 2016
1 parent 9536b79 commit c5fbd15
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 39 deletions.
6 changes: 5 additions & 1 deletion module/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#
# Copyright (c) 2015 DisplayLink (UK) Ltd.
# Copyright (c) 2015 - 2016 DisplayLink (UK) Ltd.
#
# This file is subject to the terms and conditions of the GNU General Public
# License v2. See the file COPYING in the main directory of this archive for
# more details.
#

config DRM_EVDI
Expand Down
19 changes: 13 additions & 6 deletions module/Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#
# Copyright (c) 2015 DisplayLink (UK) Ltd.
# Copyright (c) 2015 - 2016 DisplayLink (UK) Ltd.
#
# This file is subject to the terms and conditions of the GNU General Public
# License v2. See the file COPYING in the main directory of this archive for
# more details.
#

ifneq ($(DKMS_BUILD),)

# DKMS

KERN_DIR := /lib/modules/$(KERNELRELEASE)/build

ccflags-y := -Iinclude/drm
evdi-y := evdi_drv.o evdi_modeset.o evdi_connector.o evdi_encoder.o evdi_main.o evdi_fb.o evdi_gem.o evdi_stats.o evdi_painter.o evdi_debug.o
evdi-y := evdi_drv.o evdi_modeset.o evdi_connector.o evdi_encoder.o evdi_main.o evdi_fb.o evdi_gem.o evdi_stats.o evdi_painter.o evdi_debug.o evdi_cursor.o
obj-m := evdi.o

KBUILD_VERBOSE ?= 1
Expand All @@ -31,13 +34,17 @@ ifneq ($(KERNELRELEASE),)
# Note: this can be removed once it is in kernel tree and Kconfig is properly used
CONFIG_DRM_EVDI := m
ccflags-y := -Iinclude/drm
evdi-y := evdi_drv.o evdi_modeset.o evdi_connector.o evdi_encoder.o evdi_main.o evdi_fb.o evdi_gem.o evdi_stats.o evdi_painter.o evdi_debug.o
evdi-y := evdi_drv.o evdi_modeset.o evdi_connector.o evdi_encoder.o evdi_main.o evdi_fb.o evdi_gem.o evdi_stats.o evdi_painter.o evdi_debug.o evdi_cursor.o
obj-$(CONFIG_DRM_EVDI) := evdi.o

else

# kbuild against current kernel
KDIR := /lib/modules/$(shell uname -r)/build
# kbuild against specified or current kernel
ifeq ($(KVER),)
KVER := $(shell uname -r)
endif

KDIR := /lib/modules/$(KVER)/build
CFLAGS := -std=c99 -g -fPIC

default: module
Expand Down
215 changes: 215 additions & 0 deletions module/evdi_cursor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* evdi_cursor.c
*
* Copyright (c) 2016 The Chromium OS Authors
* Copyright (c) 2016 DisplayLink (UK) Ltd.
*
* Based on parts on udlfb.c:
* Copyright (C) 2009 its respective authors
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file COPYING in the main directory of this archive for
* more details.
*/

#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <linux/compiler.h>

#include "evdi_cursor.h"
#include "evdi_drv.h"

#define EVDI_CURSOR_W 64
#define EVDI_CURSOR_H 64
#define EVDI_CURSOR_BUF (EVDI_CURSOR_W * EVDI_CURSOR_H)

/*
* EVDI drm cursor private structure.
*/
struct evdi_cursor {
uint32_t buffer[EVDI_CURSOR_BUF];
bool enabled;
int x;
int y;
};

int evdi_cursor_alloc(struct evdi_cursor **cursor)
{
struct evdi_cursor *new_cursor = kzalloc(sizeof(struct evdi_cursor),
GFP_KERNEL);
if (!new_cursor)
return -ENOMEM;
*cursor = new_cursor;
return 0;
}

void evdi_cursor_free(struct evdi_cursor *cursor)
{
BUG_ON(!cursor);
kfree(cursor);
}

void evdi_cursor_copy(struct evdi_cursor *dst, struct evdi_cursor *src)
{
memcpy(dst, src, sizeof(struct evdi_cursor));
}

bool evdi_cursor_enabled(struct evdi_cursor *cursor)
{
return cursor->enabled;
}

static int evdi_cursor_download(struct evdi_cursor *cursor,
struct drm_gem_object *obj)
{
struct evdi_gem_object *evdi_gem_obj = to_evdi_bo(obj);
uint32_t *src_ptr, *dst_ptr;
size_t i;
int ret = evdi_gem_vmap(evdi_gem_obj);

if (ret != 0) {
DRM_ERROR("failed to vmap cursor\n");
return ret;
}

src_ptr = evdi_gem_obj->vmapping;
dst_ptr = cursor->buffer;
for (i = 0; i < EVDI_CURSOR_BUF; ++i)
dst_ptr[i] = le32_to_cpu(src_ptr[i]);
return 0;
}

int evdi_cursor_set(struct drm_crtc *crtc, struct drm_file *file,
uint32_t handle, uint32_t width, uint32_t height,
struct evdi_cursor *cursor)
{
if (handle) {
struct drm_gem_object *obj;
int err;
/* Currently we only support 64x64 cursors */
if (width != EVDI_CURSOR_W || height != EVDI_CURSOR_H) {
DRM_ERROR("we currently only support %dx%d cursors\n",
EVDI_CURSOR_W, EVDI_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 = evdi_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 evdi_cursor_move(struct drm_crtc *crtc, int x, int y,
struct evdi_cursor *cursor)
{
cursor->x = x;
cursor->y = y;
return 0;
}

static inline uint32_t blend_component(uint32_t pixel,
uint32_t blend,
uint32_t alpha)
{
uint32_t pre_blend = (pixel * (255 - alpha) + blend * alpha);

return (pre_blend + ((pre_blend + 1) << 8)) >> 16;
}

static inline uint32_t blend_alpha(const uint32_t pixel_val32,
uint32_t blend_val32)
{
uint32_t alpha = (blend_val32 >> 24);

return blend_component(pixel_val32 & 0xff,
blend_val32 & 0xff, alpha) |
blend_component((pixel_val32 & 0xff00) >> 8,
(blend_val32 & 0xff00) >> 8, alpha) << 8 |
blend_component((pixel_val32 & 0xff0000) >> 16,
(blend_val32 & 0xff0000) >> 16, alpha) << 16;
}

int evdi_cursor_composing_pixel(char __user *buffer,
int const cursor_value,
int const fb_value,
int cmd_offset)
{
int const composed_value = blend_alpha(fb_value, cursor_value);
int __always_unused unused =
copy_to_user(buffer + cmd_offset, &composed_value, 4);

return 0;
}

int evdi_cursor_composing_and_copy(struct evdi_cursor *cursor,
struct evdi_framebuffer *ufb,
char __user *buffer,
int buf_byte_stride,
int const max_x,
int const max_y)
{
int x, y;
struct drm_framebuffer *fb = &ufb->base;
int h_cursor_w = EVDI_CURSOR_W >> 1;
int h_cursor_h = EVDI_CURSOR_H >> 1;

for (y = -EVDI_CURSOR_H/2; y < EVDI_CURSOR_H/2; ++y) {
for (x = -EVDI_CURSOR_W/2; x < EVDI_CURSOR_W/2; ++x) {
uint32_t curs_val;
int *fbsrc;
int fb_value;
int cmd_offset;
int cursor_pix;
int const mouse_pix_x = cursor->x + x + h_cursor_w;
int const mouse_pix_y = cursor->y + y + h_cursor_h;
bool const is_pix_sane =
mouse_pix_x >= 0 &&
mouse_pix_y >= 0 &&
mouse_pix_x < fb->width &&
mouse_pix_y < fb->height &&
cursor &&
cursor->enabled;

if (!is_pix_sane)
continue;

cursor_pix = h_cursor_w+x +
(h_cursor_h+y)*EVDI_CURSOR_W;
if (cursor_pix < 0 ||
cursor_pix > EVDI_CURSOR_BUF-1) {
EVDI_WARN("cursor %d,%d\n", x, y);
continue;
}
curs_val = cursor->buffer[cursor_pix];
fbsrc = (int *)ufb->obj->vmapping;
fb_value = *(fbsrc + ((fb->pitches[0]>>2) *
mouse_pix_y + mouse_pix_x));
cmd_offset = (buf_byte_stride * mouse_pix_y) +
(mouse_pix_x * 4);
evdi_cursor_composing_pixel(buffer,
curs_val,
fb_value,
cmd_offset);
}
}

return 0;
}

void evdi_get_cursor_position(int *x, int *y, struct evdi_cursor *cursor)
{
*x = cursor->x;
*y = cursor->y;
}
53 changes: 53 additions & 0 deletions module/evdi_cursor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* evdi_cursor.h
*
* Copyright (c) 2016 The Chromium OS Authors
* Copyright (c) 2016 DisplayLink (UK) Ltd.
*
* Based on parts on udlfb.c:
* Copyright (C) 2009 its respective authors
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file COPYING in the main directory of this archive for
* more details.
*/

#ifndef _EVDI_CURSOR_H_
#define _EVDI_CURSOR_H_

#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>

struct evdi_cursor;
struct evdi_framebuffer;
struct evdi_cursor_hline {
uint32_t *buffer;
int width;
int offset;
};

extern int evdi_cursor_alloc(struct evdi_cursor **cursor);
extern void evdi_cursor_free(struct evdi_cursor *cursor);
extern void evdi_cursor_copy(struct evdi_cursor *dst, struct evdi_cursor *src);
extern bool evdi_cursor_enabled(struct evdi_cursor *cursor);
extern void evdi_cursor_get_hline(struct evdi_cursor *cursor, int x, int y,
struct evdi_cursor_hline *hline);
extern int evdi_cursor_set(struct drm_crtc *crtc, struct drm_file *file,
uint32_t handle, uint32_t width, uint32_t height,
struct evdi_cursor *cursor);
extern int evdi_cursor_move(struct drm_crtc *crtc, int x, int y,
struct evdi_cursor *cursor);
extern void evdi_get_cursor_position(int *x, int *y,
struct evdi_cursor *cursor);
extern int evdi_cursor_composing_pixel(char *buffer,
int const cursor_value,
int const fb_value,
int cmd_offset);
extern int evdi_cursor_composing_and_copy(struct evdi_cursor *cursor,
struct evdi_framebuffer *ufb,
char __user *buffer,
int buf_byte_stride,
int const max_x,
int const max_y);
#endif
4 changes: 2 additions & 2 deletions module/evdi_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
* more details.
*/

#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "evdi_drv.h"
#include "evdi_drm.h"
#include "evdi_debug.h"
Expand Down
6 changes: 3 additions & 3 deletions module/evdi_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@

#define DRIVER_NAME "evdi"
#define DRIVER_DESC "Extensible Virtual Display Interface"
#define DRIVER_DATE "19700101"
#define DRIVER_DATE "20160225"

#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 68
#define DRIVER_PATCHLEVEL 453

struct evdi_fbdev;
struct evdi_painter;
Expand All @@ -39,7 +39,7 @@ struct evdi_flip_queue;
struct evdi_device {
struct device *dev;
struct drm_device *ddev;

struct evdi_cursor *cursor;
int sku_pixel_limit;

struct evdi_fbdev *fbdev;
Expand Down
Loading

0 comments on commit c5fbd15

Please sign in to comment.