[圖形引擎Skia之三]子線程更新繪圖

前言

(*  ̄︿ ̄) 因為作者這段時間偷懶了一下,然后被某人乖巧催更,迫不得已,繼續(xù)更新吧

在上一篇文章中,我已經(jīng)介紹了Skia+SDL2的開發(fā)環(huán)境搭建,并且,放了一段程序的代碼,那么,你的程序是否跑起來了呢?
都跑起來之后,是不是感覺幾秒鐘就消失了有點不爽啊?沒關系,這次我們讓他一直跑,就像給他吃了 炫邁 一樣,你不叫停他是不會停的.

準備工作

還是老樣子吧,新建一個項目,這里我就不多說啦,不知道的小伙伴或者忘記了的小伙伴去翻翻我的上一篇文章吧

讓項目跑起來

首先呢,我們還是像之前一樣,先讓項目跑起來,然后呢,我們在對項目進行進一步修改,達到我們想要的效果

我就不用Ubuntu啦,在Windows上做吧 Σ( ° △ °|||)︴懶得開另一臺電腦啦

不墨跡了,我直接上代碼吧ヽ(??▽?)ノ

#include <SkBitmap.h>
#include <core/SkCanvas.h>
#include <core/SkTypeface.h>

#ifdef _WIN32

#include <SDL.h>

#else

#include <SDL2/SDL.h>

#endif

//創(chuàng)建RGBA結構體
struct RGBA {
    //設置Red
    Uint32 rmask = 0x00ff0000;
    //設置Green
    Uint32 gmask = 0x0000ff00;
    //設置Blue
    Uint32 bmask = 0x000000ff;
    //設置Alpha
    Uint32 amask = 0xff000000;
};

//創(chuàng)建SkBitmap對象并在Bitmap上繪制
SkBitmap draw(int w, int h) {
    //聲明
    SkBitmap bitmap;
    //設置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //轉換為像素填充
    bitmap.allocPixels();
    //創(chuàng)建畫布
    SkCanvas canvas(bitmap);
    //創(chuàng)建畫筆
    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創(chuàng)建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //創(chuàng)建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);
    //創(chuàng)建窗口
    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的像素數(shù)據(jù)創(chuàng)建表面
    surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), width, height, 32, width * 4, rgba.rmask, rgba.gmask,
        rgba.bmask, rgba.amask);
    //通過SDL_Surface創(chuàng)建矩形
    rect = create_rect(surface);
    //創(chuàng)建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //創(chuàng)建紋理
    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);
       //創(chuàng)建紋理
       surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), width, height, 32, width * 4, rgba.rmask, rgba.gmask,
           rgba.bmask, rgba.amask);
       //創(chuàng)建紋理
       texture = SDL_CreateTextureFromSurface(renderer, surface);
       //復制紋理
       SDL_RenderCopy(renderer, texture, NULL, &rect);
       //提交渲染
       SDL_RenderPresent(renderer);
       //休眠16.6毫秒
       SDL_Delay(16.6);
   }

這樣基本上就可以實現(xiàn)窗口一直存在并且一直在更新,但是呢,跑起來過后,你會發(fā)現(xiàn)這破玩意關不掉,那是因為一直在循環(huán),根本沒有機會處理其他的事情,而且是單線程,進入了死循環(huán)之后,后果大概就不用我說了吧

那么這種方法肯定就不能用啦,怎么解決呢?SDL這么強大一個媒體庫,不可能沒有辦法把?答案是肯定有辦法解決的,那么用什么辦法解決呢?當然是用線程解決啦

讓程序飛一會

SDL中有這么一個方法

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

這個方法用來干嘛的呢?當然是用來創(chuàng)建線程的啦 ╰(°▽°)╯ 簡單的介紹一下參數(shù),
第一個參數(shù) 表示 線程執(zhí)行時調用的方法名 ,
第二個參數(shù) 表示 線程的名稱 ,
第三個參數(shù) 表示 線程執(zhí)行需要的數(shù)據(jù)

那么知道了有這個方法,我們怎么去用呢?我們需要這樣修改程序

首先我們需要 把變量聲明搬到上邊去 ,然后創(chuàng)建一個 返回值為int類型且參數(shù)列表為 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);
        //創(chuàng)建紋理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, rgba.rmask, rgba.gmask,
            rgba.bmask, rgba.amask);
        //創(chuàng)建紋理
        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 <SkBitmap.h>
#include <core/SkCanvas.h>
#include <core/SkTypeface.h>

#ifdef _WIN32

#include <SDL.h>
#include <SDL_thread.h>

#else

#include <SDL2/SDL.h>

#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;

//創(chuàng)建RGBA結構體
struct RGBA {
    //設置Red
    Uint32 rmask = 0x00ff0000;
    //設置Green
    Uint32 gmask = 0x0000ff00;
    //設置Blue
    Uint32 bmask = 0x000000ff;
    //設置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//創(chuàng)建SkBitmap對象并在Bitmap上繪制
SkBitmap draw(int w, int h) {
    //聲明
    SkBitmap bitmap;
    //設置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //轉換為像素填充
    bitmap.allocPixels();
    //創(chuàng)建畫布
    SkCanvas canvas(bitmap);
    //創(chuàng)建畫筆
    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創(chuàng)建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //創(chuàng)建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);
        //創(chuàng)建紋理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //創(chuàng)建紋理
        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);
    //創(chuàng)建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //創(chuàng)建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //獲取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通過SDL_Surface創(chuàng)建矩形
    rect = create_rect(surface);
}

//程序的入口點
int main(int args, char *argv[]) {
    //初始化
    init();
    //創(chuàng)建并啟動線程
    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;
}

現(xiàn)在運行程序你會發(fā)現(xiàn)窗口一閃而過,為什么呢?因為我們把所有的操作都放到子線程中了,主線程沒有阻塞,所以主線程運行完了,整個程序就結束了,那么我們需要阻塞主線程,那就需要搞點事情,那搞點什么事情呢?想想我們還沒有做退出事件監(jiān)聽吧?那么我們就寫個事件阻塞

需要事件處理就需要在SDL初始化的時候加上事件系統(tǒng),大概是這樣子,需要修改一下代碼

SDL_Init(SDL_INIT_VIDEO);

修改為

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);

然后添加我們的事件處理循環(huán),添加一個全局變量 qiut ,之后吧我們的子線程中的while循環(huán)標記替換成 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;  
                }  
            }  

然后我們在釋放內(nèi)存的時候為了避免重復釋放,所以需要在釋放之前對數(shù)據(jù)進行判斷,之后整篇代碼大概是這樣子的

#include <SkBitmap.h>
#include <core/SkCanvas.h>
#include <core/SkTypeface.h>

#ifdef _WIN32

#include <SDL.h>
#include <SDL_thread.h>

#else

#include <SDL2/SDL.h>

#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;
//線程循環(huán)標記
bool quit = false;

//創(chuàng)建RGBA結構體
struct RGBA {
    //設置Red
    Uint32 rmask = 0x00ff0000;
    //設置Green
    Uint32 gmask = 0x0000ff00;
    //設置Blue
    Uint32 bmask = 0x000000ff;
    //設置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//創(chuàng)建SkBitmap對象并在Bitmap上繪制
SkBitmap draw(int w, int h) {
    //聲明
    SkBitmap bitmap;
    //設置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //轉換為像素填充
    bitmap.allocPixels();
    //創(chuàng)建畫布
    SkCanvas canvas(bitmap);
    //創(chuàng)建畫筆
    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創(chuàng)建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //創(chuàng)建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);
        //創(chuàng)建紋理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //創(chuàng)建紋理
        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);
    //創(chuàng)建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //創(chuàng)建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //獲取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通過SDL_Surface創(chuàng)建矩形
    rect = create_rect(surface);
}

//程序的入口點
int main(int args, char *argv[]) {
    //初始化
    init();
    //創(chuàng)建并啟動線程
    SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);
    //事件隊列
    SDL_Event e;
    //事件處理
    while (!quit) {
        //輪詢事件
        while (SDL_PollEvent(&e) != 0) {
            //用戶退出事件
            if (e.type == SDL_QUIT) {
                //設置循環(huán)標記
                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 <SkBitmap.h>
#include <core/SkCanvas.h>
#include <core/SkTypeface.h>
#include <string.h>

#ifdef _WIN32

#pragma warning(disable:4996)
#include <SDL.h>
#include <SDL_thread.h>

#else

#include <SDL2/SDL.h>

#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;
//線程循環(huán)標記
bool quit = false;
//幀數(shù)
int fps;
//待繪制的FPS數(shù)據(jù)
char chars[15];

//創(chuàng)建RGBA結構體
struct RGBA {
    //設置Red
    Uint32 rmask = 0x00ff0000;
    //設置Green
    Uint32 gmask = 0x0000ff00;
    //設置Blue
    Uint32 bmask = 0x000000ff;
    //設置Alpha
    Uint32 amask = 0xff000000;
}RGBA;


//創(chuàng)建SkBitmap對象并在Bitmap上繪制
SkBitmap draw(int w, int h) {
    //聲明
    SkBitmap bitmap;
    //設置Bitmap的配置信息
    bitmap.setInfo(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, kOpaque_SkAlphaType));
    //轉換為像素填充
    bitmap.allocPixels();
    //創(chuàng)建畫布
    SkCanvas canvas(bitmap);
    //創(chuàng)建畫筆
    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創(chuàng)建SDL_Rect
SDL_Rect create_rect(SDL_Surface *surface) {
    //創(chuàng)建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);
        //創(chuàng)建紋理
        surface = SDL_CreateRGBSurfaceFrom(bitmap.getPixels(), rect.w, rect.h, 32, rect.w * 4, RGBA.rmask, RGBA.gmask,
            RGBA.bmask, RGBA.amask);
        //創(chuàng)建紋理
        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);
    //創(chuàng)建窗口
    window = SDL_CreateWindow("Hello Skia", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
    //創(chuàng)建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    //清理渲染器
    SDL_RenderClear(renderer);
    //獲取窗口表面
    surface = SDL_GetWindowSurface(window);
    //通過SDL_Surface創(chuàng)建矩形
    rect = create_rect(surface);
}

//程序的入口點
int main(int args, char *argv[]) {
    //初始化
    init();
    //創(chuàng)建并啟動線程
    SDL_Thread *thread = SDL_CreateThread(update, "update", (void *)NULL);
    //創(chuàng)建并啟動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) {
                //設置循環(huán)標記
                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的硬件加速只需要在創(chuàng)建SDL的渲染器的時候傳入 SDL_RENDERER_ACCELERATED 字段

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

同理,換成軟件渲染只需要換成 SDL_RENDERER_SOFTWARE 即可

垂直同步

開啟垂直同步只需要在創(chuàng)建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下咋就不管用了呢? (# ̄~ ̄#)森氣~~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,987評論 0 3
  • 前言 首先呢,在搭建開發(fā)環(huán)境之前,請確保你已經(jīng)編譯出了對應平臺的library :Windows : skia.d...
    var_rain閱讀 21,746評論 5 14
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,983評論 25 709
  • 陰晦的早晨,我坐在床頭,隔著灰灰的窗戶遠眺著海際線,灰灰糊糊的,偶爾蹦出一個小黑點,那是漁船的滿載而歸。近處,...
    大地風神閱讀 229評論 1 3
  • 你我的故事被血液浸透 濃重的暈染看不清顏色 舍棄的情感埋葬幻想 未來的一切被迫隕落 死去的骸骨無法叫醒悲痛的瞽者 ...
    姜暄暄biubiubiu閱讀 167評論 1 0

友情鏈接更多精彩內(nèi)容