You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 04:36:23