DX学习笔记之Surfaces PART 1
声明:本文完全翻译自DX SDK Documentation
一个surface代表了显存中的一块线性区域,通常在显卡的显存中,尽管surface也可以存在系统内存中。surface是被IDirect3DSurface9接口管理的。
1. front buffer:一块矩形内存,会被graphics adapter翻译并在显示屏上显示。在D3D中,程序从来不会直接往front buffer上写的。
2. back buffer:一块矩形内存,程序可以直接写;它永远不会直接被显示到显示器上。
3. flipping surface: 将back buffer移到front buffer的过程。
4. swap chain: 一组,一个或多个,back buffer,可以被顺序地present到front buffer上。
Getting a Surface
可以通过调用如下方法,创建一个surface:
IDirect3DDevice9::CreateDepthStencilSurface
IDirect3DDevice9::CreateOffscreenPlainSurface
IDirect3DDevice9::CreateRenderTarget
surface format决定了surface内存中的pixel数据是如何解析的。D3D使用结构体D3DSURFACE_DESC中的D3DFORMAT成员来描述surface format。我们可以查看某一个存在surface的格式通过调用IDirect3DSurface9::GetDesc方法。
一旦一个surface已经创建,可以调用如下方法来获得它的指针:
IDirect3DCubeTexture9::GetCubeMapSurface
IDirect3DDevice9::GetBackBuffer
IDirect3DDevice9::GetDepthStencilSurface
IDirect3DDevice9::GetFrontBufferData
IDirect3DDevice9::GetRenderTarget
IDirect3DDevice9::GetBackBuffer
IDirect3DDevice9::GetSurfaceLevel
IDirect3DDevice9接口允许我们直接访问内存,通过IDirect3DDevice9::UpdateSurface方法。该方法允许我们将一个IDirect3DDevice9 surface的矩形区域拷贝到另一个IDirect3DDevice9 surface。surface接口同样提供直接访问显存的方法。例如,你可以使用IDirect3DDevice9::LockRect方法锁住显存上的一块矩形区域。千万别忘记调用IDirect3DDevice9::UnlockRect解锁surface上的那块区域,当你完成工作后。
Surface Format
pixel的类型用枚举类型D3DFORMAT来表示。例如D3DFMT_R5G6B5,5位给red,6为给green,5位给blue。
What is a Swap Chain
显卡hold一个指针,指向一个正在被显示到显示器上的surface,叫做front buffer。当显示器刷新的时候,显卡就会将front buffer的内容送到显示器上去显示。然后,这可能会导致一个问题,跟计算机的其它部件相比,显示器的刷新频率非常低,60~100hz。如果你的程序正在更新front buffer,而这时显示器正在刷新,或许用户会看到一个撕扯的画面,一半新的,一半旧的。
D3D提供两种方法来解决这个问题:
1. 我们在显示器做vertical retrace操作时,做front buffer的更新。显示器典型的刷新就从左上角到右下角逐行扫描的,在扫描完后,会有一个vertical retrace操作,即从右下角回到左上角去,在这个操作期间,我们更新front buffer是不会出现问题的。vertical retrace的操作是比较慢的,但是,不够慢到可以等待我们渲染一个非常大的场景,因此我们还需要一个新的机制,back buffering。
2. back buffering就是将场景画到off-screen的surface上,及back buffer。通过使用back buffer,我们就无需担心显示器的刷新频率了,程序可以决定什么时候将back buffer 移动到front buffer去。
移动back buffer到front buffer的过程叫做surface flipping。因为,surface都是用指针指着的,所以这个过程只需做一个指针改变而已。当程序命令D3D将back buffer移动到front buffer去时,D3D其实就做了一个flip pointer的动作。D3D一般会将flip的请求放到一个queue里,等待vertical retrace的发生。surface flipping非常重要,在多媒体,动画,游戏中;它等价于迅速翻一本漫画书,看到动画的意味。
Width vs. Pitch
D3D用结构体D3DSURFACE_DESC来描述surface,其中包括了surface的大小(宽跟高,单位是pixel),以及在内存中的表示。但我们使用IDirect3DSurface9::LockRect方法时,描述结构体D3DLOCKED_RECT里是用pitch来形容surface的。pitch值描述了surface的pitch,俗称stride,它表示图片中的一行(值就是两个内存地址的差,图片某行的开始,跟图片下行的开始),单位是byte。pitch的变动很大,它往往不仅仅是宽度×pixel的bytes,还有cache(pitch的值可能是照片被cache那部分的bytes总和),对其等因素。所以我们一定要使用IDirect3DSurface9::LockRect方法返回的ptich值,不要自己擅自算一个自以为是正确的pitch值。
Flipping Surfaces
每一个设备至少有一个swap chain。当初始化D3D设备时,设置D3DPRESENT_PARAMETERS中的BackBufferCount值来告诉D3D我们swap chain中back buffer的数量。然后调用IDirect3D9::CreateDevcie来创建设备及swap chain。
我们调用IDirect3DDevcie9::Prensent时,会发出surface flip请求。front buffer跟其他back buffer间的flipping是一个循环的模式。
当程序是多视图时,我们可以用IDirect3DDevice9::CreateAddtitionalSwapChain来创建额外的swap chain,然后每一个swap chain结合一个视图窗口。在调用该函数的时候,需要两个参数,一个是D3DPRESENT_PARAMETERS,另一个是IDirect3DSwapChain9接口的指针。然后,我们就可以直接调用IDirect3DSwapChain9::Present了。
我们可以访问某一个特定的back buffer,通过调用IDirect3DSwapChain9::GetBackBuffer或者IDirect3DDevcie9::GetBackBuffer,它会返回IDirect3DSurface接口指针,代表back buffer surface。该调用会自动增加IDirect3DDevcie9接口的引用计数,所以一定要记住调用IUnknown当我们使用完该surface,否则会内存泄漏。
要记住:swap chain对应的是present动作,display adapter driver做的是flipping操作。
While such "Present" operations are almost invariably implemented by flip operations when the swap chain is a full-screen one, they are necessarily implemented by copy operations when the swap chain is windowed. Furthermore, a display adapter driver may use flipping to implement Present operations against full-screen swap chains based on the D3DSWAPEFFECT_DISCARD and D3DSWAPEFFECT_COPY.
一个surface代表了显存中的一块线性区域,通常在显卡的显存中,尽管surface也可以存在系统内存中。surface是被IDirect3DSurface9接口管理的。
1. front buffer:一块矩形内存,会被graphics adapter翻译并在显示屏上显示。在D3D中,程序从来不会直接往front buffer上写的。
2. back buffer:一块矩形内存,程序可以直接写;它永远不会直接被显示到显示器上。
3. flipping surface: 将back buffer移到front buffer的过程。
4. swap chain: 一组,一个或多个,back buffer,可以被顺序地present到front buffer上。
Getting a Surface
可以通过调用如下方法,创建一个surface:
IDirect3DDevice9::CreateDepthStencilSurface
IDirect3DDevice9::CreateOffscreenPlainSurface
IDirect3DDevice9::CreateRenderTarget
surface format决定了surface内存中的pixel数据是如何解析的。D3D使用结构体D3DSURFACE_DESC中的D3DFORMAT成员来描述surface format。我们可以查看某一个存在surface的格式通过调用IDirect3DSurface9::GetDesc方法。
一旦一个surface已经创建,可以调用如下方法来获得它的指针:
IDirect3DCubeTexture9::GetCubeMapSurface
IDirect3DDevice9::GetBackBuffer
IDirect3DDevice9::GetDepthStencilSurface
IDirect3DDevice9::GetFrontBufferData
IDirect3DDevice9::GetRenderTarget
IDirect3DDevice9::GetBackBuffer
IDirect3DDevice9::GetSurfaceLevel
IDirect3DDevice9接口允许我们直接访问内存,通过IDirect3DDevice9::UpdateSurface方法。该方法允许我们将一个IDirect3DDevice9 surface的矩形区域拷贝到另一个IDirect3DDevice9 surface。surface接口同样提供直接访问显存的方法。例如,你可以使用IDirect3DDevice9::LockRect方法锁住显存上的一块矩形区域。千万别忘记调用IDirect3DDevice9::UnlockRect解锁surface上的那块区域,当你完成工作后。
Surface Format
pixel的类型用枚举类型D3DFORMAT来表示。例如D3DFMT_R5G6B5,5位给red,6为给green,5位给blue。
What is a Swap Chain
显卡hold一个指针,指向一个正在被显示到显示器上的surface,叫做front buffer。当显示器刷新的时候,显卡就会将front buffer的内容送到显示器上去显示。然后,这可能会导致一个问题,跟计算机的其它部件相比,显示器的刷新频率非常低,60~100hz。如果你的程序正在更新front buffer,而这时显示器正在刷新,或许用户会看到一个撕扯的画面,一半新的,一半旧的。
D3D提供两种方法来解决这个问题:
1. 我们在显示器做vertical retrace操作时,做front buffer的更新。显示器典型的刷新就从左上角到右下角逐行扫描的,在扫描完后,会有一个vertical retrace操作,即从右下角回到左上角去,在这个操作期间,我们更新front buffer是不会出现问题的。vertical retrace的操作是比较慢的,但是,不够慢到可以等待我们渲染一个非常大的场景,因此我们还需要一个新的机制,back buffering。
2. back buffering就是将场景画到off-screen的surface上,及back buffer。通过使用back buffer,我们就无需担心显示器的刷新频率了,程序可以决定什么时候将back buffer 移动到front buffer去。
移动back buffer到front buffer的过程叫做surface flipping。因为,surface都是用指针指着的,所以这个过程只需做一个指针改变而已。当程序命令D3D将back buffer移动到front buffer去时,D3D其实就做了一个flip pointer的动作。D3D一般会将flip的请求放到一个queue里,等待vertical retrace的发生。surface flipping非常重要,在多媒体,动画,游戏中;它等价于迅速翻一本漫画书,看到动画的意味。
Width vs. Pitch
D3D用结构体D3DSURFACE_DESC来描述surface,其中包括了surface的大小(宽跟高,单位是pixel),以及在内存中的表示。但我们使用IDirect3DSurface9::LockRect方法时,描述结构体D3DLOCKED_RECT里是用pitch来形容surface的。pitch值描述了surface的pitch,俗称stride,它表示图片中的一行(值就是两个内存地址的差,图片某行的开始,跟图片下行的开始),单位是byte。pitch的变动很大,它往往不仅仅是宽度×pixel的bytes,还有cache(pitch的值可能是照片被cache那部分的bytes总和),对其等因素。所以我们一定要使用IDirect3DSurface9::LockRect方法返回的ptich值,不要自己擅自算一个自以为是正确的pitch值。
Flipping Surfaces
每一个设备至少有一个swap chain。当初始化D3D设备时,设置D3DPRESENT_PARAMETERS中的BackBufferCount值来告诉D3D我们swap chain中back buffer的数量。然后调用IDirect3D9::CreateDevcie来创建设备及swap chain。
我们调用IDirect3DDevcie9::Prensent时,会发出surface flip请求。front buffer跟其他back buffer间的flipping是一个循环的模式。
当程序是多视图时,我们可以用IDirect3DDevice9::CreateAddtitionalSwapChain来创建额外的swap chain,然后每一个swap chain结合一个视图窗口。在调用该函数的时候,需要两个参数,一个是D3DPRESENT_PARAMETERS,另一个是IDirect3DSwapChain9接口的指针。然后,我们就可以直接调用IDirect3DSwapChain9::Present了。
我们可以访问某一个特定的back buffer,通过调用IDirect3DSwapChain9::GetBackBuffer或者IDirect3DDevcie9::GetBackBuffer,它会返回IDirect3DSurface接口指针,代表back buffer surface。该调用会自动增加IDirect3DDevcie9接口的引用计数,所以一定要记住调用IUnknown当我们使用完该surface,否则会内存泄漏。
要记住:swap chain对应的是present动作,display adapter driver做的是flipping操作。
While such "Present" operations are almost invariably implemented by flip operations when the swap chain is a full-screen one, they are necessarily implemented by copy operations when the swap chain is windowed. Furthermore, a display adapter driver may use flipping to implement Present operations against full-screen swap chains based on the D3DSWAPEFFECT_DISCARD and D3DSWAPEFFECT_COPY.
还没人赞这篇日记