Re: [PATCH] vo_tdfx_vid.c and vo_xover.c

Alban Bedel <[email protected]>
Newsgroups gmane.comp.video.mplayer.g2.devel
Message-ID <[email protected]>
Hi Arpi,

on Thu, 17 Jul 2003 20:27:14 +0200 you wrote:

New version.
	Albeu

-- 

Everything is controlled by a small evil group
to which, unfortunately, no one we know belongs.

_______________________________________________
MPlayer-G2-dev mailing list
[email protected]
http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev
g2.diff (application/octet-stream, 73.3 KB)
--- /home/alban/MP/g2/cfg-l1.c	Sat Jul  5 22:27:02 2003
+++ /home/alban/MP/g2.dev/cfg-l1.c	Fri Jul 18 13:38:59 2003
@@ -12,6 +12,34 @@
 
 #define CFG_STRING_LIST_SEPARATOR ','
 
+static char* esc_strchr(char* str,char c) {
+  int esc;
+
+  if(!str) return NULL;
+
+  for(esc = 0 ; str[0] ; str++) {
+    if(str[0] == '(') esc++;
+    else if(str[0] == ')') esc--;
+    else if(esc > 0) continue;
+    else if(str[0] == c) break;
+  }
+
+  return str[0] == c ? str : NULL;
+}
+
+static char* esc_strdup(char* str) {
+  int l;
+  if(!str) return NULL;
+  l = strlen(str);
+  if(l < 2) return strdup(str);
+  if(str[0] == '(' && str[l-1] == ')') {
+    char* r = strdup(str+1);
+    r[l-2] = '\0';
+    return r;
+  }
+  return strdup(str);
+}
+
 int mpconfig_parse_param(module_info_t* mod, config_t* cd, config_data_t* cfg, char* param){
 //    int i;
     long tmp_int;
@@ -173,10 +201,11 @@
 	    while(m){
 		module_info_t* mymod=NULL;
 		config_modinfo_t mi_func=cd->priv;
-		char* q=strchr(m,',');
+		char* q=esc_strchr(m,',');
 		char* r;
 		if(q){ *q=0; ++q; }
 		r=strchr(m,'=');
+		if(q && r > q) r = NULL;
 		if(r){ *r=0; ++r; }
 		mymod=mi_func(m); // find module
 		if(!mymod){
@@ -304,9 +333,9 @@
 	mp_msg(MSGT_CFGPARSER, MSGL_ERR, "[%s] this module have no config options\n",mod->name);
 	return CFG_ERR_INVALID;
     }
-    p=subconfig=strdup(subconfig);
+    p=subconfig=esc_strdup(subconfig);
     while(p && *p){
-	q=strchr(p,':');
+	q=esc_strchr(p,':');
 	if(q){ *q=0; ++q; };
 	r=strchr(p,'=');
 	if(r){
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/drivers/tdfx_vid.c	Thu Jul 17 15:40:45 2003
@@ -0,0 +1,1427 @@
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "tdfx_vid.h"
+#include "3dfx.h"
+
+
+#define TDFX_VID_MAJOR 178
+
+MODULE_AUTHOR("Albeu");
+MODULE_DESCRIPTION("A driver for Banshee targeted for video app");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifndef min
+#define min(x,y) (((x)<(y))?(x):(y))
+#endif
+
+static struct pci_dev *pci_dev;
+
+static uint8_t *tdfx_mmio_base = 0;
+static uint32_t tdfx_mem_base = 0;
+static uint32_t tdfx_io_base = 0;
+
+static int tdfx_ram_size = 0;
+
+static int tdfx_vid_in_use = 0;
+
+static drm_agp_t *drm_agp = NULL;
+static agp_kern_info agp_info;
+static agp_memory *agp_mem = NULL;
+
+static __initdata int tdfx_map_io = 1;
+static __initdata unsigned long map_start = 0; //0x7300000;
+static __initdata unsigned long map_max = (10*1024*1024);
+static unsigned long map_base = 0;
+
+static __initdata int use_fifo = 0;
+static uint32_t fifo_offset = 0;
+static uint32_t *fifo = NULL;
+static uint32_t fifo_write_pos = 0;
+static uint32_t fifo_n = FIFO0;
+
+#define FIFO_PAGE_SIZE (TDFX_VID_FIFO_PAGE_SIZE)
+#define FIFO_PAGES 1
+#define FIFO_SIZE (FIFO_PAGE_SIZE*FIFO_PAGES)
+
+MODULE_PARM(tdfx_map_io,"i");
+MODULE_PARM_DESC(tdfx_map_io, "Set to 0 to use the page fault handler (you need to patch agpgart_be.c to allow the mapping in user space)\n");
+MODULE_PARM(map_start,"l");
+MODULE_PARM_DESC(map_start,"Use a block of physical mem instead of the agp arerture.\n");
+MODULE_PARM(map_max,"l");
+MODULE_PARM_DESC(map_max, "Maximum amout of physical memory (in bytes) that can be used\n");
+MODULE_PARM(use_fifo,"i");
+MODULE_PARM_DESC(use_fifo, "Set to one to use AGP fifo instead of PCI access whenever possible\n");
+
+
+static inline u32 tdfx_inl(unsigned int reg) {
+  return readl(tdfx_mmio_base + reg);
+}
+
+static inline void tdfx_outl(unsigned int reg, u32 val) {
+  writel(val,tdfx_mmio_base  + reg);
+}
+
+static inline void banshee_make_room(int size) {
+  while((tdfx_inl(STATUS) & 0x1f) < size);
+}
+ 
+static inline void banshee_wait_idle(void) {
+  int i = 0;
+
+  banshee_make_room(1);
+  tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+
+  while(1) {
+    i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
+    if(i == 3) break;
+  }
+}
+
+static unsigned long get_lfb_size(void) {
+  u32 draminit0 = 0;
+  u32 draminit1 = 0;
+  //  u32 miscinit1 = 0;
+  u32 lfbsize   = 0;
+  int sgram_p     = 0;
+
+  draminit0 = tdfx_inl(DRAMINIT0);  
+  draminit1 = tdfx_inl(DRAMINIT1);
+
+  if ((pci_dev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+      (pci_dev->device == PCI_DEVICE_ID_3DFX_VOODOO3)) {
+    sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+  
+    lfbsize = sgram_p ?
+      (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
+       ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+      16 * 1024 * 1024;
+  } else {
+    /* Voodoo4/5 */
+    u32 chips, psize, banks;
+
+    chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
+    psize = 1 << ((draminit0 & 0x38000000) >> 28);
+    banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
+    lfbsize = chips * psize * banks;
+    lfbsize <<= 20;
+  }
+
+#if 0
+  /* disable block writes for SDRAM (why?) */
+  miscinit1 = tdfx_inl(MISCINIT1);
+  miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+  miscinit1 |= MISCINIT1_CLUT_INV;
+
+  banshee_make_room(1); 
+  tdfx_outl(MISCINIT1, miscinit1);
+#endif
+
+  return lfbsize;
+}
+
+static int tdfx_vid_find_card(void)
+{
+  struct pci_dev *dev = NULL;
+  //  unsigned int card_option;
+
+  if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, NULL)))
+    printk(KERN_INFO "tdfx_vid: Found VOODOO BANSHEE\n");
+  else if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, NULL)))
+    printk(KERN_INFO "tdfx_vid: Found VOODOO 3 \n");
+  else
+    return 0;
+
+  
+  pci_dev = dev;
+
+#if LINUX_VERSION_CODE >= 0x020300
+  tdfx_mmio_base = ioremap_nocache(dev->resource[0].start,1 << 24);
+  tdfx_mem_base =  dev->resource[1].start;
+  tdfx_io_base = dev->resource[2].start;
+#else
+  tdfx_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x4000);
+  tdfx_mem_base =  dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
+  tdfx_io_base = dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK;
+#endif
+  printk(KERN_INFO "tdfx_vid: MMIO at 0x%p\n", tdfx_mmio_base);
+  tdfx_ram_size = get_lfb_size();
+
+  printk(KERN_INFO "tdfx_vid: Found %d MB (%d bytes) of memory\n",
+	 tdfx_ram_size / 1024 / 1024,tdfx_ram_size);
+
+  
+#if 0
+  {
+    int temp;
+    printk("List resources -----------\n");
+    for(temp=0;temp<DEVICE_COUNT_RESOURCE;temp++){
+      struct resource *res=&pci_dev->resource[temp];
+      if(res->flags){
+	int size=(1+res->end-res->start)>>20;
+	printk(KERN_DEBUG "res %d:  start: 0x%X   end: 0x%X  (%d MB) flags=0x%X\n",temp,res->start,res->end,size,res->flags);
+	if(res->flags&(IORESOURCE_MEM|IORESOURCE_PREFETCH)){
+	  if(size>tdfx_ram_size && size<=64) tdfx_ram_size=size;
+	}
+      }
+    }
+  }
+#endif
+
+
+  return 1;
+}
+
+static int agp_init(void) {
+
+  drm_agp = (drm_agp_t*)inter_module_get("drm_agp");
+
+  if(!drm_agp) {
+    printk(KERN_ERR "tdfx_vid: Unable to get drm_agp pointer\n");
+    return 0;
+  }
+
+  if(drm_agp->acquire()) {
+    printk(KERN_ERR "tdfx_vid: Unable to acquire the agp backend\n");
+    drm_agp = NULL;
+    return 0;
+  }
+
+  drm_agp->copy_info(&agp_info);
+#if 0
+  printk(KERN_DEBUG "AGP Version : %d %d\n"
+	 "AGP Mode: %#X\nAperture Base: %p\nAperture Size: %d\n"
+	 "Max memory = %d\nCurrent mem = %d\nCan use perture : %s\n"
+	 "Page mask = %#X\n",
+	 agp_info.version.major,agp_info.version.minor,
+	 agp_info.mode,agp_info.aper_base,agp_info.aper_size,
+	 agp_info.max_memory,agp_info.current_memory,
+	 agp_info.cant_use_aperture ? "no" : "yes",
+	 agp_info.page_mask);
+#endif
+  drm_agp->enable(agp_info.mode);
+
+  
+  printk(KERN_INFO "AGP Enabled\n");
+
+  return 1;
+}
+    
+static void agp_close(void) {
+
+  if(!drm_agp) return;
+
+  if(agp_mem) {
+    drm_agp->unbind_memory(agp_mem);
+    drm_agp->free_memory(agp_mem);
+    agp_mem = NULL;
+  }
+      
+
+  drm_agp->release();
+  inter_module_put("drm_agp");
+}
+
+static int write_fifo(void* data,u32 size);
+
+static int agp_move(tdfx_vid_agp_move_t* m) {
+  u32 src = 0;
+  u32 src_h,src_l;
+
+  if(!(agp_mem||map_start))
+    return (-EAGAIN);
+
+  if(m->move2 > 3) {
+    printk(KERN_DEBUG "tdfx_vid: AGP move invalid destination %d\n",
+	   m->move2);
+    return (-EAGAIN);
+  }
+
+  if(map_start)
+    src =  map_start + m->src;
+  else
+    src =  agp_info.aper_base +  m->src;
+
+  src_l = (u32)src;
+  src_h = (m->width | (m->src_stride << 14)) & 0x0FFFFFFF;
+
+  if(use_fifo && fifo) {
+    u32 cmd[5] = {
+      //       transfert size on 20bits             dst type      cmd
+      ((m->src_stride*m->height) & 0xFFFFF) << 5 | (m->move2 << 3) | 0x6,
+      src_l,
+      src_h,
+      m->dst & 0x3FFFFFF, // 26 bits
+      m->dst_stride & 0x7FFF // 15 bits
+    };
+    return write_fifo(cmd,5*4);
+  }
+      
+
+  //  banshee_wait_idle();
+  banshee_make_room(6);
+  tdfx_outl(AGPHOSTADDRESSHIGH,src_h);
+  tdfx_outl(AGPHOSTADDRESSLOW,src_l);
+
+  tdfx_outl(AGPGRAPHICSADDRESS, m->dst);
+  tdfx_outl(AGPGRAPHICSSTRIDE, m->dst_stride);
+  tdfx_outl(AGPREQSIZE,m->src_stride*m->height);
+
+  tdfx_outl(AGPMOVECMD,m->move2 << 3);
+  banshee_wait_idle();
+
+  return 0;
+}
+
+static int open_fifo(u32 offset,ssize_t pages) {
+  u32 addr = offset; //agp_info.aper_base + offset;
+  u32 size;
+
+  size = tdfx_inl(CMDBASESIZE0 + fifo_n);
+  if(size & 0x100) {
+    printk(KERN_INFO "tdfx_vid: fifo alredy in use\n");
+    return 0;
+  }
+
+  if((addr >> 12)<<12 != addr) {
+    printk(KERN_INFO "tdfx_vid: unaligned fifo start\n");
+    return 0;
+  }
+
+  size = ((pages-1) & 0xFF) | 0x700; // fifo on, in agp mem, disable hole cnt
+
+  banshee_wait_idle();
+  banshee_make_room(9);
+  // The adresse is in 4KB pages (2^12 bits)
+  // AGP adress are 36 bits and this one is 24 bits => 36-24=12
+  // So it probably need the upper 20 bits of our 32 bits address
+  tdfx_outl(CMDBASEADDR0 + fifo_n,addr >> 12);
+  tdfx_outl(CMDBUMP0+fifo_n,0);
+  // But these need the lower 32 bits of the AGP address
+  tdfx_outl(CMDRDPTRL0 + fifo_n, addr);
+  // And here the upper 4 bit of the AGP adresse
+  // For it's then 0
+  tdfx_outl(CMDRDPTRH0 + fifo_n, 0);
+  // A 25 bits adresse
+  // It need the -4
+  tdfx_outl(CMDAMIN0 + fifo_n, (addr - 4) & 0x1FFFFFF);
+  tdfx_outl(CMDAMAX0 + fifo_n, (addr - 4) & 0x1FFFFFF);
+  tdfx_outl(CMDFIFODEPTH0 + fifo_n, 0);
+  tdfx_outl(CMDHOLECNT0 + fifo_n, 0);
+  tdfx_outl(CMDBASESIZE0 + fifo_n,size);
+
+  banshee_wait_idle();
+  
+  return 1;
+}
+
+static int write_fifo(void* data,u32 size) {
+  u32 read_pos;
+  u32 max_size = 0;
+
+  if(size > FIFO_SIZE) {
+    printk(KERN_INFO "tdfx_vid: Too big command for the fifo\n");
+    return 0;
+  }
+
+  if((size/4)*4 != size) {
+    printk(KERN_INFO "tdfx_vid: Got command with unaligned size !!!\n");
+    return 0;
+  }
+
+  // Wait until we got enough space
+  while(max_size < size) {
+    read_pos = tdfx_inl(CMDRDPTRL0+fifo_n) - agp_info.aper_base - fifo_offset;
+    if(read_pos <= fifo_write_pos)
+      max_size = FIFO_SIZE - (fifo_write_pos - read_pos);
+    else
+      max_size = FIFO_SIZE - (read_pos - fifo_write_pos);
+  }
+
+  if(fifo_write_pos + size >  FIFO_SIZE) {
+    memcpy_toio(fifo + fifo_write_pos, data,FIFO_SIZE - fifo_write_pos);
+    memcpy_toio(fifo, data + (FIFO_SIZE - fifo_write_pos),
+		size - (FIFO_SIZE - fifo_write_pos));
+    fifo_write_pos = size - (FIFO_SIZE - fifo_write_pos);
+  } else {
+    memcpy_toio(fifo + fifo_write_pos, data,size);
+    fifo_write_pos += size % FIFO_SIZE;
+  }
+
+  banshee_make_room(1);
+  tdfx_outl(CMDBUMP0+fifo_n ,size/4);
+  return 1;
+}
+
+static void close_fifo(void) {
+  u32 size = tdfx_inl(CMDBASESIZE0+fifo_n);
+
+  size &= ~0x100;
+  banshee_wait_idle();
+  tdfx_outl(CMDBASESIZE0+fifo_n,size);
+  banshee_wait_idle();
+}
+
+
+static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) {
+  u32 in;
+
+  cfg->version = TDFX_VID_VERSION;
+  cfg->ram_size = tdfx_ram_size;
+
+  in = tdfx_inl(VIDSCREENSIZE);
+  cfg->screen_width = in & 0xFFF;
+  cfg->screen_height = (in >> 12) & 0xFFF;
+  in = (tdfx_inl(VIDPROCCFG)>> 18)& 0x7;
+  switch(in) {
+  case 0:
+    cfg->screen_format = TDFX_VID_FORMAT_BGR8;
+    break;
+  case 1:
+    cfg->screen_format = TDFX_VID_FORMAT_BGR16;
+    break;
+  case 2:
+    cfg->screen_format = TDFX_VID_FORMAT_BGR24;
+    break;
+  case 3:
+    cfg->screen_format = TDFX_VID_FORMAT_BGR32;
+    break;
+  default:
+    printk(KERN_INFO "tdfx_vid: unknown screen format %d\n",in);
+    cfg->screen_format = 0;
+    break;
+  }
+  cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE) & 0x7FFF;
+  cfg->screen_start = tdfx_inl(VIDDESKSTART);
+  cfg->triple_buffering = (tdfx_inl(DRAMINIT1) & (1<<11))>>11;
+}
+
+inline static u32 tdfx_vid_make_format(int src,u16 stride,u32 fmt) {
+  u32 r = stride & 0xFFF3;
+  u32 tdfx_fmt = 0;
+
+  // src and dest formats
+  switch(fmt) {
+  case TDFX_VID_FORMAT_BGR8:
+    tdfx_fmt = 1;
+    break;
+  case TDFX_VID_FORMAT_BGR16:
+    tdfx_fmt = 3;
+    break;
+  case TDFX_VID_FORMAT_BGR24:
+    tdfx_fmt = 4;
+    break;
+  case TDFX_VID_FORMAT_BGR32:
+    tdfx_fmt = 5;
+    break;
+  }
+
+  if(!src && !tdfx_fmt) {
+    printk(KERN_INFO "tdfx_vid: Invalid destination format %#X\n",fmt);
+    return 0;
+  }
+
+  if(src && !tdfx_fmt) {
+    // src only format
+    switch(fmt){
+    case TDFX_VID_FORMAT_BGR1:
+      tdfx_fmt = 0;
+      break;
+    case TDFX_VID_FORMAT_BGR15: // To check
+      tdfx_fmt = 2;
+      break;
+    case TDFX_VID_FORMAT_YUY2:
+      tdfx_fmt = 8;
+      break;
+    case TDFX_VID_FORMAT_UYVY:
+      tdfx_fmt = 9;
+      break;
+    default:
+      printk(KERN_INFO "tdfx_vid: Invalid source format %#X\n",fmt);
+      return 0;
+    }
+  }
+
+  r |= tdfx_fmt << 16;
+
+  return r;
+}
+
+static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
+  u32 src_fmt,dst_fmt,cmd = 2;
+  u32 cmin,cmax,srcbase,srcxy,srcfmt,srcsize;
+  u32 dstbase,dstxy,dstfmt,dstsize = 0;
+  u32 cmd_extra = 0,src_ck[2],dst_ck[2],rop123=0;
+  
+  //printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format);
+  src_fmt = tdfx_vid_make_format(1,blit->src_stride,blit->src_format);
+  if(!src_fmt)
+    return 0;
+  //printk(KERN_INFO "tdfx_vid: Make dst fmt 0x%x\n", blit->dst_format);
+  dst_fmt = tdfx_vid_make_format(0,blit->dst_stride,blit->dst_format);
+  if(!dst_fmt)
+    return 0;
+  blit->colorkey &= 0x3;
+  // Be nice if user just want a simple blit
+  if((!blit->colorkey) && (!blit->rop[0]))
+    blit->rop[0] = TDFX_VID_ROP_COPY;
+  // No stretch : fix me the cmd should be 1 but it
+  // doesn't work. Maybe some other regs need to be set
+  // as non-stretch blit have more options
+  if(((!blit->dst_w) && (!blit->dst_h)) || 
+     ((blit->dst_w == blit->src_w) && (blit->dst_h == blit->src_h)))
+    cmd = 2;
+  
+  // Save the regs otherwise fb get crazy
+  // we can perhaps avoid some ...
+  banshee_wait_idle();
+  cmin = tdfx_inl(CLIP0MIN);
+  cmax = tdfx_inl(CLIP0MAX);
+  srcbase = tdfx_inl(SRCBASE);
+  srcxy = tdfx_inl(SRCXY);
+  srcfmt = tdfx_inl(SRCFORMAT);
+  srcsize = tdfx_inl(SRCSIZE);
+  dstbase = tdfx_inl(DSTBASE);
+  dstxy = tdfx_inl(DSTXY);
+  dstfmt = tdfx_inl(DSTFORMAT);
+  if(cmd == 2)
+    dstsize = tdfx_inl(DSTSIZE);
+  if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
+    src_ck[0] = tdfx_inl(SRCCOLORKEYMIN);
+    src_ck[1] = tdfx_inl(SRCCOLORKEYMAX);
+    tdfx_outl(SRCCOLORKEYMIN,blit->src_colorkey[0]);
+    tdfx_outl(SRCCOLORKEYMAX,blit->src_colorkey[1]);
+  }
+  if(blit->colorkey & TDFX_VID_DST_COLORKEY) {
+    dst_ck[0] = tdfx_inl(DSTCOLORKEYMIN);
+    dst_ck[1] = tdfx_inl(DSTCOLORKEYMAX);
+    tdfx_outl(SRCCOLORKEYMIN,blit->dst_colorkey[0]);
+    tdfx_outl(SRCCOLORKEYMAX,blit->dst_colorkey[1]);   
+  }
+  if(blit->colorkey) {
+    cmd_extra = tdfx_inl(COMMANDEXTRA_2D);
+    rop123 = tdfx_inl(ROP123);
+    tdfx_outl(COMMANDEXTRA_2D, blit->colorkey);
+    tdfx_outl(ROP123,(blit->rop[1] | (blit->rop[2] << 8) | blit->rop[3] << 16));
+    
+  }
+  // Get rid of the clipping at the moment
+  tdfx_outl(CLIP0MIN,0);
+  tdfx_outl(CLIP0MAX,0x0fff0fff);
+
+  // Setup the src
+  tdfx_outl(SRCBASE,blit->src & 0x00FFFFFF);
+  tdfx_outl(SRCXY,XYREG(blit->src_x,blit->src_y));
+  tdfx_outl(SRCFORMAT,src_fmt);
+  tdfx_outl(SRCSIZE,XYREG(blit->src_w,blit->src_h));
+
+  // Setup the dst
+  tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF);
+  tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y));
+  tdfx_outl(DSTFORMAT,dst_fmt);
+  if(cmd == 2)
+    tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h));
+
+  // Send the command
+  tdfx_outl(COMMAND_2D,cmd | 0x100 | (blit->rop[0] << 24));
+  banshee_wait_idle();
+
+  // Now restore the regs to make fb happy
+  tdfx_outl(CLIP0MIN, cmin);
+  tdfx_outl(CLIP0MAX, cmax);
+  tdfx_outl(SRCBASE, srcbase);
+  tdfx_outl(SRCXY, srcxy);
+  tdfx_outl(SRCFORMAT, srcfmt);
+  tdfx_outl(SRCSIZE, srcsize);
+  tdfx_outl(DSTBASE, dstbase);
+  tdfx_outl(DSTXY, dstxy);
+  tdfx_outl(DSTFORMAT, dstfmt);
+  if(cmd == 2)
+    tdfx_outl(DSTSIZE, dstsize);
+  if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
+    tdfx_outl(SRCCOLORKEYMIN,src_ck[0]);
+    tdfx_outl(SRCCOLORKEYMAX,src_ck[1]);
+  }
+  if(blit->colorkey & TDFX_VID_DST_COLORKEY) {
+    tdfx_outl(SRCCOLORKEYMIN,dst_ck[0]);
+    tdfx_outl(SRCCOLORKEYMAX,dst_ck[1]);   
+  }
+  if(blit->colorkey) {
+    tdfx_outl(COMMANDEXTRA_2D,cmd_extra);
+    tdfx_outl(ROP123,rop123);
+  }
+  return 1;
+}
+
+static int tdfx_vid_set_yuv(unsigned long arg) {
+  tdfx_vid_yuv_t yuv;
+
+  if(copy_from_user(&yuv,(tdfx_vid_yuv_t*)arg,sizeof(tdfx_vid_yuv_t))) {
+    printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
+    return(-EFAULT); 
+  }
+  banshee_make_room(2);
+  tdfx_outl(YUVBASEADDRESS,yuv.base & 0x01FFFFFF);
+  tdfx_outl(YUVSTRIDE, yuv.stride & 0x3FFF);
+  
+  banshee_wait_idle();
+  
+  return 0;
+}
+
+static int tdfx_vid_get_yuv(unsigned long arg) {
+  tdfx_vid_yuv_t yuv;
+
+  yuv.base = tdfx_inl(YUVBASEADDRESS) & 0x01FFFFFF;
+  yuv.stride = tdfx_inl(YUVSTRIDE) & 0x3FFF;
+
+  if(copy_to_user((tdfx_vid_yuv_t*)arg,&yuv,sizeof(tdfx_vid_yuv_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
+      return(-EFAULT); 
+  }
+
+  return 0;
+}
+
+static int tdfx_vid_set_overlay(unsigned long arg) {
+  tdfx_vid_overlay_t ov;
+  uint32_t screen_w,screen_h;
+  uint32_t vidcfg,stride,vidbuf;
+  int disp_w,disp_h;
+
+  if(copy_from_user(&ov,(tdfx_vid_overlay_t*)arg,sizeof(tdfx_vid_overlay_t))) {
+    printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
+    return(-EFAULT); 
+  }
+
+  if(ov.dst_y < 0) {
+    int shift;
+    if(-ov.dst_y >= ov.src_height) {
+      printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
+      return(-EFAULT);
+    }
+    shift = (-ov.dst_y)/(double)ov.dst_height*ov.src_height;
+    ov.src[0] += shift*ov.src_stride;
+    ov.src_height -= shift;
+    ov.dst_height += ov.dst_y;
+    ov.dst_y = 0;
+  }
+
+  if(ov.dst_x < 0) {
+    int shift;
+    if(-ov.dst_x >= ov.src_width) {
+      printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
+      return(-EFAULT);
+    }
+    shift = (-ov.dst_x)/(double)ov.dst_width*ov.src_width;
+    shift = ((shift+3)/2)*2;
+    ov.src[0] += shift*2;
+    ov.src_width -= shift;
+    ov.dst_width += ov.dst_x;
+    ov.dst_x = 0;
+  }
+
+  vidcfg = tdfx_inl(VIDPROCCFG);
+  // clear the overlay fmt
+  vidcfg &= ~(7 << 21);
+  switch(ov.format) {
+  case TDFX_VID_FORMAT_BGR15:
+    vidcfg |= (1 << 21);
+    break;
+  case TDFX_VID_FORMAT_BGR16:
+    vidcfg |= (7 << 21);
+    break;
+  case TDFX_VID_FORMAT_YUY2:
+    vidcfg |= (5 << 21);
+    break;
+  case TDFX_VID_FORMAT_UYVY:
+    vidcfg |= (6 << 21);
+    break;
+  default:
+    printk(KERN_DEBUG "tdfx_vid: Invalid overlay fmt 0x%x\n",ov.format);
+    return (-EFAULT); 
+  }
+
+  // YUV422 need 4 bytes aligned stride and address
+  if((ov.format == TDFX_VID_FORMAT_YUY2 ||
+      ov.format == TDFX_VID_FORMAT_UYVY)) {
+    if((ov.src_stride & ~0x3) != ov.src_stride) {
+      printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned stride %d\n",ov.src_stride);
+      return(-EFAULT);
+    }
+    if((ov.src[0] & ~0x3) != ov.src[0] || (ov.src[1] & ~0x3) != ov.src[1]){
+      printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned address 0x%x 0x%x\n",ov.src[0],ov.src[1]);
+      return(-EFAULT);
+    }
+  }
+
+  // Now we have a good input format
+  // but first get the screen size to check a bit
+  // if the size/position is valid
+  screen_w = tdfx_inl(VIDSCREENSIZE);
+  screen_h = (screen_w >> 12) & 0xFFF;
+  screen_w &= 0xFFF;
+  disp_w =  ov.dst_x + ov.dst_width >= screen_w ?
+    screen_w - ov.dst_x : ov.dst_width;
+  disp_h =  ov.dst_y + ov.dst_height >= screen_h ?
+    screen_h - ov.dst_y : ov.dst_height;
+
+  if(ov.dst_x >= screen_w || ov.dst_y >= screen_h ||
+     disp_h <= 0 || disp_h > screen_h || disp_w <= 0 || disp_w > screen_w) {
+    printk(KERN_DEBUG "tdfx_vid: Invalid overlay dimension and/or position\n");
+    return (-EFAULT); 
+  }
+  // Setup the vidproc
+  // H scaling
+  if(ov.src_width < ov.dst_width)
+    vidcfg |= (1<<14);
+  else
+    vidcfg &= ~(1<<14);
+  // V scaling
+  if(ov.src_height < ov.dst_height)
+    vidcfg |= (1<<15);
+  else
+    vidcfg &= ~(1<<15);
+  // Filtering can only be used in 1x mode
+  if(!(vidcfg | (1<<26)))
+    vidcfg |= (3<<16);
+  else
+    vidcfg &= ~(3<<16);
+  // disable overlay stereo mode
+  vidcfg &= ~(1<<2);
+  // Colorkey on/off
+  if(ov.use_colorkey) {
+    // Colorkey inversion
+    if(ov.invert_colorkey)
+      vidcfg |= (1<<6);
+    else
+      vidcfg &= ~(1<<6);
+    vidcfg |= (1<<5);
+  } else
+    vidcfg &= ~(1<<5);
+  // Overlay isn't VidIn
+  vidcfg &= ~(1<<9);
+  // vidcfg |= (1<<8);
+  tdfx_outl(VIDPROCCFG,vidcfg);
+
+  // Start coord
+  //printk(KERN_DEBUG "tdfx_vid: start %dx%d\n",ov.dst_x & 0xFFF,ov.dst_y & 0xFFF);
+  tdfx_outl(VIDOVRSTARTCRD,(ov.dst_x & 0xFFF)|((ov.dst_y & 0xFFF)<<12));
+  // End coord
+  tdfx_outl(VIDOVRENDCRD, ((ov.dst_x + disp_w-1) & 0xFFF)|
+	    (((ov.dst_y + disp_h-1) & 0xFFF)<<12));
+  // H Scaling
+  tdfx_outl(VIDOVRDUDX,( ((u32)ov.src_width) << 20) / ov.dst_width);
+  // Src offset and width (in bytes)
+  tdfx_outl(VIDOVRDUDXOFF,((ov.src_width<<1) & 0xFFF) << 19);
+  // V Scaling
+  tdfx_outl(VIDOVRDVDY, ( ((u32)ov.src_height) << 20) / ov.dst_height);
+  //else
+  //  tdfx_outl(VIDOVRDVDY,0);
+  // V Offset
+  tdfx_outl(VIDOVRDVDYOFF,0);
+  // Overlay stride
+  stride = tdfx_inl(VIDDESKSTRIDE) & 0xFFFF;
+  tdfx_outl(VIDDESKSTRIDE,stride | (((u32)ov.src_stride) << 16));
+  // Buffers address
+  tdfx_outl(LEFTOVBUF, ov.src[0]);
+  //tdfx_outl(RIGHTOVBUF, ov.src[1]);
+
+  // Send a swap buffer cmd if we are not on one of the 2 buffers
+  //  vidbuf = tdfx_inl(VIDCUROVRSTART);
+  //if(vidbuf != ov.src[0] && vidbuf != ov.src[1]) {
+  tdfx_outl(SWAPPENDING,1);
+  tdfx_outl(SWAPBUFCMD, 0);
+  //}
+  //printk(KERN_DEBUG "tdfx_vid: Buf0=0x%x Buf1=0x%x Current=0x%x\n",
+  //	 ov.src[0],ov.src[1],tdfx_inl(VIDCUROVRSTART));
+  // Colorkey
+  if(ov.use_colorkey) {
+    tdfx_outl(VIDCHRMIN,ov.colorkey[0]);
+    tdfx_outl(VIDCHRMAX,ov.colorkey[1]);
+  }
+
+  return 0;
+}
+
+static int tdfx_vid_overlay_swap(unsigned long arg) {
+  tdfx_vid_swap_t swap;
+  int s = 0;
+
+  if(copy_from_user(&swap,(tdfx_vid_swap_t*)arg,sizeof(tdfx_vid_swap_t))) {
+    printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
+    return(-EFAULT); 
+  }
+
+  if(swap.sync) {
+    s = 1;
+    s |= (swap.sync-1)<<1;
+  }
+
+  banshee_make_room(3);
+  tdfx_outl(LEFTOVBUF, swap.buffer);
+  tdfx_outl(SWAPPENDING,1);
+  tdfx_outl(SWAPBUFCMD, s);
+  //banshee_wait_idle();
+
+  return 0;
+}
+  
+
+static int tdfx_vid_overlay_on(void) {
+  uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
+  //return 0;
+  if(vidcfg & (1<<8)) { // Overlay is alredy on
+    //printk(KERN_DEBUG "tdfx_vid: Overlay is alredy on\n");
+    return (-EFAULT); 
+  }
+  vidcfg |= (1<<8);
+  tdfx_outl(VIDPROCCFG,vidcfg);
+  return 0;
+}
+
+static int tdfx_vid_overlay_off(void) {
+  uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
+
+  if(vidcfg & (1<<8)) {
+    vidcfg &= ~(1<<8);
+    tdfx_outl(VIDPROCCFG,vidcfg);
+    return 0;
+  }
+
+  printk(KERN_DEBUG "tdfx_vid: Overlay is alredy off\n");
+  return (-EFAULT); 
+}
+
+static int tdfx_vid_get_3d_lfb(unsigned long arg) {
+  tdfx_vid_3d_lfb_t lfb;
+  u32 mode = tdfx_inl(LFBMODE);
+  
+  // Parse the write format
+  lfb.format = 0;
+  switch(mode & 0xF) {
+  case 0: // RGB 16
+    switch((mode & 0x600) >> 10) {
+    case 0:
+    case 2:
+      lfb.format = TDFX_VID_FORMAT_BGR16;
+      break;
+    case 1:
+    case 3:
+      lfb.format = TDFX_VID_FORMAT_RGB16;
+      break;
+    }
+    break;
+  case 1: // RGB 15
+    switch((mode & 0x600) >> 10) {
+    case 0:
+      lfb.format = TDFX_VID_FORMAT_BGR15;
+      break;
+    case 1:
+      lfb.format = TDFX_VID_FORMAT_RGB15;
+      break;
+    case 2:
+      lfb.format = TDFX_VID_FORMAT_15BGR;
+      break;
+    case 3:
+      lfb.format = TDFX_VID_FORMAT_15RGB;
+      break;
+    }
+    break;
+  case 2: // ARGB 16
+    switch((mode & 0x600) >> 10) {
+    case 0:
+      lfb.format = TDFX_VID_FORMAT_BGRA16;
+      break;
+    case 1:
+      lfb.format = TDFX_VID_FORMAT_RGBA16;
+      break;
+    case 2:
+      lfb.format = TDFX_VID_FORMAT_ABGR16;
+      break;
+    case 3:
+      lfb.format = TDFX_VID_FORMAT_ARGB16;
+      break;
+    }
+    break;
+  case 4: // RGB 24
+    switch((mode & 0x600) >> 10) {
+    case 0:
+      lfb.format = TDFX_VID_FORMAT_BGR24;
+      break;
+    case 1:
+      lfb.format = TDFX_VID_FORMAT_RGB24;
+      break;
+    case 2:
+      lfb.format = TDFX_VID_FORMAT_24BGR;
+      break;
+    case 3:
+      lfb.format = TDFX_VID_FORMAT_24RGB;
+      break;
+    }
+    break;
+  case 5: // ARGB 32
+     switch((mode & 0x600) >> 10) {
+    case 0:
+      lfb.format = TDFX_VID_FORMAT_BGRA32;
+      break;
+    case 1:
+      lfb.format = TDFX_VID_FORMAT_RGBA32;
+      break;
+    case 2:
+      lfb.format = TDFX_VID_FORMAT_ABGR32;
+      break;
+    case 3:
+      lfb.format = TDFX_VID_FORMAT_ARGB32;
+      break;
+    }
+    break;
+    // TODO add the depth stuff
+  }
+
+  lfb.color_buf = tdfx_inl(COLBUFFERADDR);
+  lfb.color_stride = tdfx_inl(COLBUFFERSTRIDE);
+
+  lfb.aux_buf = tdfx_inl(AUXBUFFERADDR);
+  lfb.aux_stride = tdfx_inl(AUXBUFFERSTRIDE);
+  lfb.flags = mode & 0xF900;
+
+  lfb.mode = tdfx_inl(FBZMODE);
+
+  if(copy_to_user((tdfx_vid_3d_lfb_t*)arg,&lfb,sizeof(tdfx_vid_3d_lfb_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
+      return(-EFAULT); 
+  }
+  return 0;
+}
+static int tdfx_vid_set_3d_lfb(unsigned long arg) {
+  tdfx_vid_3d_lfb_t lfb;
+  u32 mode = 0;
+
+  if(copy_from_user(&lfb,(tdfx_vid_3d_lfb_t*)arg,sizeof(tdfx_vid_3d_lfb_t))) {
+    printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+    return(-EFAULT); 
+  }
+
+  if((lfb.color_buf & ~0xF) != lfb.color_buf) {
+    printk(KERN_DEBUG "tdfx_vid: color buffer address must be 16-bytes aligned\n");
+    return(-EFAULT); 
+  }
+  if((lfb.color_stride & ~0xF) != lfb.color_stride) {
+    printk(KERN_DEBUG "tdfx_vid: color buffer stride must be 16-bytes aligned\n");
+    return(-EFAULT); 
+  }
+  if((lfb.aux_buf & ~0xF) != lfb.aux_buf) {
+    printk(KERN_DEBUG "tdfx_vid: aux buffer address must be 16-bytes aligned\n");
+    return(-EFAULT); 
+  }
+  if((lfb.aux_stride & ~0xF) != lfb.aux_stride) {
+    printk(KERN_DEBUG "tdfx_vid: aux buffer stride must be 16-bytes aligned\n");
+    return(-EFAULT); 
+  }
+
+  switch(lfb.format) {
+  case TDFX_VID_FORMAT_BGR16:
+    break;
+  case TDFX_VID_FORMAT_RGB16:
+    mode = 1 << 9;
+    break;
+  case TDFX_VID_FORMAT_BGRA32:
+  case TDFX_VID_FORMAT_ABGR32:
+  case TDFX_VID_FORMAT_RGBA32:
+  case TDFX_VID_FORMAT_ARGB32:
+    mode = 5;
+    if(lfb.format >> 24 == 'R')
+      mode |= (1 << 9);
+    else if((lfb.format >> 24) == 'A' && ((lfb.format>>8) & 0xFF) == 'R')
+      mode |= (2 << 9);
+    else if((lfb.format >> 24) == 'A' && ((lfb.format>>8) & 0xFF) == 'B')
+      mode |= (3 << 9);
+    break;
+  default:
+    printk(KERN_DEBUG "tdfx_vid: Unsupported format (atm)\n");
+    return(-EFAULT); 
+  }
+
+  mode |= (lfb.flags & 0xF900);
+  tdfx_outl(LFBMODE,mode);
+  mode = tdfx_inl(FBZCOLORPATH);
+  mode &= ~0xF;
+  tdfx_outl(FBZCOLORPATH,mode);
+
+  tdfx_outl(COLBUFFERADDR,lfb.color_buf);
+  // bit 15 can be used to enable titled
+  tdfx_outl(COLBUFFERSTRIDE,lfb.color_stride & 0x3FFF);
+  tdfx_outl(AUXBUFFERADDR,lfb.aux_buf);
+  // bit 15 can be used to enable titled
+  tdfx_outl(AUXBUFFERSTRIDE,lfb.aux_stride & 0x3FFF);
+  tdfx_outl(FBZMODE,lfb.mode);
+  
+
+  return 0;
+}
+
+
+static int tdfx_vid_get_alpha(unsigned long arg) {
+  tdfx_vid_alpha_t alpha;
+  u32 reg = tdfx_inl(ALPHAMODE);
+
+  alpha.enable_func = reg & 1;
+  alpha.func = (reg >> 1) & 0x7;
+  alpha.enable_blend = (reg >> 4) & 1;
+  alpha.rgb_src = (reg >> 8) & 0xf;
+  alpha.rgb_dst = (reg >> 12) & 0xf;
+  alpha.alpha_src = (reg >> 16) & 0xf;
+  alpha.alpha_dst = (reg >> 20) & 0xf;
+  alpha.ref = reg >> 24;
+
+  if(copy_to_user((tdfx_vid_alpha_t*)arg,&alpha,sizeof(tdfx_vid_alpha_t))) {
+    printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
+    return(-EFAULT); 
+  }
+  return 0;
+  
+}
+
+static int tdfx_vid_set_alpha(unsigned long arg) {
+  tdfx_vid_alpha_t alpha;
+  u32 reg = tdfx_inl(ALPHAMODE);
+
+  if(copy_from_user(&alpha,(tdfx_vid_alpha_t*)arg,sizeof(tdfx_vid_alpha_t))) {
+    printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+    return(-EFAULT); 
+  }
+
+  if(alpha.enable_func) {
+    reg &= ~0xE;
+    reg |= 1 | (alpha.func << 1);
+  } else
+    reg &= ~1;
+
+  if(alpha.enable_blend) {
+    reg &= ~0xFFFF00;
+    reg |= (1 << 4) | (alpha.rgb_src >> 8) | (alpha.rgb_dst >> 12) |
+      (alpha.alpha_src >> 16) | (alpha.alpha_dst >> 20);
+  } else
+    reg &= ~0x100;
+
+  reg &= 0xFFFFFF;
+  reg |= alpha.ref << 24;
+
+  tdfx_outl(ALPHAMODE,reg);
+
+  return 0;
+}  
+    
+
+static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+  tdfx_vid_agp_move_t move;
+  tdfx_vid_config_t cfg;
+  tdfx_vid_blit_t blit;
+  u32 int32;
+
+  switch(cmd) {
+  case TDFX_VID_AGP_MOVE:
+    if(copy_from_user(&move,(tdfx_vid_agp_move_t*)arg,sizeof(tdfx_vid_agp_move_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+      return(-EFAULT); 
+    }
+    return agp_move(&move);
+#if 0
+  case TDFX_VID_BUMP0:
+    if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) {
+      printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+      return(-EFAULT); 
+    }
+    return bump_fifo(int16);
+#endif
+  case TDFX_VID_BLIT:
+    if(copy_from_user(&blit,(tdfx_vid_blit_t*)arg,sizeof(tdfx_vid_blit_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+      return(-EFAULT); 
+    }
+    if(!tdfx_vid_blit(&blit)) {
+      printk(KERN_INFO "tdfx_vid: Blit failed\n");
+      return(-EFAULT); 
+    }
+    return 0;
+  case TDFX_VID_GET_CONFIG:
+    if(copy_from_user(&cfg,(tdfx_vid_config_t*)arg,sizeof(tdfx_vid_config_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+      return(-EFAULT); 
+    }
+    tdfx_vid_get_config(&cfg);
+    if(copy_to_user((tdfx_vid_config_t*)arg,&cfg,sizeof(tdfx_vid_config_t))) {
+      printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
+      return(-EFAULT); 
+    }
+    return 0;
+  case TDFX_VID_SET_YUV:
+    return tdfx_vid_set_yuv(arg);
+  case TDFX_VID_GET_YUV:
+    return tdfx_vid_get_yuv(arg);
+  case TDFX_VID_SET_OVERLAY:
+    return tdfx_vid_set_overlay(arg);
+  case TDFX_VID_OVERLAY_SWAP:
+    return tdfx_vid_overlay_swap(arg);
+  case TDFX_VID_OVERLAY_ON:
+    return tdfx_vid_overlay_on();
+  case TDFX_VID_OVERLAY_OFF:
+    return tdfx_vid_overlay_off();
+  case TDFX_VID_DUMP_REG:
+    if(copy_from_user(&int32,(u32*)arg,sizeof(u32))) {
+      printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
+      return(-EFAULT); 
+    }
+    int32 = tdfx_inl(int32);
+    if(copy_to_user((u32*)arg,&int32,sizeof(u32))) {
+      printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
+      return(-EFAULT); 
+    }
+    return 0;
+  case TDFX_VID_GET_3D_LFB:
+    return tdfx_vid_get_3d_lfb(arg);
+  case TDFX_VID_SET_3D_LFB:
+    return tdfx_vid_set_3d_lfb(arg);
+  case TDFX_VID_GET_ALPHA:
+    return tdfx_vid_get_alpha(arg);
+  case TDFX_VID_SET_ALPHA:
+    return tdfx_vid_set_alpha(arg);
+  default:
+    printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd);
+    return (-EINVAL);
+  } 
+  return 0;
+}
+
+
+
+static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+
+	return 0;
+}
+
+static void tdfx_vid_mopen(struct vm_area_struct *vma) {
+  int i;
+  struct page *page;
+  unsigned long phys;
+
+  printk(KERN_DEBUG "tdfx_vid: mopen\n");
+  
+  for(i = 0 ; i < agp_mem->page_count ; i++) {
+    phys = agp_mem->memory[i] & ~(0x00000fff);
+    page = virt_to_page(phys_to_virt(phys));
+    if(!page) {
+      printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
+      return;
+    }
+    get_page(page);
+  }
+  MOD_INC_USE_COUNT;
+}
+
+static void tdfx_vid_mclose(struct vm_area_struct *vma)  {
+  int i;
+  struct page *page;
+  unsigned long phys;
+
+  printk(KERN_DEBUG "tdfx_vid: mclose\n");
+
+  for(i = 0 ; i < agp_mem->page_count ; i++) {
+    phys = agp_mem->memory[i] & ~(0x00000fff);
+    page = virt_to_page(phys_to_virt(phys));
+    if(!page) {
+      printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
+      return;
+    }
+    put_page(page);
+  }
+
+  MOD_DEC_USE_COUNT;
+}
+
+static struct page *tdfx_vid_nopage(struct vm_area_struct *vma,
+				    unsigned long address, 
+				    int write_access) {
+  unsigned long off;
+  uint32_t n;
+  struct page *page;
+  unsigned long phys;
+
+  off = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT);
+  n = off / PAGE_SIZE;
+
+  if(n >= agp_mem->page_count) {
+    printk(KERN_DEBUG "tdfx_vid: Too far away\n");
+    return ((struct page *)0UL);
+  }
+  phys = agp_mem->memory[n] & ~(0x00000fff);
+  page = virt_to_page(phys_to_virt(phys));
+  if(!page) {
+    printk(KERN_DEBUG "tdfx_vid: Can't get the page\n");
+    return ((struct page *)0UL);
+  }
+  return page;
+}
+
+/* memory handler functions */
+static struct vm_operations_struct tdfx_vid_vm_ops = {
+  open:   tdfx_vid_mopen, /* mmap-open */
+  close:  tdfx_vid_mclose,/* mmap-close */
+  nopage: tdfx_vid_nopage, /* no-page fault handler */
+};
+
+
+static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma)
+{
+  size_t size;
+#ifdef MP_DEBUG
+  printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n");
+#endif
+
+  size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE;
+
+  if(use_fifo) {
+    u32 s = tdfx_inl(CMDBASESIZE0);
+    fifo_n = FIFO0;
+    if(s & 0x100) {
+      printk(KERN_INFO "tdfx_vid: fifo0 alredy in use ... trying fifo1\n");
+      s = tdfx_inl(CMDBASESIZE1);
+      if(s & 0x100) {
+	printk(KERN_INFO "tdfx_vid: fifo1 also in use: no fifo\n");
+	use_fifo = 0;
+      } else
+	fifo_n = FIFO1;
+    }
+  }
+
+  if(use_fifo) { 
+    printk(KERN_INFO "tdfx_vid: fifo avaible\n");
+    // Fix me if PAGE_SIZE != FIFO_PAGE_SIZE
+#if (PAGE_SIZE == FIFO_PAGE_SIZE)
+    fifo_offset = size*PAGE_SIZE;
+    size += FIFO_PAGES;
+#else
+#error Fix me
+#endif
+  }
+
+  if(map_start) { // Ok we map directly in the physcal ram
+    if(size*PAGE_SIZE > map_max) {
+      printk(KERN_ERR "tdfx_vid: Not enouth mem\n");
+      return(-EAGAIN);
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
+    if(remap_page_range(vma, vma->vm_start,map_start,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+#else
+    if(remap_page_range(vma->vm_start, (unsigned long)map_start,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+#endif
+      {
+	printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
+	return(-EAGAIN);
+      }
+    printk(KERN_INFO "Physical mem 0x%lx mapped in userspace\n",map_start);
+    return 0;
+  }
+
+  if(agp_mem)
+    return(-EAGAIN);
+
+  agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY);
+  if(!agp_mem) {
+    printk(KERN_ERR "Failed to allocate AGP memory\n");
+    return(-ENOMEM);
+  }
+
+  if(drm_agp->bind_memory(agp_mem,0)) {
+    printk(KERN_ERR "Failed to bind the AGP memory\n");
+    drm_agp->free_memory(agp_mem);
+    agp_mem = NULL;
+    return(-ENOMEM);
+  }
+
+  printk(KERN_INFO "%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n",
+	 size,vma->vm_end-vma->vm_start,size*PAGE_SIZE);
+
+
+  if(tdfx_map_io) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
+    if(remap_page_range(vma, vma->vm_start,agp_info.aper_base,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+#else
+    if(remap_page_range(vma->vm_start, (unsigned long)agp_info.aper_base,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+#endif
+      {
+	printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
+	return(-EAGAIN);
+      }
+  } else {
+    // Never swap it out
+    vma->vm_flags |= VM_LOCKED | VM_IO;
+    vma->vm_ops = &tdfx_vid_vm_ops;
+    vma->vm_ops->open(vma);
+    printk(KERN_INFO "Page fault handler ready !!!!!\n");
+  }
+
+  if(use_fifo) {
+    use_fifo = open_fifo(fifo_offset,FIFO_PAGES);
+    if(use_fifo) {
+      fifo = ioremap_nocache(agp_info.aper_base + fifo_offset,FIFO_SIZE);
+      printk(KERN_INFO "Fifo at 0x%p\n", fifo);
+    }
+  }    
+
+  return 0;
+}
+
+
+static int tdfx_vid_release(struct inode *inode, struct file *file)
+{
+#ifdef MP_DEBUG
+  printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n");
+#endif
+
+  if(use_fifo) {
+    close_fifo();
+    if(fifo)
+      iounmap(fifo);
+    fifo = NULL;
+  } 
+
+  // Release the agp mem
+  if(agp_mem) {
+    drm_agp->unbind_memory(agp_mem);
+    drm_agp->free_memory(agp_mem);
+    agp_mem = NULL;
+  }
+  
+  tdfx_vid_in_use = 0;
+
+  MOD_DEC_USE_COUNT;
+  return 0;
+}
+
+static long long tdfx_vid_lseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}					 
+
+static int tdfx_vid_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)
+	int minor = MINOR(inode->i_rdev.value);
+#else
+	int minor = MINOR(inode->i_rdev);
+#endif
+
+	if(minor != 0)
+	 return(-ENXIO);
+
+	if(tdfx_vid_in_use == 1) 
+		return(-EBUSY);
+
+	tdfx_vid_in_use = 1;
+	MOD_INC_USE_COUNT;
+	return(0);
+}
+
+#if LINUX_VERSION_CODE >= 0x020400
+static struct file_operations tdfx_vid_fops =
+{
+  llseek:  tdfx_vid_lseek,
+  read:	   tdfx_vid_read,
+  write:   tdfx_vid_write,
+  ioctl:   tdfx_vid_ioctl,
+  mmap:	   tdfx_vid_mmap,
+  open:    tdfx_vid_open,
+  release: tdfx_vid_release
+};
+#else
+static struct file_operations tdfx_vid_fops =
+{
+  tdfx_vid_lseek,
+  tdfx_vid_read,
+  tdfx_vid_write,
+  NULL,
+  NULL,
+  tdfx_vid_ioctl,
+  tdfx_vid_mmap,
+  tdfx_vid_open,
+  NULL,
+  tdfx_vid_release
+};
+#endif
+
+
+int init_module(void)
+{
+  tdfx_vid_in_use = 0;
+
+  if(register_chrdev(TDFX_VID_MAJOR, "tdfx_vid", &tdfx_vid_fops)) {
+    printk(KERN_ERR "tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR);
+    return -EIO;
+  }
+
+  if(!agp_init()) {
+    printk(KERN_ERR "tdfx_vid: AGP init failed\n");
+    unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
+    return -EINVAL;
+  }
+
+  if (!tdfx_vid_find_card()) {
+    printk(KERN_ERR "tdfx_vid: no supported devices found\n");
+    agp_close();
+    unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
+    return -EINVAL;
+  }
+
+  
+
+  return (0);
+
+}
+
+void cleanup_module(void)
+{
+  if(tdfx_mmio_base)
+    iounmap(tdfx_mmio_base);
+  agp_close();
+  printk(KERN_INFO "tdfx_vid: Cleaning up module\n");
+  unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
+}
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/drivers/tdfx_vid.h	Wed Jul 16 23:27:37 2003
@@ -0,0 +1,225 @@
+
+
+#define TDFX_VID_VERSION 1
+
+#define TDFX_VID_MOVE_2_PACKED  0
+#define TDFX_VID_MOVE_2_YUV     1
+#define TDFX_VID_MOVE_2_3D      2
+#define TDFX_VID_MOVE_2_TEXTURE 3
+
+#define TDFX_VID_SRC_COLORKEY 0x1
+#define TDFX_VID_DST_COLORKEY 0x2
+
+#define TDFX_VID_ROP_NOP         0xaa     // dst ?
+#define TDFX_VID_ROP_COPY        0xcc     // src
+#define TDFX_VID_ROP_INVERT      0x55     // NOT dst
+#define TDFX_VID_ROP_XOR         0x66     // src XOR dst
+#define TDFX_VID_ROP_OR		 0xee     // src OR dst
+
+#define TDFX_VID_FORMAT_BGR1  (('B'<<24)|('G'<<16)|('R'<<8)|1)
+#define TDFX_VID_FORMAT_BGR8  (('B'<<24)|('G'<<16)|('R'<<8)|8)
+// x-5-5-5
+#define TDFX_VID_FORMAT_BGR15 (('B'<<24)|('G'<<16)|('R'<<8)|15)
+#define TDFX_VID_FORMAT_RGB15 (('R'<<24)|('G'<<16)|('B'<<8)|15)
+// 5-5-5-x
+#define TDFX_VID_FORMAT_15BGR ((15<<24)|('B'<<16)|('G'<<8)|'R')
+#define TDFX_VID_FORMAT_15RGB ((15<<24)|('R'<<16)|('G'<<8)|'B')
+// 5-6-5
+#define TDFX_VID_FORMAT_BGR16 (('B'<<24)|('G'<<16)|('R'<<8)|16)
+#define TDFX_VID_FORMAT_RGB16 (('R'<<24)|('G'<<16)|('B'<<8)|16)
+// x-8-8-8
+#define TDFX_VID_FORMAT_BGR24 (('B'<<24)|('G'<<16)|('R'<<8)|24)
+#define TDFX_VID_FORMAT_RGB24 (('R'<<24)|('G'<<16)|('B'<<8)|24)
+// 8-8-8-x
+#define TDFX_VID_FORMAT_24BGR ((24<<24)|('B'<<16)|('G'<<8)|'R')
+#define TDFX_VID_FORMAT_24RGB ((24<<24)|('R'<<16)|('G'<<8)|'B')
+
+#define TDFX_VID_FORMAT_BGR32 (('B'<<24)|('G'<<16)|('R'<<8)|32)
+
+#define TDFX_VID_FORMAT_YUY2 (('2'<<24)|('Y'<<16)|('U'<<8)|'Y')
+#define TDFX_VID_FORMAT_UYVY (('Y'<<24)|('V'<<16)|('Y'<<8)|'U')
+
+#define TDFX_VID_FORMAT_YV12 0x32315659
+#define TDFX_VID_FORMAT_IYUV (('I'<<24)|('Y'<<16)|('U'<<8)|'V')
+#define TDFX_VID_FORMAT_I420 (('I'<<24)|('4'<<16)|('2'<<8)|'0')
+
+// 1-5-5-5
+#define TDFX_VID_FORMAT_BGRA16 (('B'<<24)|('G'<<16)|('A'<<8)|16)
+// 8-8-8-8
+#define TDFX_VID_FORMAT_BGRA32 (('B'<<24)|('G'<<16)|('A'<<8)|32)
+#define TDFX_VID_FORMAT_ABGR16 (('A'<<24)|('G'<<16)|('R'<<8)|16)
+#define TDFX_VID_FORMAT_ABGR32 (('A'<<24)|('G'<<16)|('R'<<8)|32)
+
+// 5-5-5-1
+#define TDFX_VID_FORMAT_RGBA16 (('R'<<24)|('G'<<16)|('A'<<8)|16)
+#define TDFX_VID_FORMAT_RGBA32 (('R'<<24)|('G'<<16)|('A'<<8)|32)
+#define TDFX_VID_FORMAT_ARGB16 (('A'<<24)|('G'<<16)|('B'<<8)|16)
+#define TDFX_VID_FORMAT_ARGB32 (('A'<<24)|('G'<<16)|('B'<<8)|32)
+
+#define TDFX_VID_YUV_STRIDE        (1024)
+#define TDFX_VID_YUV_PLANE_SIZE    (0x0100000)
+
+
+#define TDFX_VID_FIFO_PAGE_SIZE 4096
+
+typedef struct tdfx_vid_blit_s {
+  uint32_t src;
+  uint32_t src_stride;
+  uint16_t src_x,src_y;
+  uint16_t src_w,src_h;
+  uint32_t src_format;
+
+  uint32_t  dst;
+  uint32_t dst_stride;
+  uint16_t dst_x,dst_y;
+  uint16_t dst_w,dst_h;
+  uint32_t dst_format;
+
+  // Min/max colorkeys
+  uint32_t src_colorkey[2];
+  uint32_t dst_colorkey[2];
+
+  // Enable the src and/or dst colorkey
+  uint8_t colorkey;
+  /* rop define the action to execute on each pixel depending
+   * on the src and dst colorkey matching.
+   * a pixel match the colorkey if :
+   *  pixel >= colorkey[0] && pixel <= colorkey[1] && colorkey & MASK
+   * So if the colorkey is not enabled it always fail.
+   * If colorkey == 0 && rop[0] == 0 the driver do a simple copy
+   * ie. rop[0] = TDFX_VID_ROP_COPY
+   *
+   *        | src f | src m |
+   * -------+-------+-------+
+   *  dst f |   0   |   2   |
+   * -------+-------+-------+
+   *  dst m |   1   |   3   |
+   * -------+-------+-------+
+   */
+  uint8_t rop[4];
+} tdfx_vid_blit_t;
+
+typedef struct tdfx_vid_config_s {
+  uint16_t version;
+  uint16_t card_type;
+  uint32_t ram_size;
+  uint16_t screen_width;
+  uint16_t screen_height;
+  uint16_t screen_stride;
+  uint32_t screen_format;
+  uint32_t screen_start;
+  uint8_t  triple_buffering;
+} tdfx_vid_config_t;
+
+typedef struct tdfx_vid_agp_move_s {
+  uint16_t move2;
+  uint16_t width,height;
+
+  uint32_t src;
+  uint32_t src_stride;
+
+  uint32_t dst;
+  uint32_t dst_stride;
+} tdfx_vid_agp_move_t;
+
+typedef struct tdfx_vid_yuv_s {
+  uint32_t base;
+  uint16_t stride;
+} tdfx_vid_yuv_t;
+
+typedef struct tdfx_vid_overlay_s {
+  uint32_t src[2]; // left and right buffer (2 buffer may be NULL)
+  uint16_t src_width,src_height;
+  uint16_t src_stride;
+  uint32_t format;
+
+  uint16_t dst_width,dst_height;
+  int16_t dst_x,dst_y;
+
+  uint8_t use_colorkey;
+  uint32_t colorkey[2]; // min/max
+  uint8_t invert_colorkey;
+} tdfx_vid_overlay_t;
+
+// flags
+// enable the graphic pipeline (ie do depth buffering, fog, alpha, etc)
+#define TDFX_VID_PIPELINE (1<<8)
+// swap incoming words
+#define TDFX_VID_WORD_SWAP (1<<11)
+// swap incoming bytes
+#define TDFX_VID_BYTE_SWAP (1<<12)
+
+typedef struct tdfx_vid_3d_lfb_s {
+  uint32_t color_buf; // ie the buffer where RGB data are wrote
+  uint16_t color_stride;
+  uint32_t format; // Write format
+  uint32_t flags; // enable/disable graphic pipeline, etc
+  uint32_t aux_buf;
+  uint16_t aux_stride; // For alpha or depth buffer
+
+  uint32_t mode; // enable/disable clipping, depth buffer, etc
+} tdfx_vid_3d_lfb_t;
+
+
+// Alpha func: colorkey on the alpha channel
+// The pixel is drawn only if (AlphaSrc AlphaFunc AlphaRef) is true
+#define TDFX_VID_AF_NEVER 0
+// less than
+#define TDFX_VID_AF_LT 1
+// equal
+#define TDFX_VID_AF_EQ 2
+// less or equal
+#define TDFX_VID_AF_LEQ 3
+// greater than
+#define TDFX_VID_AF_GT 4
+
+// Alpha blending
+// The blending is done by the following equation :
+// dst = (src * xxx_src) + (dst * xxx_dst)
+// where xxx is either rgb or alpha
+#define TDFX_VID_AB_ZERO 0x0
+#define TDFX_VID_AB_SRC 0x1
+#define TDFX_VID_AB_COLOR 0x2
+#define TDFX_VID_AB_DST 0x3
+#define TDFX_VID_AB_ONE 0x4
+#define TDFX_VID_AB_OM_SRC 0x5
+#define TDFX_VID_AB_OM_COLOR 0x6
+#define TDFX_VID_AB_OM_DST 0x7
+#define TDFX_VID_AB_SATURATE 0xf
+#define TDFX_VID_AB_COLORBEFOREFOG 0xf
+
+
+typedef struct tdfx_vid_alpha_s {
+  uint8_t enable_func;
+  uint8_t func;
+  uint8_t ref;
+  
+  uint8_t enable_blend;
+  uint8_t rgb_src;
+  uint8_t rgb_dst;
+  uint8_t alpha_src;
+  uint8_t alpha_dst;
+} tdfx_vid_alpha_t;
+
+typedef struct tdfx_vid_swap_s {
+  uint32_t buffer;
+  uint8_t sync; // Sync V-Sync
+} tdfx_vid_swap_t;
+  
+
+#define TDFX_VID_GET_CONFIG _IOR('J', 1, tdfx_vid_config_t)
+#define TDFX_VID_AGP_MOVE _IOW('J', 2, tdfx_vid_agp_move_t)
+#define TDFX_VID_BLIT _IOW('J', 3, tdfx_vid_blit_t)
+#define TDFX_VID_SET_YUV _IOW('J', 4, tdfx_vid_blit_t)
+#define TDFX_VID_GET_YUV _IOR('J', 5, tdfx_vid_blit_t)
+#define TDFX_VID_BUMP0 _IOW('J', 6, u16)
+#define TDFX_VID_SET_OVERLAY _IOW('J', 7, tdfx_vid_overlay_t)
+#define TDFX_VID_OVERLAY_ON _IO ('J', 8)
+#define TDFX_VID_OVERLAY_OFF _IO ('J', 9)
+#define  TDFX_VID_OVERLAY_SWAP _IOW('J', 10, tdfx_vid_swap_t)
+#define  TDFX_VID_DUMP_REG _IOR('J', 11, uint32_t)
+#define  TDFX_VID_GET_3D_LFB _IOR('J', 12, tdfx_vid_3d_lfb_t)
+#define  TDFX_VID_SET_3D_LFB _IOW('J', 13, tdfx_vid_3d_lfb_t)
+#define  TDFX_VID_GET_ALPHA _IOR('J', 14, tdfx_vid_alpha_t)
+#define  TDFX_VID_SET_ALPHA _IOW('J', 15, tdfx_vid_alpha_t)
+
--- /home/alban/MP/g2/libvo2/Makefile	Sun Jul 13 18:20:25 2003
+++ /home/alban/MP/g2.dev/libvo2/Makefile	Thu Jul 17 02:38:04 2003
@@ -3,7 +3,7 @@
 
 LIBNAME = libvo2.a
 
-SRCS=vo_null.c vo_x11.c vo_xv.c vo_mga.c video_out.c event.c x11_helper.c # vo_pgm.c vo_md5.c
+SRCS=vo_null.c vo_x11.c vo_xv.c vo_mga.c vo_tdfx_vid.c vo_xover.c video_out.c event.c x11_helper.c # vo_pgm.c vo_md5.c
 OBJS=$(SRCS:.c=.o)
 
 ifeq ($(VIDIX),yes)
--- /home/alban/MP/g2/libvo2/video_out.c	Sun Jul 13 18:33:42 2003
+++ /home/alban/MP/g2.dev/libvo2/video_out.c	Thu Jul 17 02:44:34 2003
@@ -17,11 +17,15 @@
 extern vo_info_t vo_driver_x11;
 extern vo_info_t vo_driver_xv;
 extern vo_info_t vo_driver_null;
+extern vo_info_t vo_driver_tdfx_vid;
+extern vo_info_t vo_driver_xover;
 
 vo_info_t* video_out_drivers[] = {
     &vo_driver_mga,
+    &vo_driver_tdfx_vid,
     &vo_driver_x11,
     &vo_driver_xv,
+    &vo_driver_xover,
     &vo_driver_null,
     NULL
 };
--- /home/alban/MP/g2/libvo2/video_out.h	Sun Jul 13 23:02:22 2003
+++ /home/alban/MP/g2.dev/libvo2/video_out.h	Thu Jul 17 14:39:24 2003
@@ -22,6 +22,8 @@
 #define VOCTRL_RESIZE_SRC 2
 // tells driver the x11 (or win32) window id:
 #define VOCTRL_SET_WINDOW 3
+/* set the colorkay to use for a child display */
+#define VOCTRL_SET_COLORKEY 10
 /* signal a device pause */
 #define VOCTRL_PAUSE 7
 /* start/resume playback */
@@ -54,6 +56,8 @@
 // show-frame() can display the frame at any time position (pts), using
 // hardware timer (for example dxr3/dvb mpeg-pes) [replaces format flag 0x100]
 #define VO_BUFFER_FLAG_TIMER 8
+// show-frame() can display the frame at any relative time position
+#define VO_BUFFER_FLAG_SLEEP 16
 
 //****** vo2 specific module_info_t flags: ********
 // module can work as parent for other sub-vo module (xover, vesa, fbdev...)
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/libvo2/vo_tdfx_vid.c	Thu Jul 17 18:32:18 2003
@@ -0,0 +1,497 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "mp_msg.h"
+#include "video_out.h"
+#include "video/vfcap.h"
+#include "video/img_format.h"
+
+#include "drivers/tdfx_vid.h"
+
+/*
+ * We have two memory area. The AGP memory, wich is located
+ * in RAM (but sadly read are slow) and the video memory on the
+ * card.
+ * So we are exporting the AGP buffer. Stride doesn't matter as
+ * we can change it during the AGP move.
+ * On the card we use 4 buffers. The first 3 are used for the overlay
+ * and the last one is used to do colorspace conversion and/or
+ * scaling.
+ * The overlay can only accept 3 colorspace YUY2, UYVY and BGR16 and
+ * doesn't do downscaling.
+ * However the card have a chip to convert planar YUV (YV12 and I420)
+ * to YUY2 and we can do blit with colorspace conversion and/or scaling.
+ *
+ * The colorspace are handled as follow:
+ *
+ * YV12, I420 :
+ *  - Upscaling   : -> YUV -> Overlay buffer YUY2
+ *  - Downscaling : -> YUV -> Conv Buffer YUY2 -> Overlay buffer BGR16
+ *
+ * YUY2, UYVY :
+ *  - Upscaling   : -> Overlay buffer YUY2 or UYVY
+ *  - Downscaling : -> Conv Buffer YUY2 or UYVY -> Overlay buffer BGR16
+ *
+ * BGR16 :
+ *  - Upscaling   : -> Overlay buffer BGR16
+ *  - Downscaling : -> Conv Buffer BGR16 -> Overlay buffer BGR16
+ *
+ * BGR24, BGR32 :
+ *  - Upscaling   : -> Conv Buffer BGR24 or BGR32 -> Overlay buffer BGR16
+ *  - Downscaling : -> Conv Buffer BGR24 or BGR32 -> Overlay buffer BGR16
+ *
+ *
+ * The vrate option enable the VO_BUFFER_FLAG_SLEEP. You must give it
+ * the vertical refresh rate (in Hz) of your current video mode.
+ * In normal conditions mplayer uselly have to sleep before calling
+ * show_frame to ensure A/V sync. But when VO_BUFFER_FLAG_SLEEP is enabled
+ * mplayer won't sleep and will call show_frame with the wait delay in the
+ * pts argument.
+ * Now knowing the refresh rate we instruct the banshee to do flip at the
+ * right moment and return. This way mplayer doesn't need to sleep and the
+ * A/V sync is right :)
+ * On my box (K6-2 333) a clip wich normally use ~80% of CPU go down
+ * to ~55% according to top. So it seems to help :)
+ *
+ */
+
+
+#define ALIGN(p,n) ((((p)+(n-1))/n)*n)
+
+static struct config_data_s {
+  char* dev;
+  float v_rate;
+} options_def = {
+  "/dev/tdfx_vid",
+  0
+};
+
+static config_t options[] = {
+  { "dev", &options_def.dev, CONF_TYPE_STRING, 0, 0, 0, 0, "Device to use" },
+  { "vrate", &options_def.v_rate, CONF_TYPE_FLOAT, CONF_MIN, 0, 0, 0, "Vertical refresh rate (enable 'sleeping vo')" },
+  { NULL, NULL, 0, 0, 0, 0, 0, NULL }
+};
+
+struct vo_priv_s {
+  int fd;
+  unsigned char* agp_mem;
+  tdfx_vid_config_t cfg;
+  tdfx_vid_overlay_t ov;
+  // Our 3 buffers used by the overlay in video mem
+  uint32_t ov_buf[3];
+  unsigned int ov_fmt; // To save the normal overlay format
+  // The conversion buffer (used for BGR24 or downscaling)
+  unsigned int cv_fmt;
+  int cv_stride;
+  int cv_bpp;
+  uint32_t cv_buf;
+  float v_rate; // V-Sync per second
+};
+
+static int control(struct vo_instance_s* vo,
+	int request, void *data, ...){
+  switch(request) {
+  case VOCTRL_RESIZE_DEST: {
+    int *a = data;
+
+    vo->priv->ov.src_width = vo->buffer_w;
+    vo->priv->ov.src_height = vo->buffer_h;
+    vo->priv->ov.format = vo->priv->ov_fmt;
+
+    if(a[0] >= 0) vo->priv->ov.dst_x = a[0];
+    if(a[1] >= 0) vo->priv->ov.dst_y = a[1];
+    if(a[2] > 0) vo->priv->ov.dst_width = a[2];
+    if(a[3] > 0) vo->priv->ov.dst_height = a[3];
+
+    // We can't downscale so we'll convert
+    if(vo->priv->ov.dst_width < vo->buffer_w) {
+      vo->priv->ov.src_width = vo->priv->ov.dst_width;
+      vo->priv->ov.format = IMGFMT_BGR16;
+    }
+    if(vo->priv->ov.dst_height < vo->buffer_h) {
+      vo->priv->ov.src_height = vo->priv->ov.dst_height;
+      vo->priv->ov.format = IMGFMT_BGR16;
+    }
+    if(ioctl(vo->priv->fd,TDFX_VID_SET_OVERLAY,&vo->priv->ov)) {
+      mp_msg(MSGT_VO, MSGL_ERR, "tdfx_vid: set_overlay failed\n");
+      return VO_FALSE;
+    }
+    return VO_TRUE;
+  } break;
+  case VOCTRL_SET_COLORKEY:
+    vo->priv->ov.use_colorkey = 1;
+    vo->priv->ov.colorkey[0] = vo->priv->ov.colorkey[1] = *((int*)data);
+    if(vo->config_count) {
+      if(ioctl(vo->priv->fd,TDFX_VID_SET_OVERLAY,&vo->priv->ov)) {
+	mp_msg(MSGT_VO, MSGL_ERR, "tdfx_vid: set_overlay failed\n");
+	return VO_FALSE;
+      }
+    }
+    return VO_TRUE;
+  default:
+    return VO_NOTIMPL;
+  };
+}
+
+static unsigned int query_format(struct vo_instance_s* vo,
+	unsigned int format, int width, int height){
+  unsigned int ret = VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_HWSCALE_UP|VFCAP_HWSCALE_DOWN|VFCAP_ACCEPT_STRIDE;
+
+  // TODO find the limits (both ov and planar thing) and check width, height
+
+  switch(format) {
+  case IMGFMT_YUY2:
+  case IMGFMT_UYVY:
+    //  case IMGFMT_BGR15:
+  case IMGFMT_BGR16:
+  case IMGFMT_BGR24:
+  case IMGFMT_BGR32:
+  case IMGFMT_YV12:
+  case IMGFMT_I420:
+    if(vo->priv->cfg.screen_format == TDFX_VID_FORMAT_BGR8)
+      return 0;
+    return ret;
+  }
+
+  return 0;
+}
+
+static int config(struct vo_instance_s* vo,
+	int width, int height, int d_width, int d_height,
+	unsigned int format){
+  int buf_size;
+  int buf_stride;
+  uint32_t last_buf = (uint32_t)vo->priv->agp_mem;
+  int i,planar=0;;
+
+  vo->num_buffers=3;
+  if(vo->buffers) free(vo->buffers);
+  vo->buffers=calloc(sizeof(vo_buffer_t),vo->num_buffers);
+  vo->buffer_w=width; vo->buffer_h=height;
+  vo->format=format;
+  vo->buffer_flags=VO_BUFFER_FLAG_VIDEORAM; // AGP mem read are slow :(((
+  // We have the vertical refresh rate: enable 'sleeping vo'
+  if(vo->priv->v_rate > 0)
+    vo->buffer_flags|=VO_BUFFER_FLAG_SLEEP;
+  vo->w=d_width; vo->h=d_height;
+
+  switch(format) {
+    // Planar format
+  case IMGFMT_YV12:
+  case IMGFMT_I420:
+    vo->priv->ov.format = IMGFMT_YUY2;
+    vo->priv->cv_fmt = vo->priv->ov.format;
+    buf_stride = ALIGN(width,2);
+    buf_size = buf_stride * height * 3 / 2;
+    planar = 1;
+    break;
+    // Native packed format
+  case IMGFMT_YUY2:    
+  case IMGFMT_UYVY:
+  case IMGFMT_BGR16:
+    vo->priv->ov.format = format;
+    vo->priv->cv_fmt = format;
+    buf_stride = width * 2;
+    buf_size = buf_stride * height;
+    break;
+    // Converted packed
+  case IMGFMT_BGR24:
+  case IMGFMT_BGR32:
+    vo->priv->ov.format = IMGFMT_BGR16;
+    vo->priv->cv_fmt = format;
+    buf_stride = width * (IMGFMT_BGR_DEPTH(format)/8);
+    buf_size = buf_stride * height;
+    break;
+  default:
+    printf("Wrong format: %s (0x%x)\n",vo_format_name(format),format);
+    return VO_FALSE;
+  }
+
+  // Make the buffer list
+  // 
+  for(i = 0 ; i < vo->num_buffers ; i++) {
+    vo->buffers[i].planes[0] = (unsigned char*)last_buf;
+    if(planar) {
+      vo->buffers[i].planes[1] = (unsigned char*)last_buf + (buf_stride*height);
+      vo->buffers[i].planes[2] = (unsigned char*)last_buf + (buf_stride*height)*5/4;
+    }
+    vo->buffers[i].stride[0] = buf_stride;
+    if(planar)
+      vo->buffers[i].stride[1] = vo->buffers[i].stride[2] = buf_stride/2;
+    vo->buffers[i].priv = (void*)i;
+    last_buf += buf_size;
+  }
+
+  // Setup the overlay stuff
+  // Note that the overlay bytes per pixel is always 2
+  // Overlay need a 4 bytes aligned stride and 16 bytes aligned buffers
+  vo->priv->ov.src_stride = ALIGN(2*width,4);
+ 
+  vo->priv->ov_buf[0] = ALIGN(vo->priv->cfg.screen_start + (vo->priv->cfg.screen_stride*vo->priv->cfg.screen_height),16);
+  vo->priv->ov_buf[1] = ALIGN(vo->priv->ov_buf[0] + (vo->priv->ov.src_stride * height),16);
+  vo->priv->ov_buf[2] = ALIGN(vo->priv->ov_buf[1] + (vo->priv->ov.src_stride * height),16);
+
+  vo->priv->ov.src_width = width;
+  vo->priv->ov.src_height = height;
+  vo->priv->ov.src[0] = vo->priv->ov_buf[0];
+  vo->priv->ov.dst_width = d_width;
+  vo->priv->ov.dst_height = d_height;
+
+  if(ioctl(vo->priv->fd,TDFX_VID_SET_OVERLAY,&vo->priv->ov)) {
+    mp_msg(MSGT_VO, MSGL_ERR, "tdfx_vid: set_overlay failed\n");
+    return VO_FALSE;
+  }
+  
+  // Enable the overlay
+  if(ioctl(vo->priv->fd,TDFX_VID_OVERLAY_ON)) {
+    printf("tdfx_vid: Overlay on failed\n");
+    return VO_FALSE;
+  }
+
+  // The conversion buffer
+  vo->priv->cv_buf = vo->priv->ov_buf[2] + vo->priv->ov.src_stride * height;
+  switch(vo->priv->cv_fmt){
+  case IMGFMT_BGR24:
+  case IMGFMT_BGR32:
+    vo->priv->cv_bpp = (IMGFMT_BGR_DEPTH(format)/8);
+    break;
+    // YUY2, UYVY, BGR16
+  default:
+    vo->priv->cv_bpp = 2;
+    break;
+  }
+
+  vo->priv->cv_stride = width*vo->priv->cv_bpp;
+  vo->priv->ov_fmt = vo->priv->ov.format;
+
+  return VO_TRUE;
+}
+
+
+
+static int frame_done(struct vo_instance_s* vo, vo_buffer_t* buffer) {
+  tdfx_vid_agp_move_t mov;
+  tdfx_vid_blit_t blit;
+  int buf = (int)buffer->priv;
+  uint32_t dst;
+  uint32_t dst_stride;
+  uint32_t dst_bpp;
+
+  if(vo->priv->ov.format == vo->priv->cv_fmt &&
+     vo->priv->ov.src_width == vo->buffer_w &&
+     vo->priv->ov.src_height == vo->buffer_h) {
+    dst = vo->priv->ov_buf[buf];
+    dst_stride =  vo->priv->ov.src_stride;
+    dst_bpp = 2;
+  } else {
+    dst = vo->priv->cv_buf;
+    dst_stride = vo->priv->cv_stride;
+    dst_bpp = vo->priv->cv_bpp;
+  }
+  
+  // Planar format
+  if(vo->format == IMGFMT_YV12 || vo->format == IMGFMT_I420) {
+    tdfx_vid_yuv_t yuv;
+
+    // Setup the yuv thing
+    yuv.base = dst;
+    yuv.stride = dst_stride;
+    if(ioctl(vo->priv->fd,TDFX_VID_SET_YUV,&yuv)) {
+      printf("tdfx_vid: Set yuv failed\n");
+      return VO_FALSE;
+    }
+
+    // Now agp move that
+    // Y
+    mov.move2 = TDFX_VID_MOVE_2_YUV;
+    mov.width = vo->buffer_w;
+    mov.height = vo->buffer_h;
+    mov.src = buffer->planes[0] - vo->priv->agp_mem;
+    mov.src_stride =  buffer->stride[0];
+    mov.dst = 0x0;
+    mov.dst_stride = TDFX_VID_YUV_STRIDE;
+
+    if(ioctl(vo->priv->fd,TDFX_VID_AGP_MOVE,&mov)) {
+      printf("tdfx_vid: AGP move failed on Y plane\n");
+      return VO_FALSE;
+    }
+    //return 0;
+    // U
+    mov.width = vo->buffer_w/2;
+    mov.height = vo->buffer_h/2;
+    mov.src = buffer->planes[2] - vo->priv->agp_mem;
+    mov.src_stride = buffer->stride[2];
+    mov.dst += TDFX_VID_YUV_PLANE_SIZE;
+    if(ioctl(vo->priv->fd,TDFX_VID_AGP_MOVE,&mov)) {
+      printf("tdfx_vid: AGP move failed on U plane\n");
+      return VO_FALSE;
+    }
+    // V
+    mov.src = buffer->planes[1] - vo->priv->agp_mem;
+    mov.src_stride = buffer->stride[1];
+    mov.dst += TDFX_VID_YUV_PLANE_SIZE;
+    if(ioctl(vo->priv->fd,TDFX_VID_AGP_MOVE,&mov)) {
+      printf("tdfx_vid: AGP move failed on U plane\n");
+      return VO_FALSE;
+    }
+
+  } else { // Packed format
+    mov.move2 = TDFX_VID_MOVE_2_PACKED;
+    mov.width = vo->buffer_w*dst_bpp;
+    mov.height = vo->buffer_h;
+    mov.src = buffer->planes[0] - vo->priv->agp_mem;
+    mov.src_stride =  buffer->stride[0];
+  
+    mov.dst = dst;
+    mov.dst_stride = dst_stride;
+	 
+    if(ioctl(vo->priv->fd,TDFX_VID_AGP_MOVE,&mov)) {
+      printf("tdfx_vid: AGP move failed\n");
+      return VO_FALSE;
+    }
+  }
+
+  // No conversion needed we are done
+  if(dst != vo->priv->cv_buf) return VO_TRUE;
+
+  memset(&blit,0,sizeof(tdfx_vid_blit_t));
+  blit.src = vo->priv->cv_buf;
+  blit.src_stride = vo->priv->cv_stride;
+  blit.src_x = 0;
+  blit.src_y = 0;
+  blit.src_w = vo->buffer_w;
+  blit.src_h = vo->buffer_h;
+  blit.src_format = vo->priv->cv_fmt;
+
+  blit.dst = vo->priv->ov_buf[buf];
+  blit.dst_stride = vo->priv->ov.src_stride;
+  blit.dst_x = 0;
+  blit.dst_y = 0;
+  blit.dst_w = vo->priv->ov.src_width;
+  blit.dst_h = vo->priv->ov.src_height;
+  blit.dst_format = vo->priv->ov.format;
+
+  if(ioctl(vo->priv->fd,TDFX_VID_BLIT,&blit)) {
+    printf("tdfx_vid: Blit failed\n");
+    return VO_FALSE;
+  }
+
+  return VO_TRUE;
+}
+
+static void show_frame(struct vo_instance_s* vo, vo_buffer_t* buffer,
+	float pts){
+  tdfx_vid_swap_t swap = {
+    vo->priv->ov_buf[(int)buffer->priv],
+    1 // wait v-sync
+  };
+
+  //printf("\nGot pts %f\n",pts);
+  if(pts > 0)
+    swap.sync = pts*vo->priv->v_rate; // My refersh rate  
+  //printf("Waiting %d\n",swap.sync);
+
+  if(!ioctl(vo->priv->fd,TDFX_VID_OVERLAY_ON)) { // X11 killed the overlay :(
+    if(ioctl(vo->priv->fd,TDFX_VID_SET_OVERLAY,&vo->priv->ov))
+      mp_msg(MSGT_VO, MSGL_ERR, "tdfx_vid: set_overlay failed\n");
+  }
+
+  if(ioctl(vo->priv->fd,TDFX_VID_OVERLAY_SWAP,&swap))
+    printf("tdfx_vid: Flip buffer failed\n");
+}
+
+static void uninit(struct vo_instance_s* vo) {
+  if(!vo->priv) return;
+
+  if(vo->priv->fd) {
+    ioctl(vo->priv->fd,TDFX_VID_OVERLAY_OFF);
+    close(vo->priv->fd);
+  }
+
+  free(vo->priv);
+  vo->priv = NULL;
+}
+
+static vo_instance_t* preinit(char* args,void* x11_display){
+  int fd;
+  unsigned char* agp_mem;
+  tdfx_vid_config_t tdfx_cfg;
+  vo_instance_t* vo;
+  config_data_t* cfg = args ? (config_data_t*)args : &options_def;
+
+  fd = open(cfg->dev, O_RDWR);
+  if(fd < 0) {
+    printf("tdfx_vid: Can't open %s: %s\n",cfg->dev,strerror(errno));
+    return NULL;
+  }
+
+  if(ioctl(fd,TDFX_VID_GET_CONFIG,&tdfx_cfg)) {
+    printf("tdfx_vid: Can't get current cfg: %s\n",strerror(errno));
+    close(fd);
+    return NULL;
+  }
+
+  printf("tdfx_vid version %d\n"
+	 "  Ram: %d\n"
+	 "  Screen: %d x %d\n"
+	 "  Format: %c%c%c%d\n"
+	 "  Screen start: 0x%x\n"
+	 "  Triple buffering: %s\n",
+	 tdfx_cfg.version,
+	 tdfx_cfg.ram_size,
+	 tdfx_cfg.screen_width, tdfx_cfg.screen_height,
+	 tdfx_cfg.screen_format>>24,(tdfx_cfg.screen_format>>16)&0xFF,
+	 (tdfx_cfg.screen_format>>8)&0xFF,tdfx_cfg.screen_format&0xFF,
+	 tdfx_cfg.screen_start,
+	 tdfx_cfg.triple_buffering ? "on" : "off");
+
+  agp_mem = mmap( NULL, 1024*768*4, PROT_READ | PROT_WRITE, MAP_SHARED,
+		  fd, 0);
+
+  if(agp_mem == MAP_FAILED) {
+    printf("tdfx_vid: Memmap failed !!!!!\n");
+    close(fd);
+    return NULL;
+  }
+
+  vo=calloc(sizeof(vo_instance_t),1);
+  vo->query_format=query_format;
+  vo->control=control;
+  vo->config=config;
+  vo->frame_done=frame_done;
+  vo->show_frame=show_frame;
+  vo->uninit=uninit;
+  
+  vo->priv = calloc(1,sizeof(struct vo_priv_s));
+  vo->priv->fd = fd;
+  vo->priv->agp_mem = agp_mem;
+  vo->priv->v_rate = cfg->v_rate;
+  memcpy(&vo->priv->cfg,&tdfx_cfg,sizeof(tdfx_vid_config_t));
+    
+  
+  return vo;
+}
+
+vo_info_t vo_driver_tdfx_vid = {
+    MODULE_TYPE_VO, MODULE_VERSION,
+    preinit,
+    "tdfx_vid",
+    "AGP Banshee/Voodoo3 driver",
+    "Albeu",
+    "Albeu",
+    "untested on Voodoo3",
+    VO_MODULE_CAPS_CHILD,
+    options, &options_def, sizeof(struct config_data_s)
+};
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/libvo2/vo_xover.c	Fri Jul 18 11:45:07 2003
@@ -0,0 +1,273 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "mp_msg.h"
+#include "video_out.h"
+#include "video/vfcap.h"
+
+/*
+ * TODO
+ *
+ * - Finish the colorkey stuff
+ *   - Make different colorkey for 24/32 bit depth
+ *   - Is passing only the raw x11 color ok for everyone ?
+ * 
+ */
+
+
+static struct config_data_s {
+  config_modlist_t* vo_list;
+} options_def = {
+  NULL
+};
+
+static config_t options[] = {
+  { "vo", &options_def.vo_list, CONF_TYPE_MODLIST, 0, 0, 0, vo2_find_module, "Sub driver name" },
+  { NULL, NULL, 0, 0, 0, 0, 0, NULL }
+};
+
+struct vo_priv_s {
+  Window win;
+  Display* dpy;
+  XGCValues xgcv;
+  GC gc;
+  vo_instance_t* subvo;
+  uint32_t fgColor;
+  uint32_t bgColor;
+};
+
+static void get_win(struct vo_priv_s* priv,int* x,int* y,int* w,int* h) {
+  // Dummy stuff
+  Window mRoot;
+  int drwX,drwY,drwW,drwH,drwBorderWidth,drwDepth;
+
+  if(!priv || !priv->dpy || !priv->win) return;
+
+  XGetGeometry(priv->dpy, priv->win, &mRoot,&drwX, &drwY , &drwW,
+		   &drwH, &drwBorderWidth, &drwDepth);
+  XTranslateCoordinates(priv->dpy, priv->win, mRoot, 0, 0,
+			&drwX, &drwY, &mRoot);
+  if(x) *x = drwX;
+  if(y) *y = drwY;
+  if(w) *w = drwW;
+  if(h) *h = drwH;
+}
+
+static void draw_colorkey(struct vo_instance_s* vo) {
+  if(vo->x < 0 || vo->y < 0 ||
+     vo->w <= 0 || vo->h <= 0 ||
+     vo->priv->gc == None) return;
+
+  XSetBackground(vo->priv->dpy,vo->priv->gc,vo->priv->bgColor );
+  XClearWindow(vo->priv->dpy ,vo->priv->win );
+  XSetForeground(vo->priv->dpy,vo->priv->gc , vo->priv->fgColor);
+  XFillRectangle(vo->priv->dpy,vo->priv->win,vo->priv->gc,
+		 vo->x,vo->y,vo->w,vo->h);
+  XFlush(vo->priv->dpy);
+}
+
+static int control(struct vo_instance_s* vo,
+	int request, void *data, ...){
+  switch(request) {
+  case VOCTRL_SET_WINDOW:
+    vo->priv->win=*((Window*)data);
+    // FIXME: check if we already have win, and move GC from it!
+    if(vo->priv->gc != None)
+      XFreeGC( vo->priv->dpy,vo->priv->gc );
+    vo->priv->gc = XCreateGC(vo->priv->dpy, vo->priv->win, 0L, &vo->priv->xgcv);
+    vo->x = vo->y = 0;
+    get_win(vo->priv,NULL,NULL,&vo->w,&vo->h);
+    draw_colorkey(vo);
+    break;
+  case VOCTRL_RESIZE_DEST: {
+    int* a = data;
+    //   printf("\nGot resize %dx%d %d-%d\n",a[0],a[1],a[2],a[3]);
+
+    // set the requested overlay pos/size
+    if(a[0] >= 0) vo->x = a[0];
+    if(a[1] >= 0) vo->y = a[1];
+    if(a[2] > 0) vo->w = a[2];
+    if(a[3] > 0) vo->h = a[3];
+
+    // Get the real window size
+    get_win(vo->priv,&a[0],&a[1],&a[2],&a[3]);
+    // Adjust x and y 
+    // Checks ?
+    a[0] += vo->x;
+    a[1] += vo->y;
+    // Clamp w/h to the window size
+    if(vo->w > a[2])
+      vo->w = a[2];
+    else
+      a[2] = vo->w;
+    if(vo->h > a[3])
+      vo->h = a[3];
+    else
+      a[3] = vo->h;
+    draw_colorkey(vo);
+  }
+  default:
+    // Fix me !!! We must past the ... arguments but how ?
+    if(vo->priv->subvo->control)
+      return vo->priv->subvo->control(vo->priv->subvo,request,data);
+  }
+  return VO_NOTIMPL;
+}
+
+static unsigned int query_format(struct vo_instance_s* vo,
+	unsigned int format, int width, int height){
+    return vo->priv->subvo->query_format(vo->priv->subvo,format,
+					 width,height);
+}
+
+static int config(struct vo_instance_s* vo,
+	int width, int height, int d_width, int d_height,
+	unsigned int format){
+  
+  if(vo->priv->subvo->config(vo->priv->subvo,width,height,d_width,d_height,
+			     format) != VO_TRUE)
+    return VO_FALSE;
+  vo->priv->subvo->config_count++;
+
+  vo->num_buffers=vo->priv->subvo->num_buffers;
+  vo->buffers = vo->priv->subvo->buffers;
+  vo->buffer_w=vo->priv->subvo->buffer_w;
+  vo->buffer_h=vo->priv->subvo->buffer_h;
+  vo->format=vo->priv->subvo->format;
+  vo->buffer_flags=vo->priv->subvo->buffer_flags;
+  vo->w=vo->priv->subvo->w;
+  vo->h=vo->priv->subvo->h;
+
+
+  
+
+
+  return VO_TRUE;
+}
+
+
+static vo_buffer_t* get_buffer(struct vo_instance_s* vo) {
+  return vo->priv->subvo->get_buffer(vo->priv->subvo);
+}
+
+static void release_buffer(struct vo_instance_s* vo, vo_buffer_t* buffer) {
+  return vo->priv->subvo->release_buffer(vo->priv->subvo,buffer);
+}
+
+static int frame_start(struct vo_instance_s* vo, vo_buffer_t* buffer) {
+  return vo->priv->subvo->frame_start(vo->priv->subvo,buffer);
+}
+
+static void draw_slice(struct vo_instance_s* vo, vo_buffer_t* buffer,
+        unsigned char* src[], int stride[], int w,int h, int x,int y){
+  vo->priv->subvo->draw_slice(vo->priv->subvo,buffer,
+			      src,stride,w,h,x,y);
+}
+
+static int frame_done(struct vo_instance_s* vo, vo_buffer_t* buffer) {
+  return vo->priv->subvo->frame_done(vo->priv->subvo,buffer);
+}
+
+static void show_frame(struct vo_instance_s* vo, vo_buffer_t* buffer,
+	float pts){
+  vo->priv->subvo->show_frame(vo->priv->subvo,buffer,pts);
+}
+
+static void uninit(struct vo_instance_s* vo) {
+  if(vo->priv->subvo->uninit)
+    vo->priv->subvo->uninit(vo->priv->subvo); 
+  
+}
+
+static vo_instance_t* preinit(char* arg,void* x11_display){
+  vo_info_t* module;
+  vo_instance_t* subvo = NULL;
+  vo_instance_t* vo;
+  config_data_t* opts = (config_data_t*)arg;
+  int i;
+
+  if(!arg || !opts->vo_list) {
+    mp_msg(MSGT_VO, MSGL_ERR, "VO XOverlay need a subdriver\n");
+    return NULL;
+  }
+
+  if(!x11_display) {
+    mp_msg(MSGT_VO, MSGL_ERR, "VO XOverlay need a X11 display\n");
+    return NULL;
+  }
+  
+
+  for(i = 0 ; opts->vo_list[i].mod ; i++) {
+    module = opts->vo_list[i].mod;
+
+    // Check child caps
+    if(!(module->flags &VO_MODULE_CAPS_CHILD)) {
+      mp_msg(MSGT_VO, MSGL_ERR, "Subvo %s can't be used as child\n",
+	     module->name);
+      continue;
+    }
+
+    subvo = ((vo2_preinit_t)module->entry)(opts->vo_list[i].cfg,NULL);
+    if(!subvo) {
+      mp_msg(MSGT_VO, MSGL_ERR, "Subvo %s preinit failed\n",
+	     module->name);
+      continue;
+    }
+    subvo->info = module;
+    // We have everything now
+    break;
+  }
+
+  if(!subvo) {
+    mp_msg(MSGT_VO, MSGL_ERR, "No useable subdriver found\n");
+    return NULL;
+  }
+
+  vo=calloc(sizeof(vo_instance_t),1);
+  vo->query_format=query_format;
+  vo->control=control;
+  vo->config=config;
+  if(subvo->get_buffer)
+    vo->get_buffer = get_buffer;
+  if(subvo->release_buffer)
+    vo->release_buffer = release_buffer;
+  if(subvo->frame_start)
+    vo->frame_start = frame_start;
+  if(subvo->draw_slice)
+    vo->draw_slice=draw_slice;
+  if(subvo->frame_done)
+    vo->frame_done = frame_done; 
+  vo->show_frame=show_frame;
+  vo->uninit=uninit;
+ 
+
+  vo->priv = calloc(sizeof(struct vo_priv_s),1);
+  vo->priv->subvo = subvo;
+  vo->priv->dpy = x11_display;
+  vo->priv->bgColor = 0x0L;
+  // Fix ME
+  vo->priv->fgColor = 0xf81fL;
+
+  if(subvo->control)
+    subvo->control(subvo,VOCTRL_SET_COLORKEY,&vo->priv->fgColor);
+  return vo;
+}
+
+vo_info_t vo_driver_xover = {
+    MODULE_TYPE_VO, MODULE_VERSION,
+    preinit,
+    "xover",
+    "X11 overlay",
+    "Albeu",
+    "Albeu",
+    "need a subdriver",
+    VO_MODULE_CAPS_X11|VO_MODULE_CAPS_WINDOW|VO_MODULE_CAPS_GUI|VO_MODULE_CAPS_PARENT,
+    options, &options_def, sizeof(struct config_data_s)
+};
--- /home/alban/MP/g2/libvo2/x11_helper.c	Sun Jul 13 00:40:03 2003
+++ /home/alban/MP/g2.dev/libvo2/x11_helper.c	Thu Jul 17 18:18:03 2003
@@ -455,11 +455,14 @@
 	}
 	break;
     // events generated by vo_x11_check_events():
+    case VO_EVENT_EXPOSE:
     case VO_EVENT_MOVE:
 	mp_msg(MSGT_CPLAYER,MSGL_V,"vo-event: moved to %d x %d\n",x,y);
 // dont do that, we're moving the window, not the picture inside the window!
-//	tmp[2]=tmp[3]=-1; tmp[0]=x; tmp[1]=y;
-//	vo->control(vo,VOCTRL_RESIZE_DEST,tmp);
+	{ int tmp[4];
+	tmp[2]=tmp[3]=-1; tmp[0]=-1; tmp[1]=-1;
+	vo->control(vo,VOCTRL_RESIZE_DEST,tmp);
+	}
 	break;
     default:
 	vo_default_event_callback(vo,type,flags,x,y);
--- /home/alban/MP/g2/test-play.c	Sun Jul 13 23:03:00 2003
+++ /home/alban/MP/g2.dev/test-play.c	Thu Jul 17 01:26:57 2003
@@ -468,16 +468,19 @@
 //		    time_frame=0;
 	    }
 	    // do sleeping!
-	    if(time_frame>0){
+	    if( !(video_out->buffer_flags & VO_BUFFER_FLAG_SLEEP)  ||
+		frame_time_remaining ) {
+	      if(time_frame>0){
 		time_frame/=playback_speed;
 		mp_msg(MSGT_AVSYNC,MSGL_DBG2,"time_frame=%5.3f\n",time_frame);
 		//usec_sleep((int)(time_frame*1000000.0));
 		time_frame=sleep_accurate(time_frame)*playback_speed;
+	      }
 	    }
 	    // display!
 	    if(!frame_time_remaining){
 		if(mpi && mpi->priv && video_out->show_frame)
-		    video_out->show_frame(video_out,(vo_buffer_t*)mpi->priv,0);
+		    video_out->show_frame(video_out,(vo_buffer_t*)mpi->priv,video_out->buffer_flags & VO_BUFFER_FLAG_SLEEP && time_frame > 0 ? time_frame/playback_speed : 0);
 		if(d_sub && !d_sub->eof)
 		  test_subs(d_sub,v_pts);
 		mpi=NULL;
@@ -509,7 +512,7 @@
 #endif
 	    sh_audio->delay+=x; c_total+=x;
 	    time_frame-=x; // for -autosync
-	    mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%8.3f (%5.3f) V:%8.3f (%5.3f) A-V:%+7.4f ct:%7.4f d:%5.3f x:%+5.3f \r",
+	    mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%8.3f (%5.3f) V:%8.3f (%+5.3f) A-V:%+7.4f ct:%7.4f d:%5.3f x:%+5.3f \r",
 		(float)(a_pts-delay), (float)((a_pts-delay) - old_apts),
 		 (float)v_pts, (float)(v_pts - old_vpts),
 		 AV_delay, c_total, delay, x);
--- /home/alban/MP/g2/video/Makefile	Mon May 12 01:47:03 2003
+++ /home/alban/MP/g2.dev/video/Makefile	Fri Jul 18 18:13:06 2003
@@ -12,7 +12,7 @@
 VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT)
 
 # vf_vo.c 
-VFILTER_SRCS=vf.c vf_scale.c vf_vo2.c vf_vd.c vf_pp.c vf_format.c vf_tfields.c # vf_crop.c vf_expand.c # vf_format.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_rectangle.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c 
+VFILTER_SRCS=vf.c vf_scale.c vf_vo2.c vf_vd.c vf_pp.c vf_format.c vf_tfields.c vf_osd.c # vf_crop.c vf_expand.c # vf_format.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_rectangle.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c 
 ENCODER_SRCS=ve.c # ve_lavc.c # ve_divx4.c ve_vfw.c ve_rawrgb.c ve_libdv.c ve_xvid.c ve_qtvideo.c ve_nuv.c
 
 # NATIVE_SRCS=native/RTjpegN.c native/cinepak.c native/fli.c native/minilzo.c native/msvidc.c native/nuppelvideo.c native/qtrle.c native/qtrpza.c native/qtsmc.c native/roqav.c native/xa_gsm.c native/svq1.c
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.