这里,我们真正的开始使用SDL的硬件渲染。首先,我们需要设置驱动的环境(以windows为例,我们设置为directx,Linux的设置请参考官方网站,我们这里预留为dga)。另外,如果要启动硬件加速,必须使用全屏模式(SDL_FULLSCREEN),所以,在前面的软件渲染中,我们也使用全屏以作对比。第三,硬件渲染需要打开双缓冲(SDL_DOUBLEBUF),至于为什么我们在最后讨论,我们还是先看看完整的代码。
2.2:硬件渲染演示程序完整的源代码。
#include < iostream >
#include " SDL/SDL.h "
SDL_Surface * pScreen = 0 ;
SDL_Surface * pBack = 0 ;
SDL_Surface * pFront = 0 ;
void pressESCtoQuitPlus();
void loopRender();
int main( int argc, char * argv[])
{
#ifdef __windows__
SDL_putenv( " SDL_VIDEODRIVER=directx " );
#endif
#ifdef __linux__
putenv( " SDL_VIDEODRIVER=dga " );
#endif
try {
if ( SDL_Init(SDL_INIT_VIDEO) != 0 )
throw SDL_GetError();
}
catch ( const char * s ) {
std::cerr << " SDL_Init() failed!\n " << s << std::endl;
return - 1 ;
}
const int SCREEN_WIDTH = 640 ;
const int SCREEN_HEIGHT = 480 ;
const int SCREEN_BPP = 32 ;
const Uint32 SCREEN_FLAGS = SDL_FULLSCREEN | SDL_DOUBLEBUF | SDL_HWSURFACE;
pScreen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SCREEN_FLAGS);
try {
if ( pScreen == 0 )
throw SDL_GetError();
}
catch ( const char * s ) {
std::cerr << " SDL_SetVideoMode() failed!\n " << s << std::endl;
SDL_Quit();
return - 1 ;
}
pBack = SDL_LoadBMP( " back.bmp " );
try {
if ( pBack == 0 )
throw SDL_GetError();
}
catch ( const char * s ) {
std::cerr << " SDL_LoadBMP() failed!\n " << s << std::endl;
SDL_Quit();
return - 1 ;
}
pFront = SDL_LoadBMP( " front.bmp " );
try {
if ( pFront == 0 )
throw SDL_GetError();
}
catch ( const char * s ) {
std::cerr << " SDL_LoadBMP() failed!\n " << s << std::endl;
SDL_Quit();
return - 1 ;
}
try {
pressESCtoQuitPlus();
}
catch ( const char * s ) {
std::cerr << " pressESCtoQuitPlus() failed!\n " << s << std::endl;
SDL_Quit();
return - 1 ;
}
SDL_Quit();
return 0 ;
}
void pressESCtoQuitPlus()
{
bool gameOver = false ;
while ( gameOver == false ){
SDL_Event gameEvent;
while ( SDL_PollEvent( & gameEvent) != 0 ){
if ( gameEvent.type == SDL_QUIT ){
gameOver = true ;
}
if ( gameEvent.type == SDL_KEYUP ){
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
gameOver = true ;
}
}
}
loopRender();
}
return ;
}
void loopRender()
{
SDL_Rect * pSrcRect = 0 ;
SDL_Rect * pDstRect = 0 ;
if ( SDL_BlitSurface(pBack, pSrcRect, pScreen, pDstRect) != 0 )
throw SDL_GetError();
if ( SDL_BlitSurface(pFront, pSrcRect, pScreen, pDstRect) != 0 )
throw SDL_GetError();
if ( SDL_Flip(pScreen) != 0 )
throw SDL_GetError();
return ;
}
2.3:问题。
你可能发现除了鼠标指针不显示之外,没有其它问题——这其实不是好现象,因为应该和可能出现的问题,都被我们事先避免了,但是这样让我们离事情的本质越来越远。你可以尝试着关掉SDL_DOUBLEBUF位标看看是什么效果;或者,在前面渲染单帧的程序中使用硬件渲染同时打开双缓冲看看出现什么问题——这些正是我们下一节将要讨论的。
如果你迫不及待的想知道原因,并且英语也过关的话,对于硬件渲染可能会引发的问题,我给你推荐一篇SDL官方也推荐的论文:
http://www.linuxdevcenter.com/pub/a/linux/2003/08/07/sdl_anim.html
但是很不幸的是,我在试验的过程中发现这篇文章有很多问题,当然,也许是我错了。因为我仅仅把SDL作为了一个黑盒子来研究,但是我得到的试验结果,却是不可能错的。
2.4:补充。
目前用Debian试验的时候,发现NVidia的显卡驱动屏蔽掉了dga的。也就是说实际上用不了,或者会设置起来很麻烦。实际上,SDL通过x11来实现图像,我目前的认识应该是这样的:SDL->x11->NV驱动->显卡。所以,实际上我们虽然没有通过SDL接触到显卡,但实际上还是通过种种渠道调用了显卡,我们应该充分相信NV的工程师比我们牛得多。NV官方解释如下:
http://us.download.nvidia.com/XFree86/Linux-x86/169.04/README/chapter-07.html#id2546686
Why do applications that use DGA graphics fail? | |
| The NVIDIA driver does not support the graphics component of the XFree86-DGA (Direct Graphics Access) extension. Applications can use the XDGASelectInput() function to acquire relative pointer motion, but graphics-related functions such as XDGASetMode() and XDGAOpenFramebuffer() will fail. The graphics component of XFree86-DGA is not supported because it requires a CPU mapping of framebuffer memory. As graphics cards ship with increasing quantities of video memory, the NVIDIA X driver has had to switch to a more dynamic memory mapping scheme that is incompatible with DGA. Furthermore, DGA does not cooperate with other graphics rendering libraries such as Xlib and OpenGL because it accesses GPU resources directly. NVIDIA recommends that applications use OpenGL or Xlib, rather than DGA, for graphics rendering. Using rendering libraries other than DGA will yield better performance and improve interoperability with other X applications. |