foxsen 3d桌面以及xorg的修改

foxsen 于 2007-2-2 02:28

初步搞定3D驱动

glxgears fps with dri: 297  FPS
without:  66 FPS

好像效率还不高,也许是驱动里边太保守的缘故。具体过程明天再来写了

福珑3D攻略

很多朋友希望看到福珑上的3D,因此我化了一些时间去做这个事情,现在基本完成,在此把过程大概总结一下,以供参考。

我以前也没有玩过3D相关的东西,所以第一个碰到的问题就是了解概念。dri.freedesktop.org是一个不错的起点,看了看
之后大概了解了整体架构:

   * 内核提供drm驱动,为应用程序提供访问显卡3D硬件资源的API
   * xorg中包含2D驱动,服务器端的GLX和能装载3D驱动的GL库
   * 3D驱动在mesa的源码包中
   
由于我们使用debian,源代码包就不用从cvs下了,直接用debian打包好的,具体涉及的代码包括:
   xorg-server-1.1.1
   xserver-xorg-video-ati-6.6.3
   libdrm-2.0.2
   mesa-6.5.1
   kernel source 2.6.18
除了最后一个都是apt-get source取来的,因此编译方便得很,只要用apt-get build-dep packagename就可以装上依赖的东西,
不用重复编译很多次。

其实这些东西的二进制都是现成的,因此我一上来就想看一下是不是可以白捡:
   把/etc/X11/xorg.conf中的dri/glx模块装载上
   Section "Module"
        Load    "i2c"
        Load    "bitmap"
        Load    "ddc"
        Load    "dri"             //这个
        Load    "extmod"
        Load    "freetype"
        Load    "glx"             //这个
        Load    "int10"
        Load    "vbe"
   EndSection
   对应的是/usr/lib/xorg/modules/extensions/下的libdri.so和libglx.so,源代码则在xorg-xserver-1.1.1里边
   把内核的radeon drm模块选上,安装(drivers/char/drm/{drm.ko,radeon.ko})
   (具体过程略,没时间了;主要碰到的问题包括drmopen失败(page size问题),writeback test failed(内存访问cache一致性问题),死锁(drm lock原语不支持mips))
   
   xorg-server-1.1.1:
     1. hw/xfree86/dri/sarea.h
由于龙芯采用16k page size,因此SAREA_MAX必须定义为0x4000
     /* SAREA area needs to be at least a page */
#if defined(__alpha__)
#define SAREA_MAX                       0x2000         
+#elif defined(__mips__)
+#define SAREA_MAX                       0x4000
#elif defined(__ia64__)
#define SAREA_MAX                       0x10000         /* 64kB */
#else
/* Intel 830M driver needs at least 8k SAREA */
#define SAREA_MAX                       0x2000
#endif
      
系统头文件和meda/libdrm以及内核等也有类似文件,都需要同样修改,以免应用程序出问题:
/usr/include/xorg/sarea.h
/usr/include/drm/drm_sarea.h
<kernel>/drivers/char/drm/drm_sarea.h
<mesa>/include/GL/internal/sarea.h

     2. hw/xfree86/os-support/
     增加mips架构的锁操作
     --- x.h 2009-01-30 13:07:12.000000000 +0800
+++ xf86drm.h   2007-01-30 02:04:04.000000000 +0800
@@ -327,6 +327,30 @@
                  "r" (new));                   \
        } while(0)

+#elif defined(__mips__)
+
+#define        DRM_CAS(lock, old, new, ret)            \
+       do {                                    \
+               __asm__ __volatile__(           \
+               "       .set mips3;.set noreorder;\n" \
+                "       sync; \n"             \
+               "       ll   %1, %0;\n"         \
+                "       bne  %1, %2, 1f;\n"            \
+               "        li   %1, 1; \n"     \
+               "       move %1, %3; \n"   \
+                "       sc    %1, %0;\n"               \
+                "       xori   %1, %1, 1\n"    \
+                "1:     \n"            \
+               "       .set mips0; .set reorder;\n"            \
+               : "=m" (__drm_dummy_lock(lock)),\
+                  "=&r" (ret)                  \
+               : "r" (old),                    \
+                 "r" (new)                     \
+               :"memory","$8" \
+               ); \
+       } while(0)
+
+
#elif defined(__sparc__)

#define DRM_CAS(lock,old,new,__ret)                            \
@@ -408,7 +432,7 @@
#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */
#endif

-#if defined(__alpha__) || defined(__powerpc__)
+#if defined(__alpha__) || defined(__powerpc__) || defined(__mips__)
#define DRM_CAS_RESULT(_result)                int _result
#else
#define DRM_CAS_RESULT(_result)                char _result

同样,系统头文件/usr/include/xf86drm.h也应该同样修改,这样mesa等编译的时候才会正确
                                                              

   mesa-6.5.1:
  相应头文件改过后重新编译即可。
  
  kernel: (见相关注释)
  Index: drm_bufs.c
===================================================================
--- drm_bufs.c        (revision 15)
+++ drm_bufs.c        (working copy)
@@ -194,7 +194,8 @@
                break;

        case _DRM_SHM:  /* 用uncache 方式访问以避免cache一致性问题,不确定对SHM是否必须 */
-                map->handle = vmalloc_32(map->size);
+                //map->handle = vmalloc_32(map->size);
+                map->handle = __vmalloc(map->size, GFP_KERNEL | __GFP_HIGHMEM ,  pgprot_noncached(PAGE_KERNEL));
                DRM_DEBUG("%lu %d %p\n",
                          map->size, drm_order(map->size), map->handle);
                if (!map->handle) {
Index: drm_scatter.c
===================================================================
--- drm_scatter.c        (revision 15)
+++ drm_scatter.c        (working copy)
@@ -113,7 +113,8 @@
        }
        memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr));
/* 用uncache 方式访问以避免cache一致性问题, sg内存是可能用来DMA的*/
-        entry->virtual = vmalloc_32(pages << PAGE_SHIFT);
+        //entry->virtual = vmalloc_32(pages << PAGE_SHIFT);
+        entry->virtual = __vmalloc(pages << PAGE_SHIFT, GFP_KERNEL | __GFP_HIGHMEM ,  pgprot_noncached(PAGE_KERNEL));
        if (!entry->virtual) {
                drm_free(entry->busaddr,
                         entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES);
@@ -162,6 +163,7 @@
                        unsigned long *tmp;

                        tmp = page_address(entry->pagelist);
                        /* 用uncached地址读写,才能通过writeback test*/
+                        tmp = (unsigned long*)UNCAC_ADDR((unsigned long)tmp);
                        for (j = 0;
                             j < PAGE_SIZE / sizeof(unsigned long);
                             j++, tmp++) {
@@ -180,6 +182,7 @@
                                }
                        }
                        tmp = page_address(entry->pagelist);
+                        tmp = (unsigned long*)UNCAC_ADDR((unsigned long)tmp);
                        for (j = 0;
                             j < PAGE_SIZE / sizeof(unsigned long);
                             j++, tmp++) {
@@ -191,6 +194,7 @@
        }
#endif

+
        return 0;

       failed:
Index: radeon_cp.c
===================================================================
--- radeon_cp.c        (revision 15)
+++ radeon_cp.c        (working copy)
@@ -877,7 +877,6 @@
        }

#if RADEON_FIFO_DEBUG
-        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
#endif
        return DRM_ERR(EBUSY);
@@ -898,7 +897,6 @@
        }

#if RADEON_FIFO_DEBUG
-        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
#endif
        return DRM_ERR(EBUSY);
@@ -924,7 +922,6 @@
        }

#if RADEON_FIFO_DEBUG
-        DRM_ERROR("failed!\n");
        radeon_status(dev_priv);
#endif
        return DRM_ERR(EBUSY);
@@ -2216,9 +2213,15 @@
        if (ret != 0)
                return ret;

/* first open 时增加这个map,但是根据pci bar的长度和物理显存大小不一致,会导致
    xorg match map list时失败
  */
+#if 0
        ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
                         drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
                         _DRM_WRITE_COMBINING, &map);
+#else
+        ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
+                         0x1000000, _DRM_FRAME_BUFFER,
+                         _DRM_WRITE_COMBINING, &map);
+#endif
        if (ret != 0)
                return ret;

Index: drm_sarea.h
===================================================================
--- drm_sarea.h        (revision 15)
+++ drm_sarea.h        (working copy)
/* 使用16k page,SAREA_MAX至少为1页 */
@@ -37,6 +37,8 @@
/* SAREA area needs to be at least a page */
#if defined(__alpha__)
#define SAREA_MAX                       0x2000
+#elif defined(__mips__)
+#define SAREA_MAX                       0x4000
#elif defined(__ia64__)
#define SAREA_MAX                       0x10000        /* 64kB */
#else
Index: drm_pci.c
===================================================================
--- drm_pci.c        (revision 15)
+++ drm_pci.c        (working copy)
/* virt_to_page 只能对付cached地址 */
@@ -113,7 +113,8 @@
        /* Reserve */
        for (addr = (unsigned long)dmah->vaddr, sz = size;
             sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-                SetPageReserved(virt_to_page(addr));
+//                SetPageReserved(virt_to_page(addr));
+                SetPageReserved(virt_to_page(CAC_ADDR(addr)));
        }

        return dmah;
@@ -147,7 +148,8 @@
                /* Unreserve */
                for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
                     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-                        ClearPageReserved(virt_to_page(addr));
+                //        ClearPageReserved(virt_to_page(addr));
+                        ClearPageReserved(virt_to_page(CAC_ADDR(addr)));
                }
                dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
                                  dmah->busaddr);
--- drm_vm.c    (revision 15)   /* 2007.02.02更新 */
+++ drm_vm.c    (working copy)
@@ -155,7 +155,7 @@
        offset = address - vma->vm_start;
        i = (unsigned long)map->handle + offset;
        page = (map->type == _DRM_CONSISTENT) ?
-               virt_to_page((void *)i) : vmalloc_to_page((void *)i);
+               virt_to_page((void *)CAC_ADDR(i)) : vmalloc_to_page((void *)i);
        if (!page)
                return NOPAGE_OOM;
        get_page(page);
@@ -279,7 +279,7 @@

        offset = address - vma->vm_start;       /* vm_[pg]off[set] should be 0 */
        page_nr = offset >> PAGE_SHIFT;
-       page = virt_to_page((dma->pagelist[page_nr] + (offset & (~PAGE_MASK))));
+       page = virt_to_page(CAC_ADDR(dma->pagelist[page_nr] + (offset & (~PAGE_MASK))));

        get_page(page);

@@ -479,6 +479,9 @@
        vma->vm_ops = &drm_vm_dma_ops;

        vma->vm_flags |= VM_RESERVED;   /* Don't swap */
+#ifdef __mips__
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif

        vma->vm_file = filp;    /* Needed for drm_vm_open() */
        drm_vm_open(vma);
@@ -503,6 +506,17 @@

EXPORT_SYMBOL(drm_core_get_reg_ofs);

+#ifdef __mips__
+static inline pgprot_t pgprot_noncached_accelerated(pgprot_t _prot)
+{
+       unsigned long prot = pgprot_val(_prot);
+
+       prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED_ACCELERATED;
+
+       return __pgprot(prot);
+}
+#endif
+
/**
  * mmap DMA memory.
  *
@@ -625,6 +639,13 @@
                                       vma->vm_end - vma->vm_start,
                                       vma->vm_page_prot))
#else
+#ifdef __mips__
+               if (map->type == _DRM_FRAME_BUFFER)
+                               vma->vm_page_prot = pgprot_noncached_accelerated(vma->vm_page_prot);
+                               //vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+               else
+                               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
                if (io_remap_pfn_range(vma, vma->vm_start,
                                       (map->offset + offset) >> PAGE_SHIFT,
                                       vma->vm_end - vma->vm_start,
@@ -646,11 +667,17 @@
                /* Don't let this area swap.  Change when
                   DRM_KERNEL advisory is supported. */
                vma->vm_flags |= VM_RESERVED;
+#ifdef __mips__
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
                break;
        case _DRM_SCATTER_GATHER:
                vma->vm_ops = &drm_vm_sg_ops;
                vma->vm_private_data = (void *)map;
                vma->vm_flags |= VM_RESERVED;
+#ifdef __mips__
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
                break;
        default:
                return -EINVAL; /* This should never happen. */

Index: ati_pcigart.c
===================================================================
--- ati_pcigart.c        (revision 15)
+++ ati_pcigart.c        (working copy)
@@ -175,7 +175,8 @@
                          bus_address, (unsigned long)address);
        }
/* 用uncache地址确保写入*/
-        pci_gart = (u32 *) address;
+//        pci_gart = (u32 *) address;
+        pci_gart = (u32 *) UNCAC_ADDR(address);

        pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
            ? entry->pages : ATI_MAX_PCIGART_PAGES;

     
   
大致如此,有事离开,其中碰到的几个关键现象和解决思路回头有空慢慢补上。


附件大小
debian_mesa_sarea 补丁524 字节
debian_libdrm_lock 补丁1.63 千字节
debian_xserver-xore-core_sarea 补丁518 字节
96_lnx_video_mmap.diff1.03 千字节