SDL3 入門(4):選擇圖形引擎

小时了了發表於2024-06-29

SDL2 建立渲染器時只能指定使用軟體渲染還是硬體加速,無法選擇使用哪種圖形引擎實現硬體加速。SDL3 對此做了最佳化,可以在建立渲染器時指定 rendering driver 也就是圖形引擎,比如在 Windows 平臺下可以指定使用 D3D11 也可以指定使用 OpenGL 或者 Vulkan。

指定圖形引擎

SDL_CreateRenderer 函式的第二個引數 name 表示指定使用的 rendering driver name,傳 NULL 表示使用第一個支援的 rendering driver,在 Windows 系統下通常是 D3D11。

SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window, const char *name)

SDL3 介面檔案中沒有預定義 rendering driver name,可以透過 SDL_GetNumRenderDriversSDL_GetRenderDriver 兩個函式列舉當前所支援的圖形引擎:

int count = SDL_GetNumRenderDrivers();
for (int i = 0; i < count; ++i) {
    const char* name = SDL_GetRenderDriver(i);
    SDL_Log("Render driver[%d]: %s", i, name);
}

在 Windows 系統下執行結果如下:

INFO: Render driver[0]: direct3d11
INFO: Render driver[1]: direct3d12
INFO: Render driver[2]: direct3d
INFO: Render driver[3]: opengl
INFO: Render driver[4]: opengles2
INFO: Render driver[5]: vulkan
INFO: Render driver[6]: software

其中 direct3d 指的是 D3D9,software 指軟體渲染,我們可以透過這些名字指定渲染器使用的渲染引擎。

渲染效能測試

實現一個簡單的類用來測試渲染幀率

// performance.h
...

class Performance final
{
public:
    Performance();
    ~Performance();

    void Reset();
    void IncreaseFrameCount();
    void PrintEverySecond();

private:
    using Clock = std::chrono::high_resolution_clock;
    using TimePoint = std::chrono::time_point<Clock>;

    TimePoint start_time_;
    uint64_t frame_count_ = 0;

    TimePoint last_print_time_;
    uint64_t last_frame_count_ = 0;
};
// performance.cpp
...

Performance::Performance()
{
    Reset();
}

Performance::~Performance() {}

void Performance::Reset()
{
    start_time_ = Clock::now();
    last_print_time_ = start_time_;
    frame_count_ = 0;
}

void Performance::IncreaseFrameCount()
{
    frame_count_++;
}

void Performance::PrintEverySecond()
{
    assert(start_time_.time_since_epoch().count() > 0);
    assert(last_print_time_ >= start_time_);
    auto now = Clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_print_time_);
    if (duration.count() >= 1000) {
        double elapsed_seconds =
            std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time_).count() /
            1000.0;
        double average_fps = frame_count_ / elapsed_seconds;
        double realtime_fps = (frame_count_ - last_frame_count_) / (duration.count() / 1000.0);
        last_print_time_ = now;
        last_frame_count_ = frame_count_;

        fprintf(stderr, "Performance: FPS(AVR|RT): %.2f|%.2f      \r", average_fps, realtime_fps);
    }
}

我們先測試 D3D11 的渲染幀率:

INFO: Created renderer: direct3d11
INFO: VSync: 0
Performance: FPS(AVR|RT): 32805.16|34470.00   

3 萬多幀,還不錯。這是全力渲染的結果,沒有開啟垂直同步,可以呼叫 SDL_SetRenderVSync 函式設定垂直同步:

int vsync = disable_vsync ? 0 : 1;
SDL_SetRenderVSync(renderer, vsync);
SDL_Log("VSync: %d", vsync);

再次測試渲染幀率,60fps,和螢幕重新整理率一致:

INFO: Created renderer: direct3d11
INFO: VSync: 1
Performance: FPS(AVR|RT): 59.95|60.04   

關閉垂直同步,對各渲染引擎分別進行幀率測試,結果如下:

direct3d11 direct3d12 direct3d opengl opengles2 vulkan software
33113.44 1155.43 1729.66 1673.66 1716.95 1565.44 1668.42

D3D11 一騎絕塵,看來最佳化的不錯。

注意這只是一個簡單的測試,效能瓶頸主要在從 CPU 提交渲染指令到 GPU 的過程,所以不代表 D3D11 的渲染效能和其他圖形引擎真的有這麼大的差距。實際上對於複雜的圖形渲染,除軟體渲染外所有基於 GPU 的渲染效能上不會有太大的差距。

相關文章