Direct3D 和 OpenGL真假全屏

480 篇文章 12 订阅
348 篇文章 14 订阅

全屏显示在Windows程序中,有不同的实现方法,有真全屏和假全屏之分,真全屏是将要显示的内容独占显示设备所有的全部资源,程序不加载窗外的框架。另一种是假全屏,实现的原理是调整要显示的内容的尺寸与位置,使之正好充满整个屏幕。
参见:http://hi.baidu.com/lionpark/blog/item/d8ddc9139118edd1f7039e17.html

游戏窗口模式分好几种,一般我们都直接分为全屏游戏和窗口游戏。其实还有一种中间状态,就是假全屏。

全屏模式就是我们一般所见的,例如CS,毁灭公爵,三角洲等,进入游戏以后,游戏控制整个屏幕(分辩率,刷新率,色深都改变成为游戏设定的模式)游戏独占资源,这样的好处是游戏运行速度会比窗口模式的快。不过这种方式很不方便,我想大家都有过正在打CS的时候突然QQ响了,不得不切出游戏的看看聊天的无奈吧。

窗口模式就是一般我们看到的这种windows窗口的,比如说泡泡龙一类的游戏。这种游戏的好处是玩家游戏的同时可以轻松切换到别的程序,比如聊QQ,看小说等等,这种模式一般适合占系统资源不高的小型游戏。

假全屏模式(伪全屏)其实是一种窗口模式,只不过是全屏化的窗口,它给人的感觉是全屏游戏,这样使玩家更容易投入到游戏当中。当然这个过程玩家切换到QQ界面也是不会影响到游戏的可玩性的。不过他的速度是没有和全屏游戏相比的(分辩率和刷新率,色彩都是和当前桌面同步的),聊QQ也不如窗口化的那么方便,中间产物往往都是继承了双方地优点的同时也继承了双方的缺点。

这三种方式各有利弊,你在写程序的时候更喜欢哪一种呢?
参见:http://www.dingge.com/forum/dispbbs.asp?boardID=46&ID=7391&page=1

对OpenGL不是很熟,不过迫切的想了解下面的几个关于OpenGL屏幕的问题,希望得到大家的帮助,谢谢!
OpenGL支持全屏幕“独占”模式吗?
还是仅仅只支持将窗口客户区调整得跟屏幕一样的尺寸,而不是真正的独享屏幕显示资源?
OpenGL全屏模式下的双缓冲或多缓冲机制支持像DirectX全屏模式那样的真正的Flip机制吗?
以上问题仅限于讨论OpenGL的Windows版本。

OpenGL本身不支持所谓的全屏模式。相对而言,DirectX 是真正支持独占显示模式的,并且能决定有与之联系紧密的一些绘图特性,如Flip机制就能在显卡级别交换硬件的显示缓冲的地址,而OpenGL不可能做到。
我的理解正确吗?
我的目的是想弄清楚OpenGL在利用硬件的能力上(OpenGL是支持硬件加速的吧)与Direct3D有哪些差别。

对于 Direct3D,按照你的说法,Direct3D也只是一个3D的API函数,它也没有界面和窗口,但是D3D有一个函数支持直接设置全屏独占模式: CreateDevice()参数中的pPresentationParameters->Windowed为FALSE的话,D3D就工作在全屏 独占模式,在这种模式下如果pPresentationParameters->SwapEffect为D3DSWAPEFFECT_FLIP的 话,在Present()的时候,就是交换硬件显示缓冲地址的。
对于OpenGL,也不尽然如你所说的,网上查到有个这样的函数:glutFullScreen()可以设置全屏方式,不过其具体的实现,仍然就是像你说的那样,是通过Windows里面的设置。最后,回到我的疑问上来,不论OpenGL本身支持不支持,到底有没有可能通过某种非D3D的手段(通过其它第三方库等等),使OpenGL工作在类似于D3D的真正全屏模式下,并且SwapBuffers()函数交换的是硬件的显示缓冲地址?
基于我的一个初步的研究结果,对于swapbuffer这样的操作,基于OpenGL的程序,即使是在全屏模式下,没有任何一例是“通过寄存器来切 换地址”的,统统都是copy的方式,例如CS之类的游戏。而基于D3D的全屏方式的游戏,大部分都是真正的“通过寄存器来切换地址”,我曾想办法在 D3D全屏方式下正常显示窗口,结果失败了,窗口都是闪烁的,由此可见的确是“通过寄存器来切换地址”。
这才引发了我对OpenGL的“全屏模式”是否能 “通过寄存器来切换地址”的疑问,因为若基于OpenGL的程序没有这个能力,我就可以确保正常显示出窗口而不用担心窗口会闪烁,然后我会集中精力想办法 去解决 D3D下如何不闪烁的问题。

讨论了半天,我还是没有得到一个确切的答案。
我再把问题有针对性地描述一下:OpenGL的swampbuffer在什么情况下是“通过寄存器来切换地址”的?如何能证明这一点?
本贴不是要讨论OGL和D3D孰优孰劣,仅仅只是希望能够确认一下我的研究结论而已。而且这个研究结论对于我手上的工作很重要。

我的研究结论是:
1)窗口模式下:
a. OpenGL的SwapBuffers()函数交换的是内部缓存的地址,前台缓存是copy到屏幕上的。
b. Direct3D的Present()函数也是交换的内部缓存的地址,前台缓存也是copy到屏幕上的。
结论:窗口模式下,因为需要与其它应用程序并存,所以不论是OpenGL还是D3D的底层实现都不允许硬件的显示缓存地址。
2)全屏模式下:
a. OpenGL的SwapBuffers()函数交换的仍然是内部缓存的地址,前台缓存仍然是copy到屏幕上的。工作方式与窗口方式无异,可以理解为假全屏,或者说OpenGL本身就无真全屏的概念。
b. Direct3D的Present()函数此时可能存在两种行为:一种仍然是交换内部缓存的地址,前台缓存仍然是copy到屏幕上的;另一种就是直接通知硬件交换显示缓存的地址。
结论:对于一个3D引擎来说,本来是不应该去牵扯窗口模式或全屏模式之类的问题,OpenGL可能就是这样想的,所以对于OpenGL来说,窗口和全屏没 有区别;但微软就不同,从DirectX诞生之日开始,对于窗口模式和全屏模式就有一定的区别对待,DirectX一直支持一种叫Flip的机制,在全屏 独占模式下就提供页翻转的能力(当然你也可以不用页翻转)页翻转会导致整个屏幕当前显示的内容所映射的显存物理地址会发生改变。对于现在的硬件性能来说, 的确也翻转也没有了太大的速度上的优势,copy已经足够快了,但是页翻转仍然是被DirectX所支持的。
最后,引用一段MSDN里的内容回应一下madmanahong(疯子阿虹)吧:
这是 D3DPRESENT_PARAMETERS 参数说明中的一小段文字:
SwapEffect - Member of the D3DSWAPEFFECT enumerated type. The run time will guarantee the implied semantics concerning buffer swap behavior. So if Windowed is TRUE and SwapEffect is set to D3DSWAPEFFECT_FLIP, then the run time will create one extra back buffer, and copy whichever becomes the front buffer at presentation time.
大意就是说,若Windowed为TRUE(也就是窗口模式下)同时SwapEffect指定为D3DSWAPEFFECT_FLIP,那么在运行时会自 动创建一个额外的后备缓冲(此时就至少会有2个后备缓冲了),每次Present的时候,就那个将要成为前台缓冲的内容copy到这个后台缓冲区中,然后 与下一个后备缓冲交换指针,从而完成假页翻转。
言外之意就是,若Windowed为FALSE(也就是全屏模式下)同时SwapEffect指定为D3DSWAPEFFECT_FLIP,就不会创建额外的后备缓冲,每次都会是真正的页翻转。
写过基于DirectDraw或Direct3D的中文网络游戏的人可能都遇到过这样的问题:
如果希望能在游戏中正常使用系统的各种输入法的话,那么在2D全屏游戏中不能用Flip()函数来交换前台和后备缓中,而只能用Blt()函数来copy它们;在3D全屏游戏中不能指定 D3DSWAPEFFECT_FLIP页翻转标志,而只能指定D3DSWAPEFFECT_COPY标志。否则输入法的窗口将会不断地闪烁,因为输入法的窗口并不能适应也翻转,它只能画在其中一页上。
对于OpenGL,似乎就没有以上这些设置,不过还好,它不会页翻转,所以窗口也不会闪烁。我所担心的就是,OpenGL会不会什么时候也开始页翻转了,窗口就会闪烁了?
--------------------------------------------------------------------------------
"Fulll-screen" isn't a mode, and there isn't an API to enter it -- full screen is just a consequence of other normal actions. What applications normally do is to create a WS_POPUP and WS_EX_TOPMOST window whose dimensions are GetSystemMetrics(SM_CXSCREEN), ...CYSCREEN. This obscures the rest of the screen and so looks full.
If an app has changed resolution first, using ChangeDisplaySettings(CDS_FULLSCREEN), then I don't know what GetSystemMetrics(...) returns. Note that, despite the name of this API call, I think it'd be wrong to call it a "mode". The function still allows other windows to be shown on the desktop normally, albeit at a different resolution. ChangeDisplaySettings is often used in OpenGL games.
Still, if you tried to grab exclusive mode for yourself and were denied, that'd be a good sign that someone else had it.
see also
Adding a Full Screen Feature to an MFC Application
http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B164162

全屏幕确实是windows系统的问题,没有真正的全屏幕和非全屏幕的区别的
根据显示卡的工作原理, 一个屏幕上的内容占据的显存空间只是显卡的一个部分
具体的是哪个部分,是由硬件的寄存器来控制的
所谓的swapbuffer这样的操作,也只是通过寄存器来切换地址而已
显卡本身根据寄存器上的地址,状态,以及端口信息来解释该地址下面的内容如何显示
也正是因为这样,这个操作的速度才非常的快,可以在显示卡显示原有内容的同时,你处理后台buffer的内容,完成后再swap他们
显卡工作原理本身,不分全屏不全屏的,在它的眼中永远是全屏的;
分的是文本方式还是图形方式;用的是显存还是内存还是agp内存
dx 早期是不支持windows模式下的flip的,只支持全屏幕独占方式下的flip
windows下的不支持flip的原因很简单,因为大家都共享这个桌面,不能简单的替换
swapeffect是dx9后的概念,它在windows下的flip允许也是特殊实现的
如同前面说的,flip实际上是发生在backbuffer和一个中间内部buffer,然后从中间的内部buffercopy到桌面区域,这个copy也是显卡内部数据的copy,速度也是很快的
从pc显示卡工作的原理上来说,opengl支持这个层面是没有问题,但是opengl是一个跨平台的系统; 而directx是必须依赖于windows平台的,在单一平台下,微软可以控制一切
这种显卡内存显示地址flip属性在其他的计算机系统和操作系统上能否支持,是个疑问;
如果opengl没有提供这样的功能,个人认为也是考虑跨平台跨系统兼容效果的原因
至于opengl是否会突然改变策略,这个不值得担心!
参见:http://blog.csdn.net/jiangsheng/archive/2006/05/15/740257.aspx

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值