|
From: Antonino D. <ad...@po...> - 2002-09-09 14:20:10
|
Hi, Since Xfbdev is able to rotate the display, I guess it's also reasonable for the console to have the ability to rotate the display too. I have added 3 new flags to var->vmode: FB_VMODE_ROTATE_CW 0x010000 /* 90 degree rotation */ FB_VMODE_ROTATE_CCW 0x020000 /* 270 degree rotation */ FB_VMODE_ROTATE_UD 0x040000 /* 180 degree rotation */ FB_ROTATE_MASK 0xFF0000 Rotating the display is done using console wrappers similar to fbcon-accel. Depending on the rotation flag, dispsw is pointed to the appropriate wrapper in gen_set_disp. As for driver support, the minimum requirement is for the driver to recognize these flags, and set the var->xres, var->yres, var->xres_virtual, and var->yres_virtual fields to the appropriate logical values. Ie, if display is rotated CW or CCW, then logical xres is physical yres, etc. For drivers that support panning, the viewport and direction of the panning must be appropriate for the orientation. Ie, if display is rotated 180 degrees, the viewport must be flushed to the 'right' and 'bottom' edge of the framebuffer when xoffset and yoffset are zero. Then logical pan_down is physical pan_up, etc. The option is configurable under 'Advanced Low Level Driver Options', and is dependent on CONFIG_FB_ACCEL being set since the wrapper depends on xxximageblit, xxxfillrect and xxxcopyarea. As a testbed, I modified vesafb to support console rotation. The following patches will follow (against linux-2.5.33): a. fb_rotate.diff b. fb_drawing.diff c. vesafb_rotate.diff d. fbset_rotate.diff If the patches are mangled, please get them at: http://i810fb.sourceforge.net/fb_rotate.tar.gz Tony |
|
From: Antonino D. <ad...@po...> - 2002-09-09 14:20:50
|
The patch (fb_rotate.diff) adds console rotation support to the fb
framework. Console rotation wrappers are lumped in fbcon-rotate.h and
fbcon-rotate.c.
p->fontdata is pre-rotated during fbcon_xx_setup(), thus changing fonts
may corrupt the display until fbcon_setup() is called again.
Tony
<<----------------------------------------------------------------------->>
diff -Naur linux-2.5.33/drivers/video/Config.in linux/drivers/video/Config.in
--- linux-2.5.33/drivers/video/Config.in Sun Sep 8 19:38:45 2002
+++ linux/drivers/video/Config.in Sun Sep 8 19:45:59 2002
@@ -227,6 +227,7 @@
tristate ' 24 bpp packed pixels support' CONFIG_FBCON_CFB24
tristate ' 32 bpp packed pixels support' CONFIG_FBCON_CFB32
tristate ' Hardware acceleration support' CONFIG_FBCON_ACCEL
+ dep_tristate ' Console Display Rotation support' CONFIG_FBCON_ROTATE $CONFIG_FBCON_ACCEL
tristate ' Amiga bitplanes support' CONFIG_FBCON_AFB
tristate ' Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
tristate ' Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
diff -Naur linux-2.5.33/drivers/video/Makefile linux/drivers/video/Makefile
--- linux-2.5.33/drivers/video/Makefile Sun Sep 8 19:38:45 2002
+++ linux/drivers/video/Makefile Sun Sep 8 19:45:59 2002
@@ -6,7 +6,7 @@
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
- fbcon-afb.o fbcon-ilbm.o fbcon-accel.o \
+ fbcon-afb.o fbcon-ilbm.o fbcon-accel.o fbcon-rotate.o \
fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
@@ -118,6 +118,7 @@
obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o
obj-$(CONFIG_FBCON_STI) += fbcon-sti.o
obj-$(CONFIG_FBCON_ACCEL) += fbcon-accel.o
+obj-$(CONFIG_FBCON_ROTATE) += fbcon-rotate.o
include $(TOPDIR)/Rules.make
diff -Naur linux-2.5.33/drivers/video/fbcon-rotate.c linux/drivers/video/fbcon-rotate.c
--- linux-2.5.33/drivers/video/fbcon-rotate.c Thu Jan 1 00:00:00 1970
+++ linux/drivers/video/fbcon-rotate.c Sun Sep 8 19:46:35 2002
@@ -0,0 +1,611 @@
+/*
+ * linux/drivers/video/fbcon-accel.c -- Framebuffer Display Rotation
+ *
+ * Created 20 Feb 2001 by James Simmons <jsi...@us...>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#include "fbcon-rotate.h"
+
+#define FONTDATAMAX 4096
+
+static unsigned char fontcache[FONTDATAMAX];
+
+static int pattern_test_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+ u32 tmp = (y * pitch) + x;
+ u32 index = tmp / 8;
+ u32 bit = tmp % 8;
+
+#if defined (__LITTLE_ENDIAN)
+ return (pat[index] & (1 << (7 - bit)));
+#else
+ return (pat[index] & (1 >> bit));
+#endif
+}
+
+static void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+ u32 tmp = (y * pitch) + x;
+ u32 index = tmp/8;
+ u32 bit = tmp % 8;
+
+#if defined (__LITTLE_ENDIAN)
+ pat[index] |= 1 << (7 - bit);
+#else
+ pat[index] |= 1 >> bit;
+#endif
+}
+
+static void rotate_cw(char *in, char *out, u32 width, u32 height)
+{
+ int i, j;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(height - 1 - i, j, height, out);
+ }
+ }
+}
+
+static void rotate_ccw(char *in, char *out, u32 width, u32 height)
+{
+ int i, j;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(i, width - 1 - j, height, out);
+ }
+ }
+}
+
+static void rotate_ud(char *in, char *out, u32 width, u32 height)
+{
+ int i, j;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(width - 1 - j, height - 1 - i, width, out);
+ }
+ }
+}
+
+/*
+ * Clockwise (90 degree) Rotation
+ */
+void fbcon_rr_setup(struct display *p)
+{
+ u32 i, cell_size;
+ char *src, *dst;
+
+ p->next_line = p->fb_info->fix.line_length;
+ p->next_plane = 0;
+
+ memset(fontcache, 0, FONTDATAMAX);
+
+ cell_size = (fontwidth(p) + 7)/ 8;
+ cell_size *= fontheight(p);
+ src = p->fontdata;
+ dst = fontcache;
+
+ for (i = FONTDATAMAX/cell_size; i--; ) {
+ rotate_cw(src, dst, fontwidth(p), fontheight(p));
+ src += cell_size;
+ dst += cell_size;
+ }
+}
+
+void fbcon_rr_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_copyarea area;
+
+ area.sx = info->var.yres_virtual - ((sy + height) * fontheight(p));
+ area.sy = sx * fontwidth(p);
+ area.dx = info->var.yres_virtual - ((dy + height) * fontheight(p));
+ area.dy = dx * fontwidth(p);
+ area.width = height * fontheight(p);
+ area.height = width * fontwidth(p);
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+void fbcon_rr_clear(struct vc_data *vc, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.dx = info->var.yres_virtual - ((sy + height) * fontheight(p));
+ region.dy = sx * fontwidth(p);
+ region.height = width * fontwidth(p);
+ region.width = height * fontheight(p);
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_rr_putc(struct vc_data *vc, struct display *p, int c, int yy,
+ int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, c);
+ image.bg_color = attr_bgcol(p, c);
+ image.dx = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ image.dy = xx * fontwidth(p);
+ image.width = fontheight(p);
+ image.height = fontwidth(p);
+ image.data = fontcache + (c & charmask)*fontheight(p) * width;
+ image.depth = 1;
+ info->fbops->fb_imageblit(info, &image);
+}
+
+void fbcon_rr_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ unsigned int cell_size = width * fontheight(p);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, *s);
+ image.bg_color = attr_bgcol(p, *s);
+ image.dx = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ image.dy = xx * fontwidth(p);
+ image.width = fontheight(p);
+ image.height = fontwidth(p);
+ image.depth = 1;
+ while (count--) {
+ image.data = fontcache + (scr_readw(s++) & charmask) * cell_size;
+ info->fbops->fb_imageblit(info, &image);
+ image.dy += fontwidth(p);
+ }
+}
+
+void fbcon_rr_revc(struct display *p, int xx, int yy)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_fgcol_ec(p, p->conp);
+ region.dx = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ region.dy = xx * fontwidth(p);
+ region.width = fontheight(p);
+ region.height = fontwidth(p);
+ region.rop = ROP_XOR;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_rr_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned int cw = fontwidth(p);
+ unsigned int ch = fontheight(p);
+ unsigned int rw = info->var.xres % cw;
+ unsigned int bh = info->var.yres % ch;
+ unsigned int rs = info->var.xres - rw;
+ unsigned int bs = info->var.yres - bh;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dx = 0;
+ region.dy = info->var.xoffset + rs;
+ region.height = rw;
+ region.width = info->var.yres_virtual;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+
+ if (bh) {
+ region.dx = info->var.yres_virtual - (info->var.yoffset + bs + bh);
+ region.dy = info->var.xoffset;
+ region.width = bh;
+ region.height = rs;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+}
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_rr = {
+ setup: fbcon_rr_setup,
+ bmove: fbcon_rr_bmove,
+ clear: fbcon_rr_clear,
+ putc: fbcon_rr_putc,
+ putcs: fbcon_rr_putcs,
+ revc: fbcon_rr_revc,
+ clear_margins: fbcon_rr_clear_margins,
+ fontwidthmask: FONTWIDTHRANGE(1, 16)
+};
+
+/*
+ * Counterclockwise (270 degree) Rotation
+ */
+void fbcon_rl_setup(struct display *p)
+{
+ u32 i, cell_size;
+ char *src, *dst;
+
+ p->next_line = p->fb_info->fix.line_length;
+ p->next_plane = 0;
+
+ memset(fontcache, 0, FONTDATAMAX);
+
+ cell_size = (fontwidth(p) + 7)/ 8;
+ cell_size *= fontheight(p);
+ src = p->fontdata;
+ dst = fontcache;
+
+ for (i = FONTDATAMAX/cell_size; i--; ) {
+ rotate_ccw(src, dst, (fontwidth(p) + 7) & ~7, fontheight(p));
+ src += cell_size;
+ dst += cell_size;
+ }
+}
+
+void fbcon_rl_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_copyarea area;
+
+ area.sx = sy * fontheight(p);
+ area.sy = info->var.xres_virtual - ((sx + width) * fontwidth(p));
+ area.dx = dy * fontheight(p);
+ area.dy = info->var.xres_virtual - ((dx + width) * fontwidth(p));
+ area.width = height * fontheight(p);
+ area.height = width * fontwidth(p);
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+void fbcon_rl_clear(struct vc_data *vc, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.dx = sy * fontheight(p);
+ region.dy = info->var.xres_virtual - ((sx + width) * fontwidth(p));
+ region.height = width * fontwidth(p);
+ region.width = height * fontheight(p);
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_rl_putc(struct vc_data *vc, struct display *p, int c, int yy,
+ int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, c);
+ image.bg_color = attr_bgcol(p, c);
+ image.dx = yy * fontheight(p);
+ image.dy = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ image.width = fontheight(p);
+ image.height = fontwidth(p);
+ image.data = fontcache + (c & charmask)*fontheight(p) * width;
+ image.depth = 1;
+ info->fbops->fb_imageblit(info, &image);
+}
+
+void fbcon_rl_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ unsigned int cell_size = width * fontheight(p);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, *s);
+ image.bg_color = attr_bgcol(p, *s);
+ image.dx = yy * fontheight(p);
+ image.dy = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ image.width = fontheight(p);
+ image.height = fontwidth(p);
+ image.depth = 1;
+ while (count--) {
+ image.data = fontcache + (scr_readw(s++) & charmask) * cell_size;
+ info->fbops->fb_imageblit(info, &image);
+ image.dy -= fontwidth(p);
+ }
+}
+
+void fbcon_rl_revc(struct display *p, int xx, int yy)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_fgcol_ec(p, p->conp);
+ region.dx = yy * fontheight(p);
+ region.dy = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ region.width = fontheight(p);
+ region.height = fontwidth(p);
+ region.rop = ROP_XOR;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_rl_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned int cw = fontwidth(p);
+ unsigned int ch = fontheight(p);
+ unsigned int rw = info->var.xres % cw;
+ unsigned int bh = info->var.yres % ch;
+ unsigned int rs = info->var.xres - rw;
+ unsigned int bs = info->var.yres - bh;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dx = 0;
+ region.dy = info->var.xres_virtual - (info->var.xoffset + rs + rw);
+ region.height = rw;
+ region.width = info->var.yres_virtual;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+
+ if (bh) {
+ region.dx = info->var.yoffset + bs;
+ region.dy = info->var.xres_virtual - (info->var.xoffset + rs + rw);
+ region.width = bh;
+ region.height = rs;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+}
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_rl = {
+ setup: fbcon_rl_setup,
+ bmove: fbcon_rl_bmove,
+ clear: fbcon_rl_clear,
+ putc: fbcon_rl_putc,
+ putcs: fbcon_rl_putcs,
+ revc: fbcon_rl_revc,
+ clear_margins: fbcon_rl_clear_margins,
+ fontwidthmask: FONTWIDTHRANGE(1, 16)
+};
+
+/*
+ * 180 degree Rotation
+ */
+void fbcon_ud_setup(struct display *p)
+{
+ u32 i, cell_size;
+ char *src, *dst;
+
+ p->next_line = p->fb_info->fix.line_length;
+ p->next_plane = 0;
+
+ memset(fontcache, 0, FONTDATAMAX);
+
+ cell_size = (fontwidth(p) + 7)/ 8;
+ cell_size *= fontheight(p);
+ src = p->fontdata;
+ dst = fontcache;
+
+ for (i = FONTDATAMAX/cell_size; i--; ) {
+ rotate_ud(src, dst, (fontwidth(p) + 7) & ~7, fontheight(p));
+ src += cell_size;
+ dst += cell_size;
+ }
+}
+
+void fbcon_ud_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_copyarea area;
+
+ area.sy = info->var.yres_virtual - ((sy + height) * fontheight(p));
+ area.sx = info->var.xres_virtual - ((sx + width) * fontwidth(p));
+ area.dy = info->var.yres_virtual - ((dy + height) * fontheight(p));
+ area.dx = info->var.xres_virtual - ((dx + width) * fontwidth(p));
+ area.height = height * fontheight(p);
+ area.width = width * fontwidth(p);
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+void fbcon_ud_clear(struct vc_data *vc, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.dy = info->var.yres_virtual - ((sy + height) * fontheight(p));
+ region.dx = info->var.xres_virtual - ((sx + width) * fontwidth(p));
+ region.width = width * fontwidth(p);
+ region.height = height * fontheight(p);
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_ud_putc(struct vc_data *vc, struct display *p, int c, int yy,
+ int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, c);
+ image.bg_color = attr_bgcol(p, c);
+ image.dy = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ image.dx = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ image.height = fontheight(p);
+ image.width = fontwidth(p);
+ image.depth = 1;
+ image.data = fontcache + (c & charmask)*fontheight(p) * width;
+ info->fbops->fb_imageblit(info, &image);
+}
+
+void fbcon_ud_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned short charmask = p->charmask;
+ unsigned int width = ((fontwidth(p)+7)>>3);
+ unsigned int cell_size = width * fontheight(p);
+ struct fb_image image;
+
+ image.fg_color = attr_fgcol(p, *s);
+ image.bg_color = attr_bgcol(p, *s);
+ image.dy = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ image.dx = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ image.height = fontheight(p);
+ image.width = fontwidth(p);
+ image.depth = 1;
+ while (count--) {
+ image.data = fontcache + (scr_readw(s++) & charmask) * cell_size;
+ info->fbops->fb_imageblit(info, &image);
+ image.dx -= fontwidth(p);
+ }
+}
+
+void fbcon_ud_revc(struct display *p, int xx, int yy)
+{
+ struct fb_info *info = p->fb_info;
+ struct fb_fillrect region;
+
+ region.color = attr_fgcol_ec(p, p->conp);
+ region.dy = info->var.yres_virtual - ((yy * fontheight(p)) + fontheight(p));
+ region.dx = info->var.xres_virtual - ((xx * fontwidth(p)) + fontwidth(p));
+ region.height = fontheight(p);
+ region.width = fontwidth(p);
+ region.rop = ROP_XOR;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+void fbcon_ud_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only)
+{
+ struct fb_info *info = p->fb_info;
+ unsigned int cw = fontwidth(p);
+ unsigned int ch = fontheight(p);
+ unsigned int rw = info->var.xres % cw;
+ unsigned int bh = info->var.yres % ch;
+ unsigned int rs = info->var.xres - rw;
+ unsigned int bs = info->var.yres - bh;
+ struct fb_fillrect region;
+
+ region.color = attr_bgcol_ec(p,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dy = 0;
+ region.dx = info->var.xres_virtual - (info->var.xoffset + rs + rw);
+ region.width = rw;
+ region.height = info->var.yres_virtual;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+
+ if (bh) {
+ region.dy = info->var.yres_virtual - (info->var.yoffset + bs + bh);
+ region.dx = info->var.xres_virtual - (info->var.xoffset + rs + rw);
+ region.height = bh;
+ region.width = rs;
+ info->fbops->fb_fillrect(info, ®ion);
+ }
+}
+
+ /*
+ * `switch' for the low level operations
+ */
+
+struct display_switch fbcon_ud = {
+ setup: fbcon_ud_setup,
+ bmove: fbcon_ud_bmove,
+ clear: fbcon_ud_clear,
+ putc: fbcon_ud_putc,
+ putcs: fbcon_ud_putcs,
+ revc: fbcon_ud_revc,
+ clear_margins: fbcon_ud_clear_margins,
+ fontwidthmask: FONTWIDTHRANGE(1, 16)
+};
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_rr);
+EXPORT_SYMBOL(fbcon_rr_setup);
+EXPORT_SYMBOL(fbcon_rr_bmove);
+EXPORT_SYMBOL(fbcon_rr_clear);
+EXPORT_SYMBOL(fbcon_rr_putc);
+EXPORT_SYMBOL(fbcon_rr_putcs);
+EXPORT_SYMBOL(fbcon_rr_revc);
+EXPORT_SYMBOL(fbcon_rr_clear_margins);
+
+EXPORT_SYMBOL(fbcon_rl);
+EXPORT_SYMBOL(fbcon_rl_setup);
+EXPORT_SYMBOL(fbcon_rl_bmove);
+EXPORT_SYMBOL(fbcon_rl_clear);
+EXPORT_SYMBOL(fbcon_rl_putc);
+EXPORT_SYMBOL(fbcon_rl_putcs);
+EXPORT_SYMBOL(fbcon_rl_revc);
+EXPORT_SYMBOL(fbcon_rl_clear_margins);
+
+EXPORT_SYMBOL(fbcon_ud);
+EXPORT_SYMBOL(fbcon_ud_setup);
+EXPORT_SYMBOL(fbcon_ud_bmove);
+EXPORT_SYMBOL(fbcon_ud_clear);
+EXPORT_SYMBOL(fbcon_ud_putc);
+EXPORT_SYMBOL(fbcon_ud_putcs);
+EXPORT_SYMBOL(fbcon_ud_revc);
+EXPORT_SYMBOL(fbcon_ud_clear_margins);
diff -Naur linux-2.5.33/drivers/video/fbcon-rotate.h linux/drivers/video/fbcon-rotate.h
--- linux-2.5.33/drivers/video/fbcon-rotate.h Thu Jan 1 00:00:00 1970
+++ linux/drivers/video/fbcon-rotate.h Sun Sep 8 19:45:59 2002
@@ -0,0 +1,62 @@
+/*
+ * FBcon low-level driver wrapper for the display rotation.
+ */
+
+#ifndef _VIDEO_FBCON_ROTATE_H
+#define _VIDEO_FBCON_ROTATE_H
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#if defined(CONFIG_FBCON_ROTATE) || defined(CONFIG_FBCON_ROTATE_MODULE)
+#define FBCON_HAS_ROTATE
+#endif
+#else
+#if defined(CONFIG_FBCON_ROTATE)
+#define FBCON_HAS_ROTATE
+#endif
+#endif
+
+extern struct display_switch fbcon_rr;
+extern void fbcon_rr_setup(struct display *p);
+extern void fbcon_rr_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_rr_clear(struct vc_data *vc, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_rr_putc(struct vc_data *vc, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_rr_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx);
+extern void fbcon_rr_revc(struct display *p, int xx, int yy);
+extern void fbcon_rr_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only);
+
+extern struct display_switch fbcon_rl;
+extern void fbcon_rl_setup(struct display *p);
+extern void fbcon_rl_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_rl_clear(struct vc_data *vc, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_rl_putc(struct vc_data *vc, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_rl_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx);
+extern void fbcon_rl_revc(struct display *p, int xx, int yy);
+extern void fbcon_rl_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only);
+
+extern struct display_switch fbcon_ud;
+extern void fbcon_ud_setup(struct display *p);
+extern void fbcon_ud_bmove(struct display *p, int sy, int sx, int dy,
+ int dx, int height, int width);
+extern void fbcon_ud_clear(struct vc_data *vc, struct display *p, int sy,
+ int sx, int height, int width);
+extern void fbcon_ud_putc(struct vc_data *vc, struct display *p, int c,
+ int yy, int xx);
+extern void fbcon_ud_putcs(struct vc_data *vc, struct display *p,
+ const unsigned short *s, int count, int yy, int xx);
+extern void fbcon_ud_revc(struct display *p, int xx, int yy);
+extern void fbcon_ud_clear_margins(struct vc_data *vc, struct display *p,
+ int bottom_only);
+
+#endif /* _VIDEO_FBCON_ROTATE_H */
diff -Naur linux-2.5.33/drivers/video/fbgen.c linux/drivers/video/fbgen.c
--- linux-2.5.33/drivers/video/fbgen.c Sun Sep 8 19:38:45 2002
+++ linux/drivers/video/fbgen.c Sun Sep 8 19:45:59 2002
@@ -29,6 +29,7 @@
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
#include "fbcon-accel.h"
+#include "fbcon-rotate.h"
int gen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
@@ -156,10 +157,19 @@
#ifdef FBCON_HAS_ACCEL
display->scrollmode = SCROLL_YNOMOVE;
- display->dispsw = &fbcon_accel;
+#ifdef FBCON_HAS_ROTATE
+ if (info->var.vmode & FB_VMODE_ROTATE_CW)
+ display->dispsw = &fbcon_rr;
+ else if (info->var.vmode & FB_VMODE_ROTATE_CCW)
+ display->dispsw = &fbcon_rl;
+ else if (info->var.vmode & FB_VMODE_ROTATE_UD)
+ display->dispsw = &fbcon_ud;
+ else
+#endif /* FBCON_HAS_ROTATE */
+ display->dispsw = &fbcon_accel;
#else
display->dispsw = &fbcon_dummy;
-#endif
+#endif /* FBCON_HAS_ACCEL */
return;
}
diff -Naur linux-2.5.33/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.5.33/include/linux/fb.h Sun Sep 8 19:45:40 2002
+++ linux/include/linux/fb.h Sun Sep 8 19:45:59 2002
@@ -166,6 +166,11 @@
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_MASK 255
+#define FB_VMODE_ROTATE_CW 0x010000 /* rotate console by 90 degrees */
+#define FB_VMODE_ROTATE_CCW 0x020000 /* rotate console by 270 degrees */
+#define FB_VMODE_ROTATE_UD 0x040000 /* rotate console by 180 degrees */
+#define FB_ROTATE_MASK 0xFF0000
+
#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
|
|
From: Antonino D. <ad...@po...> - 2002-09-09 14:21:28
|
The patch (fb_drawing.diff) is an optional replacement to cfbimgblt.c,
cfbfillrect.c and cfbcopyarea.c. Rotating the display CW or CCW will
expose some of the limitations (alignment and access) of the current
drawing functions because fontheight is very variable. This also fixes
software clipping.
cfbcopyarea.c is just a 'copy 'n paste' of Geert's version I leached
from fbutils (I hope this is okay with you, Geert :) The only changes
are using FB_WRITEL and FB_READL where appropriate.
Tony
<<------------------------------------------------------------------->>
diff -Naur linux-2.5.33/drivers/video/cfbcopyarea.c linux/drivers/video/cfbcopyarea.c
--- linux-2.5.33/drivers/video/cfbcopyarea.c Sun Sep 8 19:34:36 2002
+++ linux/drivers/video/cfbcopyarea.c Sun Sep 8 19:48:05 2002
@@ -28,22 +28,319 @@
#include <asm/io.h>
#include <video/fbcon.h>
+#include "fbcon-rotate.h"
+
+#define LONG_MASK (BITS_PER_LONG - 1)
+
#if BITS_PER_LONG == 32
-#define FB_READ fb_readl
-#define FB_WRITE fb_writel
+#define FB_WRITEL fb_writel
+#define FB_READL fb_readl
+#define SHIFT_PER_LONG 5
+#define BYTES_PER_LONG 4
#else
-#define FB_READ fb_readq
-#define FB_WRITE fb_writeq
+#define FB_WRITEL fb_writeq
+#define FB_READL fb_readq(x)
+#define SHIFT_PER_LONG 6
+#define BYTES_PER_LONG 8
#endif
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+ int src_idx, unsigned long n)
+{
+ unsigned long first, last;
+ int shift = dst_idx-src_idx, left, right;
+ unsigned long d0, d1;
+ int m;
+
+ if (!n)
+ return;
+
+ shift = dst_idx-src_idx;
+ first = ~0UL >> dst_idx;
+ last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+ if (!shift) {
+ // Same alignment for source and dest
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single word
+ if (last)
+ first &= last;
+ FB_WRITEL((*src & first) | (FB_READL(dst) & ~first), dst);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+
+ FB_WRITEL((*src & first) | (FB_READL(dst) & ~first), dst);
+ dst++;
+ src++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ FB_WRITEL(*src++, dst++);
+ n -= 8;
+ }
+ while (n--)
+ FB_WRITEL(*src++, dst++);
+ // Trailing bits
+ if (last)
+ FB_WRITEL((*src & last) | (FB_READL(dst) & ~last), dst);
+ }
+ } else {
+ // Different alignment for source and dest
+
+ right = shift & (BITS_PER_LONG-1);
+ left = -shift & (BITS_PER_LONG-1);
+
+ if (dst_idx+n <= BITS_PER_LONG) {
+ // Single destination word
+ if (last)
+ first &= last;
+ if (shift > 0) {
+ // Single source word
+ FB_WRITEL(((*src >> right) & first) | (FB_READL(dst) & ~first), dst);
+ } else if (src_idx+n <= BITS_PER_LONG) {
+ // Single source word
+ FB_WRITEL(((*src << left) & first) | (FB_READL(dst) & ~first), dst);
+ } else {
+ // 2 source words
+ d0 = *src++;
+ d1 = *src;
+ FB_WRITEL(((d0 << left | d1 >> right) & first) | (FB_READL(dst) & ~first), dst);
+ }
+ } else {
+ // Multiple destination words
+ d0 = *src++;
+ // Leading bits
+ if (shift > 0) {
+ // Single source word
+ FB_WRITEL(((d0 >> right) & first) | (FB_READL(dst) & ~first), dst);
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ } else {
+ // 2 source words
+ d1 = *src++;
+ FB_WRITEL(((d0 << left | d1 >> right) & first) | (FB_READL(dst) & ~first), dst);
+ d0 = d1;
+ dst++;
+ n -= BITS_PER_LONG-dst_idx;
+ }
+
+ // Main chunk
+ m = n % BITS_PER_LONG;
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ d1 = *src++;
+ FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d0 = d1;
+ d1 = *src++;
+ FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d0 = d1;
+ d1 = *src++;
+ FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d0 = d1;
+ d1 = *src++;
+ FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src++;
+ FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d0 = d1;
+ }
+
+ // Trailing bits
+ if (last) {
+ if (m <= right) {
+ // Single source word
+ FB_WRITEL(((d0 << left) & last) | (FB_READL(dst) & ~last), dst);
+ } else {
+ // 2 source words
+ d1 = *src;
+ FB_WRITEL(((d0 << left | d1 >> right) & last) | (FB_READL(dst) & ~last), dst);
+ }
+ }
+ }
+ }
+}
+
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+ const unsigned long *src, int src_idx, unsigned long n)
+{
+ unsigned long first, last;
+ int shift = dst_idx-src_idx, left, right;
+ unsigned long d0, d1;
+ int m;
+
+ if (!n)
+ return;
+
+ dst += (n-1)/BITS_PER_LONG;
+ src += (n-1)/BITS_PER_LONG;
+ if ((n-1) % BITS_PER_LONG) {
+ dst_idx += (n-1) % BITS_PER_LONG;
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= BITS_PER_LONG-1;
+ src_idx += (n-1) % BITS_PER_LONG;
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= BITS_PER_LONG-1;
+ }
+
+ shift = dst_idx-src_idx;
+ first = ~0UL << (BITS_PER_LONG-1-dst_idx);
+ last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+
+ if (!shift) {
+ // Same alignment for source and dest
+
+ if ((unsigned long)dst_idx+1 >= n) {
+ // Single word
+ if (last)
+ first &= last;
+ FB_WRITEL((*src & first) | (FB_READL(dst) & ~first), dst);
+ } else {
+ // Multiple destination words
+ // Leading bits
+ if (first) {
+ FB_WRITEL((*src & first) | (FB_READL(dst) & ~first), dst);
+ dst--;
+ src--;
+ n -= dst_idx+1;
+ }
+
+ // Main chunk
+ n /= BITS_PER_LONG;
+ while (n >= 8) {
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ FB_WRITEL(*src--, dst--);
+ n -= 8;
+ }
+ while (n--)
+ FB_WRITEL(*src--, dst--);
+
+ // Trailing bits
+ if (last)
+ FB_WRITEL((*src & last) | (FB_READL(dst) & ~last), dst);
+ }
+ } else {
+ // Different alignment for source and dest
+
+ right = shift & (BITS_PER_LONG-1);
+ left = -shift & (BITS_PER_LONG-1);
+
+ if ((unsigned long)dst_idx+1 >= n) {
+ // Single destination word
+ if (last)
+ first &= last;
+ if (shift < 0) {
+ // Single source word
+ FB_WRITEL((*src << left & first) | (FB_READL(dst) & ~first), dst);
+ } else if (1+(unsigned long)src_idx >= n) {
+ // Single source word
+ FB_WRITEL(((*src >> right) & first) | (FB_READL(dst) & ~first), dst);
+ } else {
+ // 2 source words
+ d0 = *src--;
+ d1 = *src;
+ FB_WRITEL(((d0 >> right | d1 << left) & first) | (FB_READL(dst) & ~first), dst);
+ }
+ } else {
+ // Multiple destination words
+ d0 = *src--;
+ // Leading bits
+ if (shift < 0) {
+ // Single source word
+ FB_WRITEL(((d0 << left) & first) | (FB_READL(dst) & ~first), dst);
+ dst--;
+ n -= dst_idx+1;
+ } else {
+ // 2 source words
+ d1 = *src--;
+ FB_WRITEL(((d0 >> right | d1 << left) & first) | (FB_READL(dst) & ~first), dst);
+ d0 = d1;
+ dst--;
+ n -= dst_idx+1;
+ }
+
+ // Main chunk
+ m = n % BITS_PER_LONG;
+ n /= BITS_PER_LONG;
+ while (n >= 4) {
+ d1 = *src--;
+ FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d0 = d1;
+ d1 = *src--;
+ FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d0 = d1;
+ d1 = *src--;
+ FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d0 = d1;
+ d1 = *src--;
+ FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src--;
+ FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d0 = d1;
+ }
+
+ // Trailing bits
+ if (last) {
+ if (m <= left) {
+ // Single source word
+ FB_WRITEL(((d0 >> right) & last) | (FB_READL(dst) & ~last), dst);
+ } else {
+ // 2 source words
+ d1 = *src;
+ FB_WRITEL(((d0 >> right | d1 << left) & last) |
+ (FB_READL(dst) & ~last), dst);
+ }
+ }
+ }
+ }
+}
+
void cfb_copyarea(struct fb_info *p, struct fb_copyarea *area)
{
- int x2, y2, lineincr, shift, shift_right, shift_left, old_dx, old_dy;
- int j, linesize = p->fix.line_length, bpl = sizeof(unsigned long);
- unsigned long start_index, end_index, start_mask, end_mask, last;
+ int x2, y2, old_dx, old_dy, vxres, vyres;
+ unsigned long next_line = p->fix.line_length;
+ int dst_idx = 0, src_idx = 0, rev_copy = 0;
unsigned long *dst = NULL, *src = NULL;
- char *src1, *dst1;
- int tmp, height;
+
+ vxres = p->var.xres_virtual;
+ vyres = p->var.yres_virtual;
+#ifdef FBCON_HAS_ROTATE
+ if (p->var.vmode & (FB_VMODE_ROTATE_CW | FB_VMODE_ROTATE_CCW)) {
+ vxres = p->var.yres_virtual;
+ vyres = p->var.xres_virtual;
+ }
+#endif
+
+ if (area->dx > vxres ||
+ area->sx > vxres ||
+ area->dy > vyres ||
+ area->sy > vyres)
+ return;
/* clip the destination */
old_dx = area->dx;
@@ -57,8 +354,8 @@
y2 = area->dy + area->height;
area->dx = area->dx > 0 ? area->dx : 0;
area->dy = area->dy > 0 ? area->dy : 0;
- x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
- y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+ x2 = x2 < vxres ? x2 : vxres;
+ y2 = y2 < vyres ? y2 : vyres;
area->width = x2 - area->dx;
area->height = y2 - area->dy;
@@ -66,165 +363,45 @@
area->sx += (area->dx - old_dx);
area->sy += (area->dy - old_dy);
- height = area->height;
-
/* the source must be completely inside the virtual screen */
if (area->sx < 0 || area->sy < 0 ||
- (area->sx + area->width) > p->var.xres_virtual ||
- (area->sy + area->height) > p->var.yres_virtual)
+ (area->sx + area->width) > vxres ||
+ (area->sy + area->height) > vyres)
return;
- if (area->dy < area->sy
- || (area->dy == area->sy && area->dx < area->sx)) {
- /* start at the top */
- src1 = p->screen_base + area->sy * linesize +
- ((area->sx * p->var.bits_per_pixel) >> 3);
- dst1 = p->screen_base + area->dy * linesize +
- ((area->dx * p->var.bits_per_pixel) >> 3);
- lineincr = linesize;
- } else {
- /* start at the bottom */
- src1 = p->screen_base + (area->sy + area->height-1) * linesize
- + (((area->sx + area->width - 1) * p->var.bits_per_pixel) >> 3);
- dst1 = p->screen_base + (area->dy + area->height-1) * linesize
- + (((area->dx + area->width - 1) * p->var.bits_per_pixel) >> 3);
- lineincr = -linesize;
+ if (area->dy > area->sy || (area->dy == area->sy && area->dx > area->sx)) {
+ area->dy += area->height;
+ area->sy += area->height;
+ rev_copy = 1;
}
-
- if ((BITS_PER_LONG % p->var.bits_per_pixel) == 0) {
- int ppw = BITS_PER_LONG / p->var.bits_per_pixel;
- int n = ((area->width * p->var.bits_per_pixel) >> 3);
-
- start_index = ((unsigned long) src1 & (bpl - 1));
- end_index = ((unsigned long) (src1 + n) & (bpl - 1));
- shift = ((unsigned long) dst1 & (bpl - 1)) -
- ((unsigned long) src1 & (bpl - 1));
- start_mask = end_mask = 0;
-
- if (start_index) {
- start_mask = -1 >> (start_index << 3);
- n -= (bpl - start_index);
+
+ dst = src = (unsigned long *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1));
+ dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
+ dst_idx += area->dy*next_line*8+area->dx*p->var.bits_per_pixel;
+ src_idx += area->sy*next_line*8+area->sx*p->var.bits_per_pixel;
+
+ if (rev_copy) {
+ while (area->height--) {
+ dst_idx -= next_line*8;
+ src_idx -= next_line*8;
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BYTES_PER_LONG-1);
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= (BYTES_PER_LONG-1);
+ bitcpy_rev((unsigned long *)dst, dst_idx, (unsigned long *)src,
+ src_idx, area->width*p->var.bits_per_pixel);
}
-
- if (end_index) {
- end_mask = -1 << ((bpl - end_index) << 3);
- n -= end_index;
- }
- n /= bpl;
-
- if (n <= 0) {
- if (start_mask) {
- if (end_mask)
- end_mask &= start_mask;
- else
- end_mask = start_mask;
- start_mask = 0;
- }
- n = 0;
- }
-
- if (shift) {
- if (shift > 0) {
- /* dest is over to right more */
- shift_right =
- shift * p->var.bits_per_pixel;
- shift_left =
- (ppw - shift) * p->var.bits_per_pixel;
- } else {
- /* source is to the right more */
- shift_right =
- (ppw + shift) * p->var.bits_per_pixel;
- shift_left =
- -shift * p->var.bits_per_pixel;
- }
- /* general case, positive increment */
- if (lineincr > 0) {
- if (shift < 0)
- n++;
- do {
- dst = (unsigned long *) dst1;
- src = (unsigned long *) src1;
-
- last = (FB_READ(src) & start_mask);
-
- if (shift > 0)
- FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
- for (j = 0; j < n; j++) {
- dst++;
- tmp = FB_READ(src);
- src++;
- FB_WRITE((last << shift_left) | (tmp >> shift_right), dst);
- last = tmp;
- src++;
- }
- FB_WRITE(FB_READ(dst) | (last << shift_left), dst);
- src1 += lineincr;
- dst1 += lineincr;
- } while (--height);
- } else {
- /* general case, negative increment */
- if (shift > 0)
- n++;
- do {
- dst = (unsigned long *) dst1;
- src = (unsigned long *) src1;
-
- last = (FB_READ(src) & end_mask);
-
- if (shift < 0)
- FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
- for (j = 0; j < n; j++) {
- dst--;
- tmp = FB_READ(src);
- src--;
- FB_WRITE((tmp << shift_left) | (last >> shift_right), dst);
- last = tmp;
- src--;
- }
- FB_WRITE(FB_READ(dst) | (last >> shift_right), dst);
- src1 += lineincr;
- dst1 += lineincr;
- } while (--height);
- }
- } else {
- /* no shift needed */
- if (lineincr > 0) {
- /* positive increment */
- do {
- dst = (unsigned long *) (dst1 - start_index);
- src = (unsigned long *) (src1 - start_index);
-
- if (start_mask)
- FB_WRITE(FB_READ(src) | start_mask, dst);
-
- for (j = 0; j < n; j++) {
- FB_WRITE(FB_READ(src), dst);
- dst++;
- src++;
- }
-
- if (end_mask)
- FB_WRITE(FB_READ(src) | end_mask, dst);
- src1 += lineincr;
- dst1 += lineincr;
- } while (--height);
- } else {
- /* negative increment */
- do {
- dst = (unsigned long *) dst1;
- src = (unsigned long *) src1;
-
- if (start_mask)
- FB_WRITE(FB_READ(src) | start_mask, dst);
- for (j = 0; j < n; j++) {
- FB_WRITE(FB_READ(src), dst);
- dst--;
- src--;
- }
- src1 += lineincr;
- dst1 += lineincr;
- } while (--height);
- }
+ }
+ else {
+ while (area->height--) {
+ dst += dst_idx >> SHIFT_PER_LONG;
+ dst_idx &= (BYTES_PER_LONG-1);
+ src += src_idx >> SHIFT_PER_LONG;
+ src_idx &= (BYTES_PER_LONG-1);
+ bitcpy((unsigned long *)dst, dst_idx, (unsigned long *)src,
+ src_idx, area->width*p->var.bits_per_pixel);
+ dst_idx += next_line*8;
+ src_idx += next_line*8;
}
}
-}
+}
diff -Naur linux-2.5.33/drivers/video/cfbfillrect.c linux/drivers/video/cfbfillrect.c
--- linux-2.5.33/drivers/video/cfbfillrect.c Sun Sep 8 19:34:36 2002
+++ linux/drivers/video/cfbfillrect.c Sun Sep 8 19:47:59 2002
@@ -22,168 +22,167 @@
#include <asm/types.h>
#include <video/fbcon.h>
+#include "fbcon-rotate.h"
+
#if BITS_PER_LONG == 32
-#define FB_READ fb_readl
-#define FB_WRITE fb_writel
+#define FB_WRITEL fb_writel
+#define FB_READL fb_readl
#else
-#define FB_READ fb_readq
-#define FB_WRITE fb_writeq
+#define FB_WRITEL fb_writeq
+#define FB_READL fb_readq
+#endif
+
+#if defined (__BIG_ENDIAN)
+#define SHIFT_HIGH(val, bits) ((val) >> (bits))
+#define SHIFT_LOW(val, bits) ((val) << (bits))
+#else
+#define SHIFT_HIGH(val, bits) ((val) << (bits))
+#define SHIFT_LOW(val, bits) ((val) >> (bits))
#endif
void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect)
{
- unsigned long start_index, end_index, start_mask = 0, end_mask = 0;
- unsigned long height, ppw, fg, fgcolor;
- int i, n, x2, y2, linesize = p->fix.line_length;
- int bpl = sizeof(unsigned long);
- unsigned long *dst;
- char *dst1;
+ unsigned long start_index, pitch_index;
+ unsigned long height, fg, bitstart, shift, color;
+ unsigned long bpp = p->var.bits_per_pixel;
+ unsigned long null_bits = BITS_PER_LONG - bpp;
+ unsigned long n, x2, y2, vxres, vyres, linesize = p->fix.line_length;
+ unsigned long bpl = sizeof(unsigned long);
+ unsigned long *dst = NULL;
+ char *dst1, *dst2;
+
+ vxres = p->var.xres_virtual;
+ vyres = p->var.yres_virtual;
+#ifdef FBCON_HAS_ROTATE
+ if (p->var.vmode & (FB_VMODE_ROTATE_CW | FB_VMODE_ROTATE_CCW)) {
+ vxres = p->var.yres_virtual;
+ vyres = p->var.xres_virtual;
+ }
+#endif
- if (!rect->width || !rect->height)
+ if (!rect->width || !rect->height ||
+ rect->dx > vxres ||
+ rect->dy > vyres)
return;
/* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly. */
+
x2 = rect->dx + rect->width;
y2 = rect->dy + rect->height;
- x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
- y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+ x2 = x2 < vxres ? x2 : vxres;
+ y2 = y2 < vyres ? y2 : vyres;
rect->width = x2 - rect->dx;
height = y2 - rect->dy;
- /* Size of the scanline in bytes */
- n = (rect->width * (p->var.bits_per_pixel >> 3));
- ppw = BITS_PER_LONG / p->var.bits_per_pixel;
-
- dst1 = p->screen_base + (rect->dy * linesize) +
- (rect->dx * (p->var.bits_per_pixel >> 3));
- start_index = ((unsigned long) dst1 & (bpl - 1));
- end_index = ((unsigned long) (dst1 + n) & (bpl - 1));
- if (p->fix.visual == FB_VISUAL_TRUECOLOR)
- fg = fgcolor = ((u32 *) (p->pseudo_palette))[rect->color];
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+ fg = ((u32 *) (p->pseudo_palette))[rect->color];
else
- fg = fgcolor = rect->color;
-
- for (i = 0; i < ppw - 1; i++) {
- fg <<= p->var.bits_per_pixel;
- fg |= fgcolor;
- }
-
- if (start_index) {
- start_mask = fg << (start_index << 3);
- n -= (bpl - start_index);
- }
-
- if (end_index) {
- end_mask = fg >> ((bpl - end_index) << 3);
- n -= end_index;
- }
-
- n = n / bpl;
-
- if (n <= 0) {
- if (start_mask) {
- if (end_mask)
- end_mask &= start_mask;
- else
- end_mask = start_mask;
- start_mask = 0;
- }
- n = 0;
- }
-
- if ((BITS_PER_LONG % p->var.bits_per_pixel) == 0) {
- switch (rect->rop) {
- case ROP_COPY:
- do {
- /* Word align to increases performace :-) */
- dst = (unsigned long *) (dst1 - start_index);
-
- if (start_mask) {
- FB_WRITE(FB_READ(dst) |
- start_mask, dst);
- dst++;
- }
-
- for (i = 0; i < n; i++) {
- FB_WRITE(fg, dst);
- dst++;
- }
-
- if (end_mask)
- FB_WRITE(FB_READ(dst) | end_mask,
- dst);
- dst1 += linesize;
- } while (--height);
- break;
- case ROP_XOR:
- do {
- dst = (unsigned long *) (dst1 - start_index);
-
- if (start_mask) {
- FB_WRITE(FB_READ(dst) ^
- start_mask, dst);
- dst++;
- }
-
- for (i = 0; i < n; i++) {
- FB_WRITE(FB_READ(dst) ^ fg, dst);
- dst++;
- }
+ fg = rect->color;
- if (end_mask) {
- FB_WRITE(FB_READ(dst) ^ end_mask,
- dst);
- }
+ bitstart = (((rect->dy * linesize) * 8) +
+ rect->dx * bpp);
+
+ start_index = bitstart & (BITS_PER_LONG - 1);
+
+ /* line_length not a multiple of an unsigned long? */
+ pitch_index = (linesize & (bpl - 1)) * 8;
+
+ bitstart /= 8;
+ bitstart &= ~(bpl - 1);
+ dst1 = dst2 = p->screen_base + bitstart;
+
+ switch (rect->rop) {
+ case ROP_COPY:
+ do {
+ dst = (unsigned long *) dst1;
+ shift = 0;
+ color = 0;
+ n = rect->width;
+
+ /*
+ * read leading bits
+ */
+ if (start_index) {
+ unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index));
+
+ color = FB_READL(dst) & start_mask;
+ shift = start_index;
+ }
+
+ while (n--) {
+ color |= SHIFT_HIGH(fg, shift);
+ if (shift >= null_bits) {
+ FB_WRITEL(color, dst++);
+ if (shift == null_bits)
+ color = 0;
+ else
+ color = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ }
+ shift += bpp;
+ shift &= (BITS_PER_LONG - 1);
+ }
+
+ /*
+ * write trailing bits
+ */
+ if (shift) {
+ unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+
+ FB_WRITEL((FB_READL(dst) & end_mask) | color, dst);
+ }
+
+ if (!pitch_index) {
dst1 += linesize;
- } while (--height);
- break;
- }
- } else {
- /* Odd modes like 24 or 80 bits per pixel */
- start_mask = fg >> (start_index * p->var.bits_per_pixel);
- end_mask = fg << (end_index * p->var.bits_per_pixel);
- /* start_mask =& PFILL24(x1,fg);
- end_mask_or = end_mask & PFILL24(x1+width-1,fg); */
-
- n = (rect->width - start_index - end_index) / ppw;
-
- switch (rect->rop) {
- case ROP_COPY:
- do {
- dst = (unsigned long *) dst1;
- if (start_mask)
- *dst |= start_mask;
- if ((start_index + rect->width) > ppw)
- dst++;
+ }
+ else {
+ dst2 += linesize;
+ dst1 = dst2;
+ (unsigned long) dst1 &= ~(bpl - 1);
+ start_index += pitch_index;
+ start_index &= BITS_PER_LONG - 1;
+ }
+
+ } while (--height);
+ break;
+ case ROP_XOR:
+ do {
+ dst = (unsigned long *) dst1;
+ shift = start_index;
+ color = 0;
+ n = rect->width;
+
+ while (n--) {
+ color |= SHIFT_HIGH(fg, shift);
+ if (shift >= null_bits) {
+ FB_WRITEL(FB_READL(dst) ^ color, dst);
+ dst++;
+ if (shift == null_bits)
+ color = 0;
+ else
+ color = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ }
+ shift += bpp;
+ shift &= (BITS_PER_LONG - 1);
+ }
+ if (shift)
+ FB_WRITEL(FB_READL(dst) ^ color, dst);
- /* XXX: slow */
- for (i = 0; i < n; i++) {
- *dst++ = fg;
- }
- if (end_mask)
- *dst |= end_mask;
- dst1 += linesize;
- } while (--height);
- break;
- case ROP_XOR:
- do {
- dst = (unsigned long *) dst1;
- if (start_mask)
- *dst ^= start_mask;
- if ((start_mask + rect->width) > ppw)
- dst++;
-
- for (i = 0; i < n; i++) {
- *dst++ ^= fg; /* PFILL24(fg,x1+i); */
- }
- if (end_mask)
- *dst ^= end_mask;
+ if (!pitch_index) {
dst1 += linesize;
- } while (--height);
- break;
- }
+ }
+ else {
+ dst2 += linesize;
+ dst1 = dst2;
+ (unsigned long) dst1 &= ~(bpl - 1);
+ start_index += pitch_index;
+ start_index &= BITS_PER_LONG - 1;
+ }
+ } while (--height);
+ break;
}
+
return;
}
diff -Naur linux-2.5.33/drivers/video/cfbimgblt.c linux/drivers/video/cfbimgblt.c
--- linux-2.5.33/drivers/video/cfbimgblt.c Sun Sep 8 19:31:34 2002
+++ linux/drivers/video/cfbimgblt.c Sun Sep 8 19:47:55 2002
@@ -22,6 +22,13 @@
* FIXME
* The code for 24 bit is horrible. It copies byte by byte size instead of
* longs like the other sizes. Needs to be optimized.
+ *
+ * Tony:
+ * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
+ * up the code significantly.
+ *
+ * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
+ * still processed a bit at a time.
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
@@ -32,6 +39,7 @@
#include <asm/types.h>
#include <video/fbcon.h>
+#include "fbcon-rotate.h"
#define DEBUG
@@ -41,91 +49,303 @@
#define DPRINTK(fmt, args...)
#endif
+static u32 cfb_tab8[] = {
+#if defined(__BIG_ENDIAN)
+ 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+ 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+ 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+ 0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000,0xff000000,0x00ff0000,0xffff0000,
+ 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+ 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+ 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static u32 cfb_tab16[] = {
+#if defined(__BIG_ENDIAN)
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static u32 cfb_tab32[] = {
+ 0x00000000, 0xffffffff
+};
+
+#if BITS_PER_LONG == 32
+#define FB_WRITEL fb_writel
+#define FB_READL fb_readl
+#else
+#define FB_WRITEL fb_writeq
+#define FB_READL fb_readq
+#endif
+
+#if defined (__BIG_ENDIAN)
+#define LEFT_POS(bpp) (BITS_PER_LONG - bpp)
+#define NEXT_POS(pos, bpp) ((pos) -= (bpp))
+#define SHIFT_HIGH(val, bits) ((val) >> (bits))
+#define SHIFT_LOW(val, bits) ((val) << (bits))
+#else
+#define LEFT_POS(bpp) (0)
+#define NEXT_POS(pos, bpp) ((pos) += (bpp))
+#define SHIFT_HIGH(val, bits) ((val) << (bits))
+#define SHIFT_LOW(val, bits) ((val) >> (bits))
+#endif
+
+static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
+ unsigned long start_index, unsigned long pitch_index)
+{
+ /* Draw the penguin */
+ int i, n;
+ unsigned long bitmask = SHIFT_LOW(~0UL, BITS_PER_LONG - p->var.bits_per_pixel);
+ unsigned long *palette = (unsigned long *) p->pseudo_palette;
+ unsigned long *dst, *dst2, color = 0, val, shift;
+ unsigned long null_bits = BITS_PER_LONG - p->var.bits_per_pixel;
+ u8 *src = image->data;
+
+ dst2 = (unsigned long *) dst1;
+ for (i = image->height; i--; ) {
+ n = image->width;
+ dst = (unsigned long *) dst1;
+ shift = 0;
+ val = 0;
+
+ if (start_index) {
+ unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index));
+
+ val = FB_READL(dst) & start_mask;
+ shift = start_index;
+ }
+ while (n--) {
+ if (p->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ color = *src & bitmask;
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+ color = palette[*src] & bitmask;
+ val |= SHIFT_HIGH(color, shift);
+ if (shift >= null_bits) {
+ FB_WRITEL(val, dst++);
+ if (shift == null_bits)
+ val = 0;
+ else
+ val = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ }
+ shift += p->var.bits_per_pixel;
+ shift &= (BITS_PER_LONG - 1);
+ src++;
+ }
+ if (shift) {
+ unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+
+ FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+ }
+ dst1 += p->fix.line_length;
+ if (pitch_index) {
+ dst2 += p->fix.line_length;
+ dst1 = (char *) dst2;
+ (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+
+ start_index += pitch_index;
+ start_index &= BITS_PER_LONG - 1;
+ }
+ }
+}
+
+static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
+ unsigned long fgcolor, unsigned long bgcolor,
+ unsigned long start_index, unsigned long pitch_index)
+{
+ unsigned long i, j, l = 8;
+ unsigned long shift, color, bpp = p->var.bits_per_pixel;
+ unsigned long *dst, *dst2, val, pitch = p->fix.line_length;
+ unsigned long null_bits = BITS_PER_LONG - bpp;
+ u8 *src = image->data;
+
+ dst2 = (unsigned long *) dst1;
+
+ for (i = image->height; i--; ) {
+ shift = 0;
+ val = 0;
+ j = image->width;
+ dst = (unsigned long *) dst1;
+
+ /* write start bits, if any */
+ if (start_index) {
+ unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index));
+
+ val = FB_READL(dst) & start_mask;
+ shift = start_index;
+ }
+ while (j--) {
+ l--;
+ if (*src & (1 << l))
+ color = fgcolor;
+ else
+ color = bgcolor;
+ val |= SHIFT_HIGH(color, shift);
+
+ /* Did the bitshift spill bits to the next long? */
+ if (shift >= null_bits) {
+ FB_WRITEL(val, dst++);
+ if (shift == null_bits)
+ val = 0;
+ else
+ val = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ }
+ shift += bpp;
+ shift &= (BITS_PER_LONG - 1);
+ if (!l) { l = 8; src++; };
+ }
+ /* write end bits, if any*/
+ if (shift) {
+ unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+
+ FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+ }
+ dst1 += pitch;
+
+ if (pitch_index) {
+ dst2 += pitch;
+ dst1 = (char *) dst2;
+ (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+
+ start_index += pitch_index;
+ start_index &= BITS_PER_LONG - 1;
+ }
+
+ }
+}
+
+static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
+ unsigned long fgcolor, unsigned long bgcolor)
+{
+ int i, j, k, l = 8, n;
+ unsigned long bit_mask, end_mask, eorx;
+ unsigned long fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel;
+ unsigned long tmp = (1 << bpp) - 1;
+ unsigned long ppw = BITS_PER_LONG/bpp, ppos;
+ unsigned long *dst;
+ u32 *tab = NULL;
+ char *src = image->data;
+
+ switch (ppw) {
+ case 4:
+ tab = cfb_tab8;
+ break;
+ case 2:
+ tab = cfb_tab16;
+ break;
+ case 1:
+ tab = cfb_tab32;
+ break;
+ }
+
+ for (i = ppw-1; i--; ) {
+ fgx <<= bpp;
+ bgx <<= bpp;
+ fgx |= fgcolor;
+ bgx |= bgcolor;
+ }
+
+ n = ((image->width + 7) / 8);
+ pad = (n * 8) - image->width;
+ n = image->width % ppw;
+
+ bit_mask = (1 << ppw) - 1;
+ eorx = fgx ^ bgx;
+
+ k = image->width/ppw;
+
+ for (i = image->height; i--; ) {
+ dst = (unsigned long *) dst1;
+
+ for (j = k; j--; ) {
+ l -= ppw;
+ end_mask = tab[(*src >> l) & bit_mask];
+ FB_WRITEL((end_mask & eorx)^bgx, dst++);
+ if (!l) { l = 8; src++; }
+ }
+ if (n) {
+ end_mask = 0;
+ ppos = LEFT_POS(bpp);
+ for (j = n; j > 0; j--) {
+ l--;
+ if (*src & (1 << l))
+ end_mask |= tmp << ppos;
+ NEXT_POS(ppos, bpp);
+ if (!l) { l = 8; src++; }
+ }
+ FB_WRITEL((end_mask & eorx)^bgx, dst++);
+ }
+ l -= pad;
+ dst1 += p->fix.line_length;
+ }
+}
+
void cfb_imageblit(struct fb_info *p, struct fb_image *image)
{
- int pad, ppw;
- int x2, y2, n, i, j, k, l = 7;
- unsigned long tmp = ~0 << (BITS_PER_LONG - p->var.bits_per_pixel);
- unsigned long fgx, bgx, fgcolor, bgcolor, eorx;
- unsigned long end_mask;
- unsigned long *dst = NULL;
+ int x2, y2, vxres, vyres;
+ unsigned long fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+ unsigned long bpl = sizeof(unsigned long), bpp = p->var.bits_per_pixel;
u8 *dst1;
- u8 *src;
+
+ vxres = p->var.xres_virtual;
+ vyres = ...
[truncated message content] |
|
From: Geert U. <ge...@li...> - 2002-09-09 14:36:17
|
On 9 Sep 2002, Antonino Daplas wrote:
> cfbcopyarea.c is just a 'copy 'n paste' of Geert's version I leached
> from fbutils (I hope this is okay with you, Geert :) The only changes
> are using FB_WRITEL and FB_READL where appropriate.
Of course (actually that was my intention ;-)
Did you measure any noticeable differences (performance-wise) with the old
routines?
BTW, expect a fillrect() for arbitrary bitdepths soon...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@li...
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
|
|
From: Antonino D. <ad...@po...> - 2002-09-09 15:06:08
|
On Mon, 2002-09-09 at 22:35, Geert Uytterhoeven wrote: > On 9 Sep 2002, Antonino Daplas wrote: > > cfbcopyarea.c is just a 'copy 'n paste' of Geert's version I leached > > from fbutils (I hope this is okay with you, Geert :) The only changes > > are using FB_WRITEL and FB_READL where appropriate. > > Of course (actually that was my intention ;-) Thanks. > > Did you measure any noticeable differences (performance-wise) with the old > routines? > Yes, but not by much, something like less than a second. But I haven't really done a test where the primary operation is copyarea... Will this be affected by the the setting of display->scrollmode? I use SCROLL_YREDRAW. > BTW, expect a fillrect() for arbitrary bitdepths soon... This is good :) The one I included should do that too, but it is terribly inefficient. Tony |
|
From: Geert U. <ge...@li...> - 2002-10-06 20:42:24
|
On 9 Sep 2002, Antonino Daplas wrote:
> On Mon, 2002-09-09 at 22:35, Geert Uytterhoeven wrote:
> > On 9 Sep 2002, Antonino Daplas wrote:
> > > cfbcopyarea.c is just a 'copy 'n paste' of Geert's version I leached
> > > from fbutils (I hope this is okay with you, Geert :) The only changes
> > > are using FB_WRITEL and FB_READL where appropriate.
> >
> > Of course (actually that was my intention ;-)
> Thanks.
>
> >
> > Did you measure any noticeable differences (performance-wise) with the old
> > routines?
> >
> Yes, but not by much, something like less than a second. But I haven't
> really done a test where the primary operation is copyarea... Will this
> be affected by the the setting of display->scrollmode? I use
> SCROLL_YREDRAW.
>
> > BTW, expect a fillrect() for arbitrary bitdepths soon...
> This is good :) The one I included should do that too, but it is
> terribly inefficient.
The fillrect() for arbitrary bitdepths is in fbtest now. I also added fast
support for planar screens. Well, now I can start porting amifb to the accel
framework.
So far I tested fbtest on
- PPC (atyfb on 3D RAGE II+, cfb)
- m68k (amifb on Amiga AGA, planar)
- Alpha (tgafb on DEC UDB with 8-bit TGA, cfb)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@li...
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
|
|
From: Antonino D. <ad...@po...> - 2002-10-07 19:45:04
Attachments:
cfbfillrect.c
|
On Mon, 2002-10-07 at 04:41, Geert Uytterhoeven wrote:
>
> The fillrect() for arbitrary bitdepths is in fbtest now. I also added fast
> support for planar screens. Well, now I can start porting amifb to the accel
> framework.
>
I modified your fillrect for cfbfillrect.c. Just added support for
ROP_XOR.
Here's also some rudimentary benchmarks:
fill/copy a 256x256 rectangle 1000 times (8bpp):
old new
copyarea 4.930s 5.151s
fillrect(ROP_COPY) 0.136s 0.256s
fillrect(ROP_XOR) 4.059s 3.903s
Tony
|
|
From: Geert U. <ge...@li...> - 2002-10-07 20:06:52
|
On 8 Oct 2002, Antonino Daplas wrote:
> On Mon, 2002-10-07 at 04:41, Geert Uytterhoeven wrote:
> > The fillrect() for arbitrary bitdepths is in fbtest now. I also added fast
> > support for planar screens. Well, now I can start porting amifb to the accel
> > framework.
> >
> I modified your fillrect for cfbfillrect.c. Just added support for
> ROP_XOR.
>
> Here's also some rudimentary benchmarks:
>
> fill/copy a 256x256 rectangle 1000 times (8bpp):
>
> old new
> copyarea 4.930s 5.151s
> fillrect(ROP_COPY) 0.136s 0.256s
> fillrect(ROP_XOR) 4.059s 3.903s
Yes, there is still room for optimization...
If next_line is a multiple of BYTES_PER_LONG, there's no need to recalculate
the first and last masks.
Even if next_line is not a multiple of BYTES_PER_LONG, the first and last masks
are periodic, and can be precalculated and put in a table (4 entries on 32-bit
and 8 entries on 64-bit).
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@li...
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
|
|
From: Antonino D. <ad...@po...> - 2002-09-09 14:22:02
|
The patch (vesafb_rotate.diff) adds console rotation support to vesafb.
The main change is addition of vesafb_check_var to check for the flags,
and swapping xres, yres, etc where appropriate.
ypan should work okay, I'm not so sure about ywrap.
Tony
<<------------------------------------------------------------------------>>
diff -Naur linux-2.5.33/drivers/video/Config.in linux/drivers/video/Config.in
--- linux-2.5.33/drivers/video/Config.in Sun Sep 8 19:47:38 2002
+++ linux/drivers/video/Config.in Sun Sep 8 19:50:38 2002
@@ -370,6 +370,13 @@
define_tristate CONFIG_FBCON_ACCEL m
fi
fi
+ if [ "$CONFIG_FB_VESA" = "y" ]; then
+ define_tristate CONFIG_FBCON_ROTATE y
+ else
+ if [ "$CONFIG_FB_VESA" = "m" ]; then
+ define_tristate CONFIG_FBCON_ROTATE m
+ fi
+ fi
if [ "$CONFIG_FB_AMIGA" = "y" ]; then
define_tristate CONFIG_FBCON_AFB y
define_tristate CONFIG_FBCON_ILBM y
diff -Naur linux-2.5.33/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- linux-2.5.33/drivers/video/vesafb.c Sun Sep 8 19:34:40 2002
+++ linux/drivers/video/vesafb.c Sun Sep 8 19:49:11 2002
@@ -27,6 +27,8 @@
#include <video/fbcon.h>
+#include "fbcon-rotate.h"
+
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
@@ -62,12 +64,18 @@
static void (*pmi_start)(void);
static void (*pmi_pal)(void);
+#ifdef FBCON_HAS_ROTATE
+static u32 xres;
+static u32 yres;
+static u32 vxres;
+static u32 vyres;
+#endif
/* --------------------------------------------------------------------- */
static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
- int offset;
+ int offset, depth = (var->bits_per_pixel + 7)/8;
if (!ypan)
return -EINVAL;
@@ -78,7 +86,19 @@
if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
return -EINVAL;
- offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
+#ifdef FBCON_HAS_ROTATE
+ if (var->vmode & FB_VMODE_ROTATE_CW)
+ offset = ((var->xoffset * info->fix.line_length) +
+ ((var->yres_virtual - (var->yoffset + var->yres))) * depth) / 4;
+ else if (var->vmode & FB_VMODE_ROTATE_CCW)
+ offset = (((var->xres_virtual - (var->xoffset + var->xres)) * info->fix.line_length) +
+ (var->yoffset * depth)) / 4;
+ else if (var->vmode & FB_VMODE_ROTATE_UD)
+ offset = (((var->yres_virtual - (var->yoffset + var->yres)) * info->fix.line_length) +
+ ((var->xres_virtual - (var->xoffset + var->xres))) * depth) / 4;
+ else
+#endif
+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
__asm__ __volatile__(
"call *(%%edi)"
@@ -173,11 +193,43 @@
return 0;
}
+static int vesafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+#ifdef FBCON_HAS_ROTATE
+ u32 vmode;
+
+ vmode = var->vmode;
+ *var = info->var;
+ if (vmode & (FB_VMODE_ROTATE_CW | FB_VMODE_ROTATE_CCW)) {
+ var->xres = yres;
+ var->yres = xres;
+ var->xres_virtual = vyres;
+ var->yres_virtual = vxres;
+ }
+ else {
+ var->xres = xres;
+ var->yres = yres;
+ var->xres_virtual = vxres;
+ var->yres_virtual = vyres;
+ }
+ vmode &= FB_ROTATE_MASK;
+ vmode |= info->var.vmode & ~FB_ROTATE_MASK;
+ var->vmode = vmode;
+#else
+ *var = info->var;
+#endif
+
+ var->xoffset = 0;
+ var->yoffset = 0;
+ return 0;
+}
+
static struct fb_ops vesafb_ops = {
.owner = THIS_MODULE,
.fb_set_var = gen_set_var,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = gen_set_cmap,
+ .fb_check_var = vesafb_check_var,
.fb_setcolreg = vesafb_setcolreg,
.fb_pan_display = vesafb_pan_display,
.fb_fillrect = cfb_fillrect,
@@ -300,6 +352,19 @@
ypan = 0;
}
+#ifdef FBCON_HAS_ROTATE
+ xres = vesafb_defined.xres;
+ yres = vesafb_defined.yres;
+ vxres = vesafb_defined.xres_virtual;
+ vyres = vesafb_defined.yres_virtual;
+ if (vesafb_defined.vmode & (FB_VMODE_ROTATE_CW | FB_VMODE_ROTATE_CCW)) {
+ vesafb_defined.xres = yres;
+ vesafb_defined.yres = xres;
+ vesafb_defined.xres_virtual = vyres;
+ vesafb_defined.yres_virtual = vxres;
+ }
+#endif
+
/* some dummy values for timing to make fbset happy */
vesafb_defined.pixclock = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8;
|
|
From: Antonino D. <ad...@po...> - 2002-09-09 14:22:36
|
The patch (fbset_rotate.diff), which is against fbset-2.1, adds 3 new
options to set the rotation:
fbset -{cw|ccw|ud} {true|false}
Try this with the modified vesafb.
Tony
<<------------------------------------------------------------------>>
diff -Naur fbset-orig/fb.h fbset-2.1/fb.h
--- fbset-orig/fb.h Wed Jun 23 22:09:48 1999
+++ fbset-2.1/fb.h Sat Sep 7 11:28:41 2002
@@ -137,6 +137,11 @@
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_MASK 255
+#define FB_VMODE_ROTATE_CW 0x010000
+#define FB_VMODE_ROTATE_CCW 0x020000
+#define FB_VMODE_ROTATE_UD 0x040000
+#define FB_ROTATE_MASK 0xFF0000
+
#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
diff -Naur fbset-orig/fbset.c fbset-2.1/fbset.c
--- fbset-orig/fbset.c Wed Jun 23 22:11:46 1999
+++ fbset-2.1/fbset.c Sun Sep 8 09:44:19 2002
@@ -89,6 +89,9 @@
static const char *Opt_bcast = NULL;
static const char *Opt_laced = NULL;
static const char *Opt_double = NULL;
+static const char *Opt_cw = NULL;
+static const char *Opt_ccw = NULL;
+static const char *Opt_ud = NULL;
static const char *Opt_move = NULL;
static const char *Opt_step = NULL;
static const char *Opt_modename = NULL;
@@ -126,6 +129,9 @@
{ "-bcast", &Opt_bcast, 1 },
{ "-laced", &Opt_laced, 1 },
{ "-double", &Opt_double, 1 },
+ { "-cw", &Opt_cw, 1 },
+ { "-ccw", &Opt_ccw, 1 },
+ { "-ud", &Opt_ud, 1 },
{ "-move", &Opt_move, 1 },
{ "-step", &Opt_step, 1 },
{ "-rgba", &Opt_rgba, 1 },
@@ -354,6 +360,15 @@
var->vmode = FB_VMODE_DOUBLE;
else
var->vmode = FB_VMODE_NONINTERLACED;
+
+ var->vmode &= ~FB_ROTATE_MASK;
+ if (vmode->cw == TRUE)
+ var->vmode |= FB_VMODE_ROTATE_CW;
+ else if (vmode->ccw == TRUE)
+ var->vmode |= FB_VMODE_ROTATE_CCW;
+ else if (vmode->ud == TRUE)
+ var->vmode |= FB_VMODE_ROTATE_UD;
+
var->vmode |= FB_VMODE_CONUPDATE;
var->red.length = vmode->red.length;
var->red.offset = vmode->red.offset;
@@ -402,6 +417,21 @@
vmode->dblscan = TRUE;
break;
}
+
+ vmode->cw = FALSE;
+ vmode->ccw = FALSE;
+ vmode->ud = FALSE;
+ switch (var->vmode & FB_ROTATE_MASK) {
+ case FB_VMODE_ROTATE_CW:
+ vmode->cw = TRUE;
+ break;
+ case FB_VMODE_ROTATE_CCW:
+ vmode->ccw = TRUE;
+ break;
+ case FB_VMODE_ROTATE_UD:
+ vmode->ud = TRUE;
+ break;
+ }
vmode->red.length = var->red.length;
vmode->red.offset = var->red.offset;
vmode->green.length = var->green.length;
@@ -567,6 +597,12 @@
vmode->laced = atoboolean(Opt_laced);
if (Opt_double)
vmode->dblscan = atoboolean(Opt_double);
+ if (Opt_cw)
+ vmode->cw = atoboolean(Opt_cw);
+ if (Opt_ccw)
+ vmode->ccw = atoboolean(Opt_ccw);
+ if (Opt_ud)
+ vmode->ud = atoboolean(Opt_ud);
if (Opt_grayscale)
vmode->grayscale = atoboolean(Opt_grayscale);
if (Opt_step)
@@ -643,6 +679,12 @@
puts(" laced true");
if (vmode->dblscan)
puts(" double true");
+ if (vmode->cw)
+ puts(" cw true");
+ if (vmode->ccw)
+ puts(" ccw true");
+ if (vmode->ud)
+ puts(" ud true");
if (vmode->nonstd)
printf(" nonstd %u\n", vmode->nonstd);
if (vmode->accel_flags)
@@ -677,6 +719,12 @@
printf(" \"Interlace\"");
if (vmode->dblscan)
printf(" \"DoubleScan\"");
+ if (vmode->cw)
+ printf(" \"Clockwise Rotation\"");
+ if (vmode->ccw)
+ printf(" \"CounterClockwise Rotation\"");
+ if (vmode->ud)
+ printf(" \"180 degree Rotation\"");
if (vmode->hsync)
printf(" \"+HSync\"");
else
@@ -879,6 +927,9 @@
" -bcast <value> : broadcast enable (false or true)\n"
" -laced <value> : interlace enable (false or true)\n"
" -double <value> : doublescan enable (false or true)\n"
+ " -cw <value> : rotate clockwise (false or true)\n"
+ " -ccw <value> : rotate counter clockwise (false or true)\n"
+ " -ud <value> : rotate 180 degrees (false or true)\n"
" -rgba <r,g,b,a> : recommended length of color entries\n"
" -grayscale <value> : grayscale enable (false or true)\n"
" Display positioning:\n"
diff -Naur fbset-orig/fbset.h fbset-2.1/fbset.h
--- fbset-orig/fbset.h Wed Jun 23 22:12:28 1999
+++ fbset-2.1/fbset.h Sat Sep 7 10:39:28 2002
@@ -62,6 +62,9 @@
unsigned extsync : 1;
unsigned bcast : 1;
unsigned laced : 1;
+ unsigned cw : 1;
+ unsigned ccw : 1;
+ unsigned ud : 1;
unsigned dblscan : 1;
unsigned grayscale : 1;
/* scanrates */
diff -Naur fbset-orig/modes.l fbset-2.1/modes.l
--- fbset-orig/modes.l Wed Jun 23 22:09:48 1999
+++ fbset-2.1/modes.l Sat Sep 7 11:37:09 2002
@@ -41,6 +41,9 @@
{ "bcast", BCAST, 0 },
{ "laced", LACED, 0 },
{ "double", DOUBLE, 0 },
+ { "cw", CW, 0 },
+ { "ccw", CCW, 0 },
+ { "ud", UD, 0 },
{ "rgba", RGBA, 0 },
{ "nonstd", NONSTD, 0 },
{ "accel", ACCEL, 0 },
diff -Naur fbset-orig/modes.y fbset-2.1/modes.y
--- fbset-orig/modes.y Wed Jun 23 22:09:48 1999
+++ fbset-2.1/modes.y Sat Sep 7 11:34:39 2002
@@ -41,7 +41,7 @@
%start file
%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC BCAST LACED DOUBLE
- RGBA NONSTD ACCEL GRAYSCALE
+ CW CCW UD RGBA NONSTD ACCEL GRAYSCALE
ENDMODE POLARITY BOOLEAN STRING NUMBER
%%
@@ -94,6 +94,9 @@
| options bcast
| options laced
| options double
+ | options cw
+ | options ccw
+ | options ud
| options rgba
| options nonstd
| options accel
@@ -145,6 +148,24 @@
double : DOUBLE BOOLEAN
{
VideoMode.dblscan = $2;
+ }
+ ;
+
+cw : DOUBLE CW
+ {
+ VideoMode.cw = $2;
+ }
+ ;
+
+ccw : DOUBLE CCW
+ {
+ VideoMode.ccw = $2;
+ }
+ ;
+
+ud : DOUBLE UD
+ {
+ VideoMode.ud = $2;
}
;
|