Commit 4d81c99a authored by Keith Packard's avatar Keith Packard

Create driver-independent CRTC-based cursor layer.

This moves most of the cursor management code out of the intel driver and
into the general server code. Of course, the hope is that this code will be
useful for other driver writers as well.

Check out xf86Crtc.h for the usage information, making sure you add the
needed hooks to the crtc funcs structure for your driver.
parent 0ebe5379
......@@ -48,6 +48,7 @@ XORG_LIBS = \
parser/libxf86config.a \
dixmods/libdixmods.la \
modes/libxf86modes.a \
ramdac/libramdac.a \
ddc/libddc.a \
i2c/libi2c.a \
@XORG_LIBS@
......
......@@ -2,7 +2,8 @@ noinst_LIBRARIES = libloader.a
INCLUDES = $(XORG_INCS) -I$(srcdir)/../parser -I$(srcdir)/../dixmods/extmod \
-I$(srcdir)/../vbe -I$(top_srcdir)/miext/cw -I$(srcdir)/../int10 \
-I$(srcdir)/../ddc -I$(srcdir)/../i2c -I$(srcdir)/../modes
-I$(srcdir)/../ddc -I$(srcdir)/../i2c -I$(srcdir)/../modes \
-I$(srcdir)/../ramdac
#AM_LDFLAGS = -r
AM_CFLAGS = -DIN_LOADER $(XORG_CFLAGS)
......
......@@ -841,6 +841,7 @@ DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent)
static const char *compiled_in_modules[] = {
"ddc",
"i2c",
"ramdac",
NULL
};
......@@ -861,7 +862,7 @@ doLoadModule(const char *module, const char *path, const char **subdirlist,
PatternPtr patterns = NULL;
int noncanonical = 0;
char *m = NULL;
char **cim;
const char **cim;
xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module);
......
......@@ -1230,6 +1230,11 @@ _X_HIDDEN void *xfree86LookupTab[] = {
SYMFUNC(xf86RandR12SetConfig)
SYMFUNC(xf86RandR12SetRotations)
#endif
SYMFUNC(xf86_cursors_init)
SYMFUNC(xf86_reload_cursors)
SYMFUNC(xf86_show_cursors)
SYMFUNC(xf86_hide_cursors)
SYMFUNC(xf86_cursors_fini)
SYMFUNC(xf86DoEDID_DDC1)
SYMFUNC(xf86DoEDID_DDC2)
......
......@@ -3,6 +3,7 @@ noinst_LIBRARIES = libxf86modes.a
libxf86modes_a_SOURCES = \
xf86Crtc.c \
xf86Crtc.h \
xf86Cursors.c \
xf86cvt.c \
xf86DiDGA.c \
xf86EdidModes.c \
......@@ -16,7 +17,8 @@ libxf86modes_a_SOURCES = \
INCLUDES = $(XORG_INCS) -I$(srcdir)/../ddc -I$(srcdir)/../i2c \
-I$(srcdir)/../loader -I$(srcdir)/../rac -I$(srcdir)/../parser \
-I$(srcdir)/../scanpci -I$(srcdir)/../vbe -I$(srcdir)/../int10 \
-I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod
-I$(srcdir)/../vgahw -I$(srcdir)/../ramdac \
-I$(srcdir)/../dixmods/extmod
sdk_HEADERS = \
xf86Crtc.h \
......
......@@ -28,6 +28,7 @@
#include "xf86Rename.h"
#endif
#include "xf86Modes.h"
#include "xf86Cursor.h"
#include "damage.h"
/* Compat definitions for older X Servers. */
......@@ -37,6 +38,9 @@
#ifndef M_T_DRIVER
#define M_T_DRIVER 0x40
#endif
#ifndef HARDWARE_CURSOR_ARGB
#define HARDWARE_CURSOR_ARGB 0x00004000
#endif
typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
......@@ -154,6 +158,42 @@ typedef struct _xf86CrtcFuncs {
void
(*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data);
/**
* Set cursor colors
*/
void
(*set_cursor_colors) (xf86CrtcPtr crtc, int bg, int fg);
/**
* Set cursor position
*/
void
(*set_cursor_position) (xf86CrtcPtr crtc, int x, int y);
/**
* Show cursor
*/
void
(*show_cursor) (xf86CrtcPtr crtc);
/**
* Hide cursor
*/
void
(*hide_cursor) (xf86CrtcPtr crtc);
/**
* Load monochrome image
*/
void
(*load_cursor_image) (xf86CrtcPtr crtc, CARD8 *image);
/**
* Load ARGB image
*/
void
(*load_cursor_argb) (xf86CrtcPtr crtc, CARD32 *image);
/**
* Clean up driver-specific bits of the crtc
*/
......@@ -174,12 +214,6 @@ struct _xf86Crtc {
*/
Bool enabled;
/** Track whether cursor is within CRTC range */
Bool cursorInRange;
/** Track state of cursor associated with this CRTC */
Bool cursorShown;
/**
* Active mode
*
......@@ -232,6 +266,19 @@ struct _xf86Crtc {
#else
void *randr_crtc;
#endif
/**
* Current cursor is ARGB
*/
Bool cursor_argb;
/**
* Track whether cursor is within CRTC range
*/
Bool cursor_in_range;
/**
* Track state of cursor associated with this CRTC
*/
Bool cursor_shown;
};
typedef struct _xf86OutputFuncs {
......@@ -495,6 +542,13 @@ typedef struct _xf86CrtcConfig {
const xf86CrtcConfigFuncsRec *funcs;
CreateScreenResourcesProcPtr CreateScreenResources;
/* Cursor information */
xf86CursorInfoPtr cursor_info;
CursorPtr cursor;
CARD8 *cursor_image;
Bool cursor_on;
CARD32 cursor_fg, cursor_bg;
} xf86CrtcConfigRec, *xf86CrtcConfigPtr;
extern int xf86CrtcConfigPrivateIndex;
......@@ -637,4 +691,41 @@ xf86ConnectorGetName(xf86ConnectorType connector);
Bool
xf86SetDesiredModes (ScrnInfoPtr pScrn);
/**
* Initialize the CRTC-based cursor code. CRTC function vectors must
* contain relevant cursor setting functions.
*
* Driver should call this from ScreenInit function
*/
Bool
xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags);
/**
* Called when anything on the screen is reconfigured.
*
* Reloads cursor images as needed, then adjusts cursor positions.
*
* Driver should call this from crtc commit function.
*/
void
xf86_reload_cursors (ScreenPtr screen);
/**
* Called from EnterVT to turn the cursors back on
*/
void
xf86_show_cursors (ScrnInfoPtr scrn);
/**
* Called by the driver to turn cursors off
*/
void
xf86_hide_cursors (ScrnInfoPtr scrn);
/**
* Clean up CRTC-based cursor code. Driver must call this at CloseScreen time.
*/
void
xf86_cursors_fini (ScreenPtr screen);
#endif /* _XF86CRTC_H_ */
/*
* Copyright © 2007 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#endif
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
#include "xf86RandR12.h"
#include "X11/extensions/render.h"
#define DPMS_SERVER
#include "X11/extensions/dpms.h"
#include "X11/Xatom.h"
#ifdef RENDER
#include "picturestr.h"
#endif
#include "cursorstr.h"
/*
* Given a screen coordinate, rotate back to a cursor source coordinate
*/
static void
xf86_crtc_rotate_coord (Rotation rotation,
int width,
int height,
int x_dst,
int y_dst,
int *x_src,
int *y_src)
{
if (rotation & RR_Reflect_X)
x_dst = width - x_dst - 1;
if (rotation & RR_Reflect_Y)
y_dst = height - y_dst - 1;
switch (rotation & 0xf) {
case RR_Rotate_0:
*x_src = x_dst;
*y_src = y_dst;
break;
case RR_Rotate_90:
*x_src = height - y_dst - 1;
*y_src = x_dst;
break;
case RR_Rotate_180:
*x_src = width - x_dst - 1;
*y_src = height - y_dst - 1;
break;
case RR_Rotate_270:
*x_src = y_dst;
*y_src = width - x_dst - 1;
break;
}
}
/*
* Convert an x coordinate to a position within the cursor bitmap
*/
static int
cursor_bitpos (int flags, int x, Bool mask)
{
if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
mask = !mask;
if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
x = (x & ~3) | (3 - (x & 3));
if (flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST)
x = (x & ~7) | (7 - (x & 7));
if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1)
x = (x << 1) + mask;
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8)
x = ((x & ~7) << 1) | (mask << 3) | (x & 7);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16)
x = ((x & ~15) << 1) | (mask << 4) | (x & 15);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32)
x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
return x;
}
/*
* Fetch one bit from a cursor bitmap
*/
static CARD8
get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask)
{
x = cursor_bitpos (flags, x, mask);
image += y * stride;
return (image[(x >> 3)] >> (x & 7)) & 1;
}
/*
* Set one bit in a cursor bitmap
*/
static void
set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask)
{
x = cursor_bitpos (flags, x, mask);
image += y * stride;
image[(x >> 3)] |= 1 << (x & 7);
}
/*
* Load a two color cursor into a driver that supports only ARGB cursors
*/
static void
xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
int x, y;
int xin, yin;
int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags;
CARD32 bits;
#ifdef ARGB_CURSOR
crtc->cursor_argb = FALSE;
#endif
for (y = 0; y < cursor_info->MaxHeight; y++)
for (x = 0; x < cursor_info->MaxWidth; x++)
{
xf86_crtc_rotate_coord (crtc->rotation,
cursor_info->MaxWidth,
cursor_info->MaxHeight,
x, y, &xin, &yin);
if (get_bit (src, stride, flags, xin, yin, TRUE) ==
((flags & HARDWARE_CURSOR_INVERT_MASK) == 0))
{
if (get_bit (src, stride, flags, xin, yin, FALSE))
bits = xf86_config->cursor_fg;
else
bits = xf86_config->cursor_bg;
}
else
bits = 0;
cursor_image[y * cursor_info->MaxWidth + x] = bits;
}
crtc->funcs->load_cursor_argb (crtc, cursor_image);
}
/*
* Set the colors for a two-color cursor (ignore for ARGB cursors)
*/
static void
xf86_set_cursor_colors (ScrnInfoPtr scrn, int bg, int fg)
{
ScreenPtr screen = scrn->pScreen;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
CursorPtr cursor = xf86_config->cursor;
int c;
CARD8 *bits = cursor ? cursor->devPriv[screen->myNum] : NULL;
/* Save ARGB versions of these colors */
xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled && !crtc->cursor_argb)
{
if (crtc->funcs->load_cursor_image)
crtc->funcs->set_cursor_colors (crtc, bg, fg);
else if (bits)
xf86_crtc_convert_cursor_to_argb (crtc, bits);
}
}
}
static void
xf86_crtc_hide_cursor (xf86CrtcPtr crtc)
{
if (crtc->cursor_shown)
{
crtc->funcs->hide_cursor (crtc);
crtc->cursor_shown = FALSE;
}
}
void
xf86_hide_cursors (ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
xf86_config->cursor_on = FALSE;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_hide_cursor (crtc);
}
}
static void
xf86_crtc_show_cursor (xf86CrtcPtr crtc)
{
if (!crtc->cursor_shown && crtc->cursor_in_range)
{
crtc->funcs->show_cursor (crtc);
crtc->cursor_shown = TRUE;
}
}
void
xf86_show_cursors (ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
xf86_config->cursor_on = TRUE;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_show_cursor (crtc);
}
}
static void
xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
DisplayModePtr mode = &crtc->mode;
int x_temp;
int y_temp;
Bool in_range;
/*
* Move to crtc coordinate space
*/
x -= crtc->x;
y -= crtc->y;
/*
* Rotate
*/
switch ((crtc->rotation) & 0xf) {
case RR_Rotate_0:
break;
case RR_Rotate_90:
x_temp = y;
y_temp = mode->VDisplay - cursor_info->MaxWidth - x;
x = x_temp;
y = y_temp;
break;
case RR_Rotate_180:
x_temp = mode->HDisplay - cursor_info->MaxWidth - x;
y_temp = mode->VDisplay - cursor_info->MaxHeight - y;
x = x_temp;
y = y_temp;
break;
case RR_Rotate_270:
x_temp = mode->HDisplay - cursor_info->MaxHeight - y;
y_temp = x;
x = x_temp;
y = y_temp;
break;
}
/*
* Reflect
*/
if (crtc->rotation & RR_Reflect_X)
x = mode->HDisplay - cursor_info->MaxWidth - x;
if (crtc->rotation & RR_Reflect_Y)
y = mode->VDisplay - cursor_info->MaxHeight - y;
/*
* Disable the cursor when it is outside the viewport
*/
in_range = TRUE;
if (x >= mode->HDisplay || y >= mode->VDisplay ||
x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight)
{
in_range = FALSE;
x = 0;
y = 0;
}
crtc->cursor_in_range = in_range;
if (in_range)
{
crtc->funcs->set_cursor_position (crtc, x, y);
xf86_crtc_show_cursor (crtc);
}
else
xf86_crtc_hide_cursor (crtc);
}
static void
xf86_set_cursor_position (ScrnInfoPtr scrn, int x, int y)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
/* undo what xf86HWCurs did to the coordinates */
x += scrn->frameX0;
y += scrn->frameY0;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_set_cursor_position (crtc, x, y);
}
}
/*
* Load a two-color cursor into a crtc, performing rotation as needed
*/
static void
xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
CARD8 *cursor_image;
#ifdef ARGB_CURSOR
crtc->cursor_argb = FALSE;
#endif
if (crtc->rotation == RR_Rotate_0)
cursor_image = src;
else
{
int x, y;
int xin, yin;
int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags;
cursor_image = xf86_config->cursor_image;
memset(cursor_image, 0, cursor_info->MaxWidth * stride);
for (y = 0; y < cursor_info->MaxHeight; y++)
for (x = 0; x < cursor_info->MaxWidth; x++)
{
xf86_crtc_rotate_coord (crtc->rotation,
cursor_info->MaxWidth,
cursor_info->MaxHeight,
x, y, &xin, &yin);
if (get_bit(src, stride, flags, xin, yin, FALSE))
set_bit(cursor_image, stride, flags, x, y, FALSE);
if (get_bit(src, stride, flags, xin, yin, TRUE))
set_bit(cursor_image, stride, flags, x, y, TRUE);
}
}
crtc->funcs->load_cursor_image (crtc, cursor_image);
}
/*
* Load a cursor image into all active CRTCs
*/
static void
xf86_load_cursor_image (ScrnInfoPtr scrn, unsigned char *src)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
{
if (crtc->funcs->load_cursor_image)
xf86_crtc_load_cursor_image (crtc, src);
else if (crtc->funcs->load_cursor_argb)
xf86_crtc_convert_cursor_to_argb (crtc, src);
}
}
}
static Bool
xf86_use_hw_cursor (ScreenPtr screen, CursorPtr cursor)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
xf86_config->cursor = cursor;
if (cursor->bits->width > cursor_info->MaxWidth ||
cursor->bits->height> cursor_info->MaxHeight)
return FALSE;
return TRUE;
}
static Bool
xf86_use_hw_cursor_argb (ScreenPtr screen, CursorPtr cursor)
{