SDL2内存RGB图像显示速度过慢,寻求高效渲染优化方案
SDL2 内存RGB图像显示性能优化方案
问题说明
使用SDL2显示内存中的RGB值列表时,中等尺寸图像的屏幕更新耗时过长。测试代码中单帧更新耗时11.8毫秒,要实现60fps(每帧约16.7毫秒)的输出,留给其他任务的时间仅剩4.2毫秒,急需优化显示流程。
原测试代码
//gcc -Ofast -g "%f" `pkg-config --cflags --libs sdl2` -o SDL_test_3 #include <SDL2/SDL.h> #include <stdio.h> #include <time.h> //====---The_General_Use_Variables---==== unsigned char uc1; long l1; float f1; float f2; float f3; float t1; float t2; int main(){ int sx=1000; int sy=700; int did_work; //初始化SDL did_work=SDL_Init(SDL_INIT_VIDEO); if (did_work!=0){printf("Issue_in_SDL_Init\n");} //创建窗口 SDL_Window *window=NULL; window = SDL_CreateWindow( "win1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sx, sy, SDL_WINDOW_SHOWN ); SDL_Event windowEvent; if (!window){printf("SDL_CreateWindow_failed\n");} //获取窗口Surface SDL_Surface *screenSurface; screenSurface=SDL_GetWindowSurface(window); //创建图像缓冲区 unsigned char *im_buffer;im_buffer=malloc(sx*sy*3*sizeof(unsigned char)); for(l1=0;l1<sx*sy*3;l1++){im_buffer[l1]=0;} //创建基于缓冲区的Surface SDL_Surface *im_surface = SDL_CreateRGBSurfaceFrom((void*)im_buffer, sx, sy, 24, // bits per pixel = 24 sx*3, // pitch 0x0000FF, // red mask 0x00FF00, // green mask 0xFF0000, // blue mask 0); //初始绘制并更新窗口 SDL_BlitSurface(im_surface, NULL, screenSurface, NULL); SDL_UpdateWindowSurface(window); //循环设置 int seconds=5; t1=clock(); t1+=CLOCKS_PER_SEC*seconds; t2=clock(); long counter=0; uc1=0; while(t2<t1){ uc1++; counter++; SDL_PollEvent(&windowEvent); //更新红色通道 for(l1=0;l1<sx*sy*3;l1+=3){im_buffer[l1]=uc1;} //错误:每帧重新创建Surface im_surface=SDL_CreateRGBSurfaceFrom((void*)im_buffer, sx, sy, 24, // bits per pixel = 24 sx*3, // pitch 0x0000FF, // red mask 0x00FF00, // green mask 0xFF0000, // blue mask 0); SDL_BlitSurface(im_surface, NULL, screenSurface, NULL); SDL_UpdateWindowSurface(window); t2=clock(); } f1=counter; f2=seconds; printf("average_fps=%f \n",f1/f2); printf("frametime=%f \n",1000*f2/f1); }
核心优化点
1. 避免每帧重复创建SDL_Surface
SDL_CreateRGBSurfaceFrom是轻量包装内存的操作,但重复调用仍会产生不必要的资源分配/销毁开销。只需在初始化时创建一次,后续直接修改im_buffer即可,Surface会自动关联最新的缓冲区数据。
2. 切换到SDL_Renderer硬件加速(推荐)
SDL_Surface是软件渲染,依赖CPU计算;SDL_Renderer利用GPU硬件加速,能大幅提升渲染效率,尤其适合大尺寸图像。
3. 优化内存访问与更新区域
- 尽量保证内存访问连续,减少缓存 miss;
- 若仅更新部分区域,使用
SDL_UpdateWindowSurfaceRects替代SDL_UpdateWindowSurface,只传输变化区域的数据。
优化后的代码示例
方案一:Surface版本优化(最小改动)
//gcc -Ofast -g "%f" `pkg-config --cflags --libs sdl2` -o SDL_test_3_opt #include <SDL2/SDL.h> #include <stdio.h> #include <time.h> #include <string.h> unsigned char uc1; long l1; float f1, f2, t1, t2; int main(){ int sx=1000; int sy=700; int did_work; did_work=SDL_Init(SDL_INIT_VIDEO); if (did_work!=0){printf("Issue_in_SDL_Init\n");} SDL_Window *window=SDL_CreateWindow( "win1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sx, sy, SDL_WINDOW_SHOWN ); if (!window){printf("SDL_CreateWindow_failed\n");} SDL_Surface *screenSurface=SDL_GetWindowSurface(window); unsigned char *im_buffer=malloc(sx*sy*3*sizeof(unsigned char)); memset(im_buffer, 0, sx*sy*3); // 用memset替代循环初始化,更高效 // 仅创建一次Surface SDL_Surface *im_surface = SDL_CreateRGBSurfaceFrom((void*)im_buffer, sx, sy, 24, sx*3, 0x0000FF, 0x00FF00, 0xFF0000, 0); SDL_BlitSurface(im_surface, NULL, screenSurface, NULL); SDL_UpdateWindowSurface(window); int seconds=5; t1=clock() + CLOCKS_PER_SEC*seconds; long counter=0; uc1=0; SDL_Event windowEvent; while(clock() < t1){ uc1++; counter++; SDL_PollEvent(&windowEvent); // 直接修改缓冲区,无需重新创建Surface for(l1=0;l1<sx*sy*3;l1+=3){ im_buffer[l1] = uc1; } SDL_BlitSurface(im_surface, NULL, screenSurface, NULL); SDL_UpdateWindowSurface(window); } f1=counter; f2=seconds; printf("average_fps=%f \n",f1/f2); printf("frametime=%f \n",1000*f2/f1); // 释放资源 SDL_FreeSurface(im_surface); free(im_buffer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
方案二:Renderer硬件加速版本(性能最优)
//gcc -Ofast -g "%f" `pkg-config --cflags --libs sdl2` -o SDL_test_3_renderer #include <SDL2/SDL.h> #include <stdio.h> #include <time.h> #include <string.h> unsigned char uc1; long l1; float f1, f2, t1, t2; int main(){ int sx=1000; int sy=700; int did_work; did_work=SDL_Init(SDL_INIT_VIDEO); if (did_work!=0){printf("Issue_in_SDL_Init\n");} // 创建窗口和硬件加速Renderer,开启VSYNC避免画面撕裂 SDL_Window *window=SDL_CreateWindow( "win1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sx, sy, SDL_WINDOW_SHOWN ); SDL_Renderer *renderer=SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (!window || !renderer){printf("Create window/renderer failed\n");} unsigned char *im_buffer=malloc(sx*sy*3*sizeof(unsigned char)); memset(im_buffer, 0, sx*sy*3); // 创建可流式更新的Texture SDL_Texture *texture=SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, sx, sy); int seconds=5; t1=clock() + CLOCKS_PER_SEC*seconds; long counter=0; uc1=0; SDL_Event windowEvent; while(clock() < t1){ uc1++; counter++; SDL_PollEvent(&windowEvent); // 更新缓冲区数据 for(l1=0;l1<sx*sy*3;l1+=3){ im_buffer[l1] = uc1; } // 将缓冲区数据更新到Texture SDL_UpdateTexture(texture, NULL, im_buffer, sx*3); // 清空渲染目标并绘制Texture SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); // 提交渲染结果到屏幕 SDL_RenderPresent(renderer); } f1=counter; f2=seconds; printf("average_fps=%f \n",f1/f2); printf("frametime=%f \n",1000*f2/f1); // 释放资源 SDL_DestroyTexture(texture); free(im_buffer); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

