[图形引擎Skia之三]子线程更新绘图

前言

(*  ̄︿ ̄) 因为作者这段时间偷懒了一下,然后被某人乖巧催更,迫不得已,继续更新吧

在上一篇文章中,我已经介绍了Skia+SDL2的开发环境搭建,并且,放了一段程序的代码,那么,你的程序是否跑起来了呢?
都跑起来之后,是不是感觉几秒钟就消失了有点不爽啊?没关系,这次我们让他一直跑,就像给他吃了 炫迈 一样,你不叫停他是不会停的.

准备工作

还是老样子吧,新建一个项目,这里我就不多说啦,不知道的小伙伴或者忘记了的小伙伴去翻翻我的上一篇文章吧

让项目跑起来

首先呢,我们还是像之前一样,先让项目跑起来,然后呢,我们在对项目进行进一步修改,达到我们想要的效果

我就不用Ubuntu啦,在Windows上做吧 Σ( ° △ °|||)︴懒得开另一台电脑啦

不墨迹了,我直接上代码吧ヽ(✿゚▽゚)ノ

#include 
#include 
#include 

#ifdef _WIN32

#include 

#else

#include 

#endif

//创建RGBA结构体
struct RGBA {
    //设置Red
    Uint32 rmask = 0x00ff0000;
    //设置Green
    Uint32 gmask = 0x0000ff00;
    //设置Blue
    Uint32 bmask = 0x000000ff;
    //设置Alpha
    Uint32 amask = 0xff000000;
};

//创建SkBitmap对象并在Bitmap上绘制
SkBitmap draw(int w, int h) {
    //声明
    SkBitmap bitmap;
    //设置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //转换为像素填充
    bitmap.allocPixels();
    //创建画布
    SkCanvas canvas(bitmap);
    //创建画笔
    SkPaint paint;
    //设置画布颜色
    canvas.clear(SK_ColorWHITE);
    //设置画笔抗锯齿
    paint.setAntiAlias(true);
    //设置画笔颜色(此处为红色)
    paint.setARGB(255, 255, 0, 0);
    //绘制圆形
    canvas.drawCircle(80, 80, 40, paint);
    //绘制线段
    canvas.drawLine(0, 280, w, 280, paint);
    //设置字体大小
    paint.setTextSize(60);
    //绘制字体
    canvas.drawString("Hello Skia", 300, 150, paint);
    //返回SkBitmap对象
    return bitmap;
}

//通过SDL_Surface创建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //创建SDL_Rect对象
    SDL_Rect src = { 0, 0, surface->w, surface->h };
    //返回SDL_Rect对象
    return src;
}

//程序的入口点
int main(int args, char *argv[]) {
    //声明窗口
    SDL_Window *window;
    //声明绘图表面
    SDL_Surface *surface;
    //声明渲染器
    SDL_Renderer *renderer;
    //声明纹理
    SDL_Texture *texture;
    //声明Bitmap
    SkBitmap bitmap;
    //声明RGBA结构体
    RGBA rgba;
    //声明矩形
    SDL_Rect rect;
    //声明窗口的宽高
    int width = 800;
    int height = 480;
    //初始化SDL为视频显示
    SDL_Init(SDL_INIT_VIDEO);
    //创建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    if (window == NULL) {
        return -1;
    }
    //获取绘制后的Bitmap
    bitmap = draw(width, height);
    //通过Bitmap的像素数据创建表面
    surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), width, height, 32, width * 4, rgba.rmask, rgba.gmask,
        rgba.bmask, rgba.amask);
    //通过SDL_Surface创建矩形
    rect = create_rect(surface);
    //创建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //创建纹理
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    //辅助纹理到渲染器
    SDL_RenderCopy(renderer, texture, NULL, &rect);
    //显示到窗口
    SDL_RenderPresent(renderer);
    //延时5秒钟
    SDL_Delay(5000);
    //释放表面
    SDL_FreeSurface(surface);
    //释放纹理
    SDL_DestroyTexture(texture);
    //释放渲染器
    SDL_DestroyRenderer(renderer);
    //释放窗口
    SDL_DestroyWindow(window);
    //结束SDL
    SDL_Quit();
    //程序退出
    return 0;
}

其实呢,还是和上次一样的,因为我懒 ︿( ̄︶ ̄)︿ 复制粘贴多快呀

还是跑一下吧,给你们解解馋


skia_run_with_windows.png

为了让程序一直更新,并且受我们自己控制,就需要对代码进行修改
那么,怎么样才能让程序一直刷新不断的重绘呢?

最简单的办法

一直调用while,我们只需要把

 SDL_Delay(5000);

换成

while (true) {
       //判断表面是否为空
       if (surface != NULL){
           //释放表面
           SDL_FreeSurface(surface);
       }
       //判断纹理是否为空
       if (texture != NULL) {
           //释放纹理
           SDL_DestroyTexture(texture);
       }
       //绘制位图
       bitmap = draw(width, height);
       //创建纹理
       surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), width, height, 32, width * 4, rgba.rmask, rgba.gmask,
           rgba.bmask, rgba.amask);
       //创建纹理
       texture = SDL_CreateTextureFromSurface(renderer, surface);
       //复制纹理
       SDL_RenderCopy(renderer, texture, NULL, &rect);
       //提交渲染
       SDL_RenderPresent(renderer);
       //休眠16.6毫秒
       SDL_Delay(16.6);
   }

这样基本上就可以实现窗口一直存在并且一直在更新,但是呢,跑起来过后,你会发现这破玩意关不掉,那是因为一直在循环,根本没有机会处理其他的事情,而且是单线程,进入了死循环之后,后果大概就不用我说了吧

那么这种方法肯定就不能用啦,怎么解决呢?SDL这么强大一个媒体库,不可能没有办法把?答案是肯定有办法解决的,那么用什么办法解决呢?当然是用线程解决啦

让程序飞一会

SDL中有这么一个方法

SDL_Thread* SDL_CreateThread(SDL_ThreadFunction fn,
                             const char*        name,
                             void*              data)

这个方法用来干嘛的呢?当然是用来创建线程的啦 ╰(°▽°)╯ 简单的介绍一下参数,
第一个参数 表示 线程执行时调用的方法名 ,
第二个参数 表示 线程的名称 ,
第三个参数 表示 线程执行需要的数据

那么知道了有这个方法,我们怎么去用呢?我们需要这样修改程序

首先我们需要 把变量声明搬到上边去 ,然后创建一个 返回值为int类型且参数列表为 void* 的方法

//声明窗口
SDL_Window *window;
//声明绘图表面
SDL_Surface *surface;
//声明渲染器
SDL_Renderer *renderer;
//声明纹理
SDL_Texture *texture;
//声明Bitmap
SkBitmap bitmap;
//声明RGBA结构体
RGBA rgba;
//声明矩形
SDL_Rect rect;

int update(void *data) {
    while (true) {
        //判断表面是否为空
        if (surface != NULL) {
            //释放表面
            SDL_FreeSurface(surface);
        }
        //判断纹理是否为空
        if (texture != NULL) {
            //释放纹理
            SDL_DestroyTexture(texture);
        }
        //绘制位图
        bitmap = draw(rect.w, rect.h);
        //创建纹理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, rgba.rmask, rgba.gmask,
            rgba.bmask, rgba.amask);
        //创建纹理
        texture = SDL_CreateTextureFromSurface(renderer, surface);
        //复制纹理
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        //提交渲染
        SDL_RenderPresent(renderer);
        //休眠16.6毫秒
        SDL_Delay(16.6);
    }
  return 0;
}

然后在main方法中替换

SDL_Delay(5000);

SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);

为了方便查看代码,我将代码结构稍微调整了一下,之后整篇代码大概是这样子的

#include 
#include 
#include 

#ifdef _WIN32

#include 
#include 

#else

#include 

#endif

//声明窗口
SDL_Window *window;
//声明绘图表面
SDL_Surface *surface;
//声明渲染器
SDL_Renderer *renderer;
//声明纹理
SDL_Texture *texture;
//声明Bitmap
SkBitmap bitmap;
//声明矩形
SDL_Rect rect;
//声明窗口的宽高
int width = 800;
int height = 480;

//创建RGBA结构体
struct RGBA {
    //设置Red
    Uint32 rmask = 0x00ff0000;
    //设置Green
    Uint32 gmask = 0x0000ff00;
    //设置Blue
    Uint32 bmask = 0x000000ff;
    //设置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//创建SkBitmap对象并在Bitmap上绘制
SkBitmap draw(int w, int h) {
    //声明
    SkBitmap bitmap;
    //设置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //转换为像素填充
    bitmap.allocPixels();
    //创建画布
    SkCanvas canvas(bitmap);
    //创建画笔
    SkPaint paint;
    //设置画布颜色
    canvas.clear(SK_ColorWHITE);
    //设置画笔抗锯齿
    paint.setAntiAlias(true);
    //设置画笔颜色(此处为红色)
    paint.setARGB(255, 255, 0, 0);
    //绘制圆形
    canvas.drawCircle(80, 80, 40, paint);
    //绘制线段
    canvas.drawLine(0, 280, w, 280, paint);
    //设置字体大小
    paint.setTextSize(60);
    //绘制字体
    canvas.drawString("Hello Skia", 300, 150, paint);
    //返回SkBitmap对象
    return bitmap;
}

//通过SDL_Surface创建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //创建SDL_Rect对象
    SDL_Rect src = { 0, 0, surface->w, surface->h };
    //返回SDL_Rect对象
    return src;
}

//SDL线程调用的方法
int update(void *data) {
    while (true) {
        //判断表面是否为空
        if (surface != NULL) {
            //释放表面
            SDL_FreeSurface(surface);
        }
        //判断纹理是否为空
        if (texture != NULL) {
            //释放纹理
            SDL_DestroyTexture(texture);
        }
        //绘制位图
        bitmap = draw(rect.w, rect.h);
        //创建纹理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //创建纹理
        texture = SDL_CreateTextureFromSurface(renderer, surface);
        //复制纹理
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        //提交渲染
        SDL_RenderPresent(renderer);
        //休眠16.6毫秒
        SDL_Delay(16.6);
    }
    return 0;
}

//初始化
void init() {
    //初始化SDL为视频显示
    SDL_Init(SDL_INIT_VIDEO);
    //创建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //创建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //获取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通过SDL_Surface创建矩形
    rect = create_rect(surface);
}

//程序的入口点
int main(int args, char *argv[]) {
    //初始化
    init();
    //创建并启动线程
    SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);
    //释放表面
    SDL_FreeSurface(surface);
    //释放纹理
    SDL_DestroyTexture(texture);
    //释放渲染器
    SDL_DestroyRenderer(renderer);
    //释放窗口
    SDL_DestroyWindow(window);
    //结束SDL
    SDL_Quit();
    //程序退出
    return 0;
}

现在运行程序你会发现窗口一闪而过,为什么呢?因为我们把所有的操作都放到子线程中了,主线程没有阻塞,所以主线程运行完了,整个程序就结束了,那么我们需要阻塞主线程,那就需要搞点事情,那搞点什么事情呢?想想我们还没有做退出事件监听吧?那么我们就写个事件阻塞

需要事件处理就需要在SDL初始化的时候加上事件系统,大概是这样子,需要修改一下代码

SDL_Init(SDL_INIT_VIDEO);

修改为

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);

然后添加我们的事件处理循环,添加一个全局变量 qiut ,之后吧我们的子线程中的while循环标记替换成 quit

while (!quit) {  
            //Handle events on queue  
            while (SDL_PollEvent(&e) != 0) {  
                //User requests quit  
                if (e.type == SDL_QUIT) {  
                    quit = true;  
                }  
                if (e.type == SDL_FINGERUP) {  
                    quit = true;  
                }  
            }  

然后我们在释放内存的时候为了避免重复释放,所以需要在释放之前对数据进行判断,之后整篇代码大概是这样子的

#include 
#include 
#include 

#ifdef _WIN32

#include 
#include 

#else

#include 

#endif

//声明窗口
SDL_Window *window;
//声明绘图表面
SDL_Surface *surface;
//声明渲染器
SDL_Renderer *renderer;
//声明纹理
SDL_Texture *texture;
//声明Bitmap
SkBitmap bitmap;
//声明矩形
SDL_Rect rect;
//声明窗口的宽高
int width = 800;
int height = 480;
//线程循环标记
bool quit = false;

//创建RGBA结构体
struct RGBA {
    //设置Red
    Uint32 rmask = 0x00ff0000;
    //设置Green
    Uint32 gmask = 0x0000ff00;
    //设置Blue
    Uint32 bmask = 0x000000ff;
    //设置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//创建SkBitmap对象并在Bitmap上绘制
SkBitmap draw(int w, int h) {
    //声明
    SkBitmap bitmap;
    //设置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //转换为像素填充
    bitmap.allocPixels();
    //创建画布
    SkCanvas canvas(bitmap);
    //创建画笔
    SkPaint paint;
    //设置画布颜色
    canvas.clear(SK_ColorWHITE);
    //设置画笔抗锯齿
    paint.setAntiAlias(true);
    //设置画笔颜色(此处为红色)
    paint.setARGB(255, 255, 0, 0);
    //绘制圆形
    canvas.drawCircle(80, 80, 40, paint);
    //绘制线段
    canvas.drawLine(0, 280, w, 280, paint);
    //设置字体大小
    paint.setTextSize(60);
    //绘制字体
    canvas.drawString("Hello Skia", 300, 150, paint);
    //返回SkBitmap对象
    return bitmap;
}

//通过SDL_Surface创建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //创建SDL_Rect对象
    SDL_Rect src = { 0, 0, surface->w, surface->h };
    //返回SDL_Rect对象
    return src;
}

//SDL线程调用的方法
int update(void *data) {
    while (!quit) {
        //判断表面是否为空
        if (surface != NULL) {
            //释放表面
            SDL_FreeSurface(surface);
        }
        //判断纹理是否为空
        if (texture != NULL) {
            //释放纹理
            SDL_DestroyTexture(texture);
        }
        //绘制位图
        bitmap = draw(rect.w, rect.h);
        //创建纹理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //创建纹理
        texture = SDL_CreateTextureFromSurface(renderer, surface);
        //复制纹理
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        //提交渲染
        SDL_RenderPresent(renderer);
        //休眠16.6毫秒
        SDL_Delay(16.6);
    }
    return 0;
}

//初始化
void init() {
    //初始化SDL为视频显示
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
    //创建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //创建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //获取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通过SDL_Surface创建矩形
    rect = create_rect(surface);
}

//程序的入口点
int main(int args, char *argv[]) {
    //初始化
    init();
    //创建并启动线程
    SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);
    //事件队列
    SDL_Event e;
    //事件处理
    while (!quit) {
        //轮询事件
        while (SDL_PollEvent(&e) != 0) {
            //用户退出事件
            if (e.type == SDL_QUIT) {
                //设置循环标记
                quit = true;
            }
        }
    }
    //判断表面是否为空
    if (surface != NULL) {
        //释放表面
        SDL_FreeSurface(surface);
    }
    //判断纹理是否为空
    if (texture != NULL) {
        //释放纹理
        SDL_DestroyTexture(texture);
    }
    //判断渲染器是否为空
    if (renderer != NULL) {
        //释放渲染器
        SDL_DestroyRenderer(renderer);
    }
    //释放窗口
    SDL_DestroyWindow(window);
    //结束SDL
    SDL_Quit();
    //程序退出
    return 0;
}

然后运行程序试试?是不是想怎么玩就怎么玩啦?没错,就是这样,为了更直观的查看FPS,我们需要增加一点代码,这里我就不详细介绍啦,直接贴代码吧,反正你们也不会仔细的看我的文章 (*  ̄︿ ̄)

之后,贴出增加FPS显示后的代码

#include 
#include 
#include 
#include 

#ifdef _WIN32

#pragma warning(disable:4996)
#include 
#include 

#else

#include 

#endif

//声明窗口
SDL_Window *window;
//声明绘图表面
SDL_Surface *surface;
//声明渲染器
SDL_Renderer *renderer;
//声明纹理
SDL_Texture *texture;
//声明Bitmap
SkBitmap bitmap;
//声明矩形
SDL_Rect rect;
//声明窗口的宽高
int width = 800;
int height = 480;
//线程循环标记
bool quit = false;
//帧数
int fps;
//待绘制的FPS数据
char chars[15];

//创建RGBA结构体
struct RGBA {
    //设置Red
    Uint32 rmask = 0x00ff0000;
    //设置Green
    Uint32 gmask = 0x0000ff00;
    //设置Blue
    Uint32 bmask = 0x000000ff;
    //设置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//创建SkBitmap对象并在Bitmap上绘制
SkBitmap draw(int w, int h) {
    //声明
    SkBitmap bitmap;
    //设置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //转换为像素填充
    bitmap.allocPixels();
    //创建画布
    SkCanvas canvas(bitmap);
    //创建画笔
    SkPaint paint;
    //设置画布颜色
    canvas.clear(SK_ColorWHITE);
    //设置画笔抗锯齿
    paint.setAntiAlias(true);
    //设置画笔颜色(此处为红色)
    paint.setARGB(255, 255, 0, 0);
    //绘制圆形
    canvas.drawCircle(80, 80, 40, paint);
    //绘制线段
    canvas.drawLine(0, 280, w, 280, paint);
    //设置字体大小
    paint.setTextSize(60);
    //绘制字体
    canvas.drawString("Hello Skia", 300, 150, paint);
    //设置字体大小
    paint.setTextSize(20);
    //绘制FPS
    canvas.drawText(chars, sizeof((char*)chars) - 1, 10, 20, paint);
    //返回SkBitmap对象
    return bitmap;
}

//通过SDL_Surface创建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //创建SDL_Rect对象
    SDL_Rect src = { 0, 0, surface->w, surface->h };
    //返回SDL_Rect对象
    return src;
}

//SDL线程调用的方法
int update(void *data) {
    while (!quit) {
        //判断表面是否为空
        if (surface != NULL) {
            //释放表面
            SDL_FreeSurface(surface);
        }
        //判断纹理是否为空
        if (texture != NULL) {
            //释放纹理
            SDL_DestroyTexture(texture);
        }
        //绘制位图
        bitmap = draw(rect.w, rect.h);
        //创建纹理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //创建纹理
        texture = SDL_CreateTextureFromSurface(renderer, surface);
        //复制纹理
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        //提交渲染
        SDL_RenderPresent(renderer);
        //休眠16.6毫秒
        SDL_Delay(16.6);
        //FPS自增长
        fps++;
    }
    return 0;
}

//FPS更新线程方法
int updateFPS(void *data) {
    while (!quit){
        //拼接字符串
        sprintf(chars, "FPS: %d", fps);
        //重置FPS
        fps = 0;
        //每秒获取一次刷新速率
        SDL_Delay(1000);
    }
    return 0;
}

//初始化
void init() {
    //初始化SDL为视频显示
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
    //创建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //创建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //获取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通过SDL_Surface创建矩形
    rect = create_rect(surface);
}

//程序的入口点
int main(int args, char *argv[]) {
    //初始化
    init();
    //创建并启动线程
    SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);
    //创建并启动FPS记录线程
    SDL_Thread *fpsThread = SDL_CreateThread(updateFPS, "fps", (void *)NULL);
    //事件队列
    SDL_Event e;
    //事件处理
    while (!quit) {
        //轮询事件
        while (SDL_PollEvent(&e) != 0) {
            //用户退出事件
            if (e.type == SDL_QUIT) {
                //设置循环标记
                quit = true;
            }
        }
    }
    //判断表面是否为空
    if (surface != NULL) {
        //释放表面
        SDL_FreeSurface(surface);
    }
    //判断纹理是否为空
    if (texture != NULL) {
        //释放纹理
        SDL_DestroyTexture(texture);
    }
    //判断渲染器是否为空
    if (renderer != NULL) {
        //释放渲染器
        SDL_DestroyRenderer(renderer);
    }
    //释放窗口
    SDL_DestroyWindow(window);
    //结束SDL
    SDL_Quit();
    //程序退出
    return 0;
}

然后嘛,附上一张图吧


skia_run_on_windows_with_fps.png

扩展知识

关于SDL的 垂直同步硬件加速

硬件加速

开启SDL的硬件加速只需要在创建SDL的渲染器的时候传入 SDL_RENDERER_ACCELERATED 字段

SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

同理,换成软件渲染只需要换成 SDL_RENDERER_SOFTWARE 即可

垂直同步

开启垂直同步只需要在创建SDL的渲染器的时候传入 SDL_RENDERER_PRESENTVSYNC 字段即可,这样程序在运行的时候会以最大限度保持在每秒60次的重绘速度

SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);

当然,通常我们会把硬件加速和垂直同步一起使用,所以我们通常会这么写

SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

好啦,小伙伴们可以随便玩啦,可以试着测试一下最大的FPS哦~~ 只需要把 SDL_Delay(16.6); 这句注释掉就可以啦~~

最后放几张图吧,我这老爷车跑Visual Studio 2017都吃力
FPS就凑合着看吧(# ̄~ ̄#)

使用软件加速的最大FPS
sdl_sofware_render_fps.png
使用硬件加速的最大FPS
sdl_hardware_render_fps.png
开启垂直同步的FPS
sdl_sync_render_fps.png

不知道为什么,在Ubuntu上跑软加速都能上 800FPS ,硬加速能上 1400FPS
在Windows下咋就不管用了呢? (# ̄~ ̄#)森气~~

你可能感兴趣的:([图形引擎Skia之三]子线程更新绘图)