老狼[cgwolver]

QQ:419780024
随笔 - 37, 文章 - 0, 评论 - 64, 引用 - 0
数据加载中……

2009年4月1日

SwapBuffers的效率问题

最近看了ms实现的opengl 1.1 source,写的非常不错,但也发现了不少问题,而且这个问题在后续版本中并没有改掉(难道ms 为保 d3d 故意的?太恶劣了。。。)
这里就SwapBuffers API的问题简单说一下,希望大家看到他的缺陷,并且避开它。

这是ms opengl 1.1 中的source:

__inline FARPROC GetAPI(char *szDll, char *szAPI, HMODULE *phDll)
{
    *phDll = LoadLibraryA(szDll);

    if (*phDll == NULL)
    {
        return NULL;
    }

    return GetProcAddress(*phDll, szAPI);
}

/***********************************************************************/

BOOL WINAPI SwapBuffers(HDC hdc)
{
    HMODULE hDll;
    PFN5    pfn = (PFN5)GetAPI(szOpenGL, "wglSwapBuffers", &hDll);
    BOOL    bRet = FALSE;

    if (pfn)
    {
        bRet = (*pfn)(hdc);
    }
    
    if (hDll)
    {
        FreeLibrary(hDll);
    }
        
    return bRet;
}

可以看到SwapBuffers API的问题,很低效!为了证实opengl 的后续版本也存在这个问题,我在windows xp sp2 下用ida 5.2 打开gdi32.dll 找到了SwapBuffers 的反汇编代码如下:

.text:77F2599E ; *************** S U B R O U T I N E ***************************************
.text:77F2599E
.text:77F2599E ; Attributes: bp-based frame
.text:77F2599E
.text:77F2599E ; BOOL __stdcall SwapBuffers(HDC)
.text:77F2599E                 public __stdcall SwapBuffers(x)
.text:77F2599E __stdcall SwapBuffers(x) proc near
.text:77F2599E
.text:77F2599E hLibModule      = dword ptr -4
.text:77F2599E arg_0           = dword ptr  8
.text:77F2599E
.text:77F2599E                 mov     edi, edi
.text:77F259A0                 push    ebp
.text:77F259A1                 mov     ebp, esp
.text:77F259A3                 push    ecx
.text:77F259A4                 push    esi
.text:77F259A5                 lea     eax, [ebp+hLibModule]
.text:77F259A8                 push    eax             ; int
.text:77F259A9                 push    offset s_Wglswapbuffer ; "wglSwapBuffers"
.text:77F259AE                 push    offset s_Opengl32 ; "OPENGL32"
.text:77F259B3                 call    GetAPI(x,x,x)
.text:77F259B3
.text:77F259B8                 xor     esi, esi
.text:77F259BA                 test    eax, eax
.text:77F259BC                 jz      short loc_77F259C5
.text:77F259BC
.text:77F259BE                 push    [ebp+arg_0]
.text:77F259C1                 call    eax
.text:77F259C3                 mov     esi, eax
.text:77F259C3
.text:77F259C5
.text:77F259C5 loc_77F259C5:                           ; CODE XREF: SwapBuffers(x)+1Ej
.text:77F259C5                 cmp     [ebp+hLibModule], 0
.text:77F259C9                 jz      short loc_77F259D4
.text:77F259C9
.text:77F259CB                 push    [ebp+hLibModule] ; hLibModule
.text:77F259CE                 call    ds:FreeLibrary(x)
.text:77F259CE
.text:77F259D4
.text:77F259D4 loc_77F259D4:                           ; CODE XREF: SwapBuffers(x)+2Bj
.text:77F259D4                 mov     eax, esi
.text:77F259D6                 pop     esi
.text:77F259D7                 leave
.text:77F259D8                 retn    4
.text:77F259D8
.text:77F259D8 __stdcall SwapBuffers(x) endp

可以看到确实SwapBuffer每次调用都在GetAPI,而GetAPI先LoadLibrary,再GetProcAddress;虽然SwapBuffers每次LoadLibrary/FreeLibaray也许只是改变引用计数,但是我想GetProcAddress总是有开销的,即便有Cache机制也会有开销的。追根溯源,我又找到了GetProcAdress的source code,发现GetProcAddress是调用LdrGetProcedureAddress,继续追查,LdrGetProcedureAddress:

NTSTATUS
LdrpGetProcedureAddress (
    IN PVOID DllHandle,
    IN PANSI_STRING ProcedureName OPTIONAL,
    IN ULONG ProcedureNumber OPTIONAL,
    OUT PVOID *ProcedureAddress,
    IN BOOLEAN RunInitRoutines
    )

/*++

Routine Description:

    This function locates the address of the specified procedure in the
    specified DLL and returns its address.

Arguments:

    DllHandle - Supplies a handle to the DLL that the address is being
        looked up in.

    ProcedureName - Supplies that address of a string that contains the
        name of the procedure to lookup in the DLL.  If this argument is
        not specified, then the ProcedureNumber is used.

    ProcedureNumber - Supplies the procedure number to lookup.  If
        ProcedureName is specified, then this argument is ignored.
        Otherwise, it specifies the procedure ordinal number to locate
        in the DLL.

    ProcedureAddress - Returns the address of the procedure found in
        the DLL.

Return Value:

    TBD

--*/

{
    NTSTATUS st;
    UCHAR FunctionNameBuffer[64];
    PUCHAR src, dst;
    ULONG cb, ExportSize;
    PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    IMAGE_THUNK_DATA Thunk;
    PVOID ImageBase;
    PIMAGE_IMPORT_BY_NAME FunctionName;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
    PLIST_ENTRY Next;

    if (ShowSnaps) {
        DbgPrint("LDR: LdrGetProcedureAddress by ");
    }

    FunctionName = NULL;
    if ( ARGUMENT_PRESENT(ProcedureName) ) {

        if (ShowSnaps) {
            DbgPrint("NAME - %s\n", ProcedureName->Buffer);
        }

        //
        // BUGBUG need STRING to PSZ
        //


        if (ProcedureName->Length >= sizeof( FunctionNameBuffer )-1 ) {
            FunctionName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TEMP_TAG ),ProcedureName->Length+1+sizeof(USHORT));
            if ( !FunctionName ) {
                return STATUS_INVALID_PARAMETER;
                }
        } else {
            FunctionName = (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer;
        }

        FunctionName->Hint = 0;

        cb = ProcedureName->Length;
        src = ProcedureName->Buffer;
        dst = FunctionName->Name;

        ImageBase = NtCurrentPeb()->ImageBaseAddress;
        while (cb--) {
            *dst++ = *src++;
        }
        *dst = '\0';

        Thunk.u1.AddressOfData = FunctionName;

    } else {
             if (ShowSnaps) {
                 DbgPrint("ORDINAL - %lx\n", ProcedureNumber);
             }

             if (ProcedureNumber) {
                 Thunk.u1.Ordinal = ProcedureNumber | IMAGE_ORDINAL_FLAG;
             } else {
                      return STATUS_INVALID_PARAMETER;
                    }
          }

    if ( LdrpInLdrInit == FALSE ) {
        RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
        }
    try {

        if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
            st = STATUS_DLL_NOT_FOUND;
            return st;
        }

        ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
                           LdrDataTableEntry->DllBase,
                           TRUE,
                           IMAGE_DIRECTORY_ENTRY_EXPORT,
                           &ExportSize
                           );

        if (!ExportDirectory) {
            return STATUS_PROCEDURE_NOT_FOUND;
        }

        st = LdrpSnapThunk(LdrDataTableEntry->DllBase,
                           0,
                           &Thunk,
                           &Thunk,
                           ExportDirectory,
                           ExportSize,
                           FALSE,
                           NULL
                          );

        if ( RunInitRoutines ) {

            //
            // Look at last entry in init order list. If entry processed
            // flag is not set, then a forwarded dll was loaded during the
            // getprocaddr call and we need to run init routines
            //

            Next = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
            LdrDataTableEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
            if ( !(LdrDataTableEntry->Flags & LDRP_ENTRY_PROCESSED) ) {
                try {
                    st = LdrpRunInitializeRoutines(NULL);
                    }
                except( EXCEPTION_EXECUTE_HANDLER ) {
                    st = GetExceptionCode();
                    }

                }
            }

        if ( NT_SUCCESS(st) ) {
            *ProcedureAddress = Thunk.u1.Function;
            }
    } finally {
        if ( FunctionName && (FunctionName != (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer) ) {
            RtlFreeHeap(RtlProcessHeap(),0,FunctionName);
            }
        if ( LdrpInLdrInit == FALSE ) {
            RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
            }
    }
    return st;
}

LdrpGetProcedureAddress 其实是去查IAT,找到函数地址,并返回。

我想,关于SwapBuffers这个被频繁调用的API的性能的问题,也许用性能分析工具,比如intel vtune或者amd codeanalyst 就可以看得出来,下面使用vs2005中使用自带的PerformanceTools进行分析了一个性能分析,测试代码如下:

for( int i = 0;i<100;i++ )
{        
    ::glClear( GL_COLOR_BUFFER_BIT );
    ::SwapBuffers( wnd->m_hdc );
}
        
for( int i = 0;i<100;i++ )
{
    ::glClear( GL_COLOR_BUFFER_BIT );
    wglSwapBuffers( wnd->m_hdc );
}

测试结果分三次:

第一次:
                                  Time( msecs )             %
SwapBuffers               1379.503985                21.323
wglSwapBuffers          1333.716537                20.615

第二次:
                                  Time( msecs )             %
SwapBuffers               1374.064678                29.757
wglSwapBuffers          1333.665637                28.882

第三次:
                                  Time( msecs )             %
SwapBuffers               1382.822897                21.076
wglSwapBuffers          1334.037943                20.332

测试环境:

CPU:Intel Core2 Duo  E4500 2.20 GHz  
显卡:NVIDIA GEFORCE 8600 GT
OS:Windows XP SP2

上面的数据就是最好的说明,平均每帧多开销0.5个毫秒。想一下,FPS达到 30帧的时候,每帧可用时间片只有33毫秒,却被它白白浪费的0.5个毫秒。

要避免这个问题,最好还是自己去获得wglSwapBuffers这个函数,才是最高效的,因为wglSwapBuffers是厂商驱动提供的。在软模式opengl下,它也会回调os 的 GdiSwapBuffers

另外其他API的问题也是这样的 ChoosePixelFormat,DescribePixelFormat,GetPixelFormat,SetPixelFormat,它们都是先得到wglXXX版本的函数地址,比如wglChoosePixelFormat,wglDescribePixelFormat,wglGetPixelFormat,wglSetPixelFormat然后再调用。

我曾经遇到过这样的问题,在真正opengl调用之前调用DescribePixelFormat,会非常慢。他一定是LoadLibrary ,FreeLibrary,从下面的输出窗口可以看到执行的时候会输出加载卸载opengl32.dll的信息。但是当opengl api 被调用后,这个时候就LoadLibrary,FreeLibrary 只是改变饮用计数了。一种解决的方法是,在调用ChoosePixelFormat,DescribePixelFormat,GetPixelFormat,SetPixelFormat这些函数之前,先调用 LoadLibrary("OpenGL32.dll");这样就不会频繁的加载卸载dll;更好的方法还是自己获取wgl版本的相应函数;
如果你要列举所有像素格式,如果不这么做,会发现慢的要死,每个调用都要LoadLibrary/FreeLibrary。

posted @ 2009-04-01 16:15 老狼[cgwolver] 阅读(481) | 评论 (2)编辑

2009年3月10日

Windows 管理员密码破解工具

单击这里下载 lc4.rar

posted @ 2009-03-10 14:14 老狼[cgwolver] 阅读(175) | 评论 (0)编辑

2009年1月15日

Overload new and delete operator

// for stdandard type

#pragma pack(push,8)
#pragma warning(push,3)

#pragma push_macro("new")
#undef new

inline void* __cdecl operator new(size_t size)
{
     return malloc(size);
}
inline void* __cdecl operator new(size_t size,const char*file,const int line)
{
     return malloc(size);
}
inline void __cdecl operator delete(void*ptr)
{
     return free(ptr);
}

inline void* __cdecl operator new[](size_t size)
{
     return ::operator new(size);
}
inline void __cdecl operator delete[](void* p)
{
     ::operator delete(p);
}

inline void * __cdecl operator new( size_t size, void *p )

     return  realloc( p,size);
}
inline void * __cdecl operator new[]( size_t size, void *p )

     return  realloc( p,size);
}

#pragma pop_macro("new")

//for c++ class

class CWnd

{

     inline void* operator new(size_t size)
     {    
         return malloc(size);
     }
     inline void*operator new(size_t size,const char*file,const int line)
     {
         return malloc(size);
     }
     inline void operator delete(void*ptr)
     {
         return free(ptr);
     }     
     inline void* operator new[](size_t size)
     {
         void* p =  malloc(size);
         return p;
     }    
     inline void operator delete[](void* p)
     {
         operator delete(p);
     } 
     void *operator new( size_t size, void *p ) 
     { 
         return  realloc( p,size);
     }
     void *operator new[]( size_t size, void *p ) 
     { 
         unsigned int * p1 = (unsigned int*)((unsigned int) p - 4);
         CWnd* p2 = (CWnd*)p;
         for( int i = 0;i<size;i++)
              p2[i].~CWnd();
         return  realloc( p1,size);
     }

}

posted @ 2009-01-15 12:50 老狼[cgwolver] 阅读(75) | 评论 (0)编辑

2009年1月8日

Deferred Contexts

     摘要: MS dx11 搞出一个Deferred Contexts来,我愤怒了!纯属噱头!更让我愤怒的是国内各网站都在叼着噱头瞎嚷嚷!  阅读全文

posted @ 2009-01-08 19:05 老狼[cgwolver] 阅读(80) | 评论 (0)编辑

2009年1月7日

wglSwapMultipleBuffers --- an undocumented wgl api

     摘要: wglSwapMultipleBuffers是一个未载入文档的一个wgl API,这是用opengl实现 multiple “swap chain” 或者叫做多重视图的最佳方法;  阅读全文

posted @ 2009-01-07 02:00 老狼[cgwolver] 阅读(253) | 评论 (0)编辑

2009年1月6日

ms opengl 1.1 source download

本贴下载已关闭,详情请察看: http://www.enginedev.net/read.php?tid-7.html

posted @ 2009-01-06 16:03 老狼[cgwolver] 阅读(534) | 评论 (39)编辑

使用 mapfile 访问 dll 中的变量

1)使用 ida 生成 map file

2)使用 GetModuleHandle 获得 dll起始地址

3)使用 ImageNtHeader 获得 Nt 头

4)根据Nt 头中的 Sections 和 NumberOfSections 访问每一个Section

5)根据Section的相对虚拟地址VirtualAddress计算绝对虚拟地址计算出sector 的虚拟地址

     使用ImageRvaToVa 或者使用pSection->PointerToRawData +ModuleBase

6)根据map file 中的“段号:段内偏移”的偏移计算实际的虚拟地址

      0004:00000150       var_3

     

posted @ 2009-01-06 12:52 老狼[cgwolver] 阅读(47) | 评论 (0)编辑

Hex-Rays.Decompiler ...

Hex-Rays.Decompiler适合对二进制代码进行分析的程序员。它把可执行程序解读成类C语言的代码,具有简洁,结构清楚的特点,这是针对DataRescue.IDA.Pro.Advanced.v5.2的版本

DataRescue.IDA.Pro.Advanced.v5.2.windows-YAG.zip 
Hex-Rays.Decompiler.v1.0.for.DataRescue.IDA.Pro.Advanced.v5.2-YAG.zip 

posted @ 2009-01-06 10:28 老狼[cgwolver] 阅读(319) | 评论 (0)编辑

2009年1月4日

OpenGL Driver Architecture[转]

OpenGL Driver Architecture
Yang Jian
jyang@cad.zju.edu.cn

1 OpenGL Installable Client Driver 
Windows下OpenGL Driver有三种类型,可安装的客户端驱动程序(Installable Client Driver
,缩写为ICD),微驱动(minidriver)和独立驱动程序。独立驱动程序主要是为一些特殊的图形系统设计,这些图形系统的能力相对比较强大,整个系统的主要目的为图形应用,目前已经不多见。MiniDriver在3D图形加速卡没有普及之前曾经被使用过,但是有由于其支持的能力太低,自nvi
dia TNT 之后就看不到这类驱动程序。
   现在图形芯片供应商都采用ICD的方式提供OpenGL Driver。ICD的最大特点是(1)能够支持OpenGL驱动程序开发者提供完整的OpenGL支持,和OpenGL Extension支持;(2)使得OpenGL能够以client-server的方式运行;(3)对OpenGL应用程序开发者提供统一的API接口。

下面是一个OpenGL ICD驱动程序体系结构的简图。


         Application
            |
|
GDI32.dll<---OpenGL32.dll ---? winsrv.dll
|           |
|        |
--------  xxgl.dll(example, nvoglnt.dll, atioglxx.gl, )  ------? DirectDraw5~7
        |                                 |
        |                                     |----? Direct3D8   or above
      3d graphics card(Hardware)

其中
OpenGL32.dll是微软基于软件实现的OpenGL。
Nvntgl.dll或者atiglxx.dll分别是Nvidia和ATI提供的OpenGL ICD驱动程序。
同时OpenGL32.dll和图形芯片供应商的驱动程序都需要访问DirectDraw和GDI32。
个别的OpenGL驱动程序甚至使用了Direct3D8或者更高的版本。

2 确定当前图形加速卡的ICD驱动
   
    对于Windows98/me的系统,可以注册表的下面位置查找:
“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OpenGLDrivers”

对于Windows 2000/XP的系统,请定位到注册表的下述位置:
“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers”

    运行 regedit.exe可以进入注册表。
3 基于ICD的OpenGL数据流分析
   我们使用上图作为分析基础。

   3.1 像素格式
   首先,OpenGL 应用程序检测图形加速卡能够支持的像素格式,主要是Back Color Buffer,Depth Buffer和Stencil Buffer。目前需要图形加速卡都不再支持8-bits的Back Buffer。ATI和Nvidia的许多图形卡均不支持32-bits的Depth
Buffer,一般都是D16,D24和D24S8(24-bitsDepth和8-bits的Stencil)。
   当Application调用DescribePixelFormat,  GetPixelFormat,  SetPixelFormat,
ChoosePixelFormat,应用程序把这些调用传递给OpenGL32,OpenGL32首先显示卡驱动程序检测能够支持的OpenGL像素格式,显示卡驱动程序对应有多个回调函数,DrvDescribePixelFormat(显示驱动), DrvSetPixelFormat(显示驱动)等。
       如果显示驱动没有对应的回调函数,OpenGL32.dll会调用ICD驱动中对应的函数完成这个工作。大家可以使用VC6.0中的工具Depends打开nvoglnt.dll(nvidia)或者atioglxx..dll(ATI),我们可以看到他们都实现下面上面两个回调函数:
        DrvDescribePixelFormat(ICD驱动)
        DrvSetPixelFormat(ICD驱动)
    不过大家可能觉得奇怪,nividia或者ATI的OpenGL驱动只有几个函数,而且都是以Drv*开头,下面我会给大家一个解答。

  2.2 Context 创建与设置当前Context
    当我们的应用程序调用wglCreateContex的时候,OpenGL32.dll的wglCreateContext函数将参数转化后,调用ICD Driver的DrvCreateContext函数,DrvCreateContext函数然后调用ICD Driver的DrvCreateLayerContext,其中有一个参数是HDC,ICD Driver通过HDC
获得当前的像素格式ID,实际上这个像素格式ID就是ICD Driver本身定义的。DrvCreateLayerContext将产生一个OpenGL Context的内部数据结构,同时根据像素格式ID将对应的像素格式设置到OpenGL context的内部数据结构,同时向OpenGL32.dll的wglCreateContext返回这个OpenGL
context的编号,一般是从0开始向上递增。
   请注意,这时候,你换无法调用OpenGL API,因为应用程序还没有调用wglMakeCurrent。
       
   我们现在可以调用wglMakeCurrent,因为我们已经创建一个OpenGL Context。wglMakeCurrent将调用ICD Driver的DrvSetContext。DrvSetContext将完成以下工作:
(1)   根据HDC获取当前的窗口句柄,HWND;
(2)   初始化内部数据结构;
(3)   初始化SW OpenGL context的常量和回调函数
(4)   创建back color buffer, Depth Buffer 和stencil Buffer,和其他类型的缓冲区;
(5)   调用硬件OpenGL context 的初始化函数,初始化硬件OpenGL context的常量和回调函数;
(6)   HW OpenGL Context 设置正确的glGetString返回值;
(7)   设置一个当前的__glDispatchTable,并且返回这个Dispatchtable。

    这些工作中有两项任务需要说明,一是如何创建缓冲区,二是Dispatchtable是何方怪物。

   颜色缓冲区,深度缓冲区和模板缓冲区是位于图形加速卡上的一块显示内存区域,它是由图形加速卡的显示驱动程序所管理,OpenGL ICD Driver是无法直接访问和申请的。所以OpenGL ICD
Driver通过IDirectDraw7::CreateSurface申请。不过一些显示芯片供应上通过IDirect3DDevice::CreateBackBuffer或者IDirect3DDevice::CreateDepthStencilBuffer获得,两种方法并没有本质上的差异。另外还有一种方法是通过ExtEscape的方法创建缓冲区,这种方法比较复杂,我就不
讲了。
需要注意的是:目前的硬件体系结构将Depth Buffer和Stencil Buffer结合在一起,它们在显示内存中相互交叠,一般的存储格式为:24-bits Depth, 8-bits Stencil, 24-D, 8-S,….

glDispatchTable是OpenGL ICD 驱动程序最为关键的一个结构。它们OpenGL 所有API函数指针的一个结构。
它基本定义如下:
struct glDispatchTable{
void (APIENTRY *glAccum) (GLenum op, GLfloat value);
    void (APIENTRY *glAlphaFunc) (GLenum func, GLclampf ref);
    …..
};

OpenGL的每一个函数都都有一个对应的函数指针定义。DrvSetContext负责返回一个glDispatchTable结构指针,将ICD Driver中所有OpenGL API的函数指针赋值给glDispatchTable,使得OpenGL32.dll能够直接调用ICD Driver中对应的OpenGL函数。
例如,应用程序调用glBegin,将会产生如下的调用顺序:
    Application Call glBegin  ==  >
    OpenGL32.dll  glBegin
      {
           (*__glDispatchTable.glBegin)();  == >
       }  

     ICD Driver Call glBegin
     {
        ….
}

    也就是说通过glDispatchTable,所有的OpenGLAPI最终都将进入到ICD Driver对应的函数中。

    啰嗦这么多,相信大家该对OpenGL体系结构有一个大致的认识了。下面我将另外一个内容,OpenGL ICD是如何实现Display List。

3.3     ICD Driver中Display List的实现。
    OpenGL中Display List是一种加速绘制的方法,那么它内部是如何实现的呢?
    其实相当简单。
    首先ICD Driver对每一个OpenGL API进行编号,例如,glAccum是0,glAlphaFunc是2,
    #define __GL_DLISTOP_ACCUM          0
    #define __GL_DLISTOP_ ALPHAFUNC     1
….
  当应用程序调用glNewList生成一个新的Display List,ICD Driver分配一个数组,其中每个元素定义如下
   struct  listop{
        int         opcode; //对应上面的API编号
        void*   parameter;
};

如果我们在Display List中调用glVertex3F,那么ICD Driver调用如下代码(真实代码要复杂些),这时候ICD Driver仅仅将这些命令和它们的参数保存数组中,并不处理这个API。
    plistop->opcode   = __GL_DLISTOP_VERTEX3F;
    (GLfoat*)plistop->parameter = x;
((GLfoat*)plistop->parameter)++ = y;
((GLfoat*)plistop->parameter)++ = z;

然后,当应用程序调用一个glCallList的时候,ICD Driver首先找到那个数组,根据每个listop的opcode调用对应的处理函数。
  

  3.4 ICD Driver中纹理的管理
    OpenGL ICD Driver无法直接申请显示内存,但是图形硬件需要使用纹理数据实现问题贴图。那么ICD Driver必须能够将纹理数据拷贝到显示内存或AGP memory, 即Local Video Memory ,non-local Video Memory。AGP
memory是操作系统管理的,经过GART映射后图形处理芯片可以访问的特殊内存区域。

   当我们调用一个glTexImage2D的函数定义纹理的时候,ICD Driver首先创建一块系统内存区域,将纹理数据拷贝到系统内存。然后调用IDirectDraw7::CreateSurface申请video memory。如果申请失败,而且video
memory存储空间不足,表明现在有太多的应用程序在运行,或者这个应用程序申请了太多的video memory,需要释放一些纹理内存空间,调用IDirctDrawSurface7::Release一些video memory空间。一般采用FIFO的方式实现内存的替换管理。
    当video memory申请成功后,调用IDirectDrawSurface7::Lock获得video memory的用户地址,将保存在系统内存中的数据复制到video memory中。图形芯片就能够访问纹理数据了。

  3.5 wglMakeCurrent(NULL, NULL)
    当应用程序调用wglMakeCurrent(NULL),OpenGL32.dll将调用ICD Driver中的DrvReleaseContext使得所有的OpenGL API都成为空操作,不会产生任何结果。

  3.6 SwapBuffer的实现
   如果是窗口程序,ICD Driver 的DrvSwapBuffers将调用IDirectDrawSurface7::Blt实现从后台缓冲区到前台缓冲区的内容复制。
   如果是全屏幕程序,DrvSwapBuffers将调用IDirectDrawSurface7::flip实现快速的前后缓冲区切换。
    一些驱动程序使用IDirect3DDevice8::Present或者IDirect3DDevice9::Present实现缓冲区内容的切换。

3.7 wglDeleteContext
wglDeleteContext将调用DrvDeleteCOntext,它将释放所有申请的系统内存和显示内存(video memory),以及纹理,并且删除硬件OpenGL context和软件OpenGL context。而且所有的OpenGL API将不可用。

4 OpenGL ICD Driver 评价
  目前OpenGL ICD Driver都相当成熟,基本上都是沿用SGI提供的参考框架结构。大家可以参考下面的链接获取SGI的OpenGL driver实现:
    http://oss.sgi.com/projects/ogl-sample/

目前OpenGL做得最好的是3dlabs,它能够支持OpenGL 2.0。
ATI 和 nvidia都支持 OpenGL 1.4,不过ATI支持更多的OpenGL extension。
其他如SIS, XGI, S3支持的API比nvidia要少一些。
Intel等集成显示卡的驱动自然很差了,硬件能力为OpenGL 1.2或者OpenGL 1.3.

5 Linux的OpenGL Driver体系结构
    Linux下为DRI(Direct Render Infrastrcture),有兴趣可以参考它的网站;
http://dri.sourceforge.net/cgi-bin/moin.cgi

posted @ 2009-01-04 17:41 老狼[cgwolver] 阅读(247) | 评论 (0)编辑

About depends walker ...

用了这么多年vc,才知道有个depends walker,我太cj了。。。

vs2005 在 \Microsoft Visual Studio 8\Common7\Tools\Bin 路径下面

如果你还不知道是什么,就自己去看吧

 

posted @ 2009-01-04 17:19 老狼[cgwolver] 阅读(51) | 评论 (0)编辑