我正在使用 SDL 2.0.4 和 GLEW 1.13.0,似乎 SDL2 中存在某种 fps 限制。我知道这一点,因为我做了一些时间测量。
更具体地说,我什么都不画,但如果我在主循环中调用 SDL_GL_SwapWindow(),每个循环大约需要 16 毫秒。如果没有这个电话,几乎不需要任何时间。当 SDL_GL_SwapWindow 是主循环中唯一的函数调用时,它甚至需要 16 毫秒。这意味着,必须在 SDL2 中启用某种 fps 限制或垂直同步。所以我的问题是:如何禁用上述限制?
我发现的唯一一个与我的问题有点相似的线程如下:SDL_GL_SwapWindow bad performance。但是这个线程中的答案对我并没有真正的帮助。此外,这似乎不是由我的计算机引起的,因为使用 FreeGLUT 完成的类似代码不会出现此问题。
所有文件的简要概述:
jtime.h: For time measurement
color.h: For colored console output (easier to make out errors)
display.h: Declaration of class Display
display.cpp: Implementation of class Display
main.cpp: Main function and HandleEvents()
我的代码:
主文件
#include <iostream>
#include <conio.h>
#include <display.h>
#include <glew.h>
#include <jtime.h>
void HandleEvents(SDL_Event&& e, jpk::Display& d)
{
if(e.type == SDL_QUIT)
d.GetWindowState() = jpk::Display::WindowState::EXIT;
}
int main(int argc, char* argv[])
{
jpk::Display display("Test", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 400, 400);
if(display.GetWindowState() == jpk::Display::WindowState::EXIT)
return 1;
else
{
jpk::measure<> ms;
while(display.GetWindowState() != jpk::Display::WindowState::EXIT)
{
ms.start();
display.Update(50, HandleEvents);
std::cout << "Time taken: " << ms.stop() << "ms" << std::endl;
}
return 0;
}
}
显示.cpp
#include <display.h>
#include <color.h>
#include <jtime.h>
#include <glew.h>
#include <wglew.h>
#include <iostream>
#include <vector>
#include <list>
jpk::Display::SDL2Helper jpk::Display::helper(SDL_INIT_MODULES, SDL_OUTPUT_MSG);
jpk::Display::SDL2Helper::SDL2Helper(const uint32_t& f, const bool& o) :
init(true)
{
jpk::measure<> ms;
if(SDL_Init(f))
{
std::cerr << jpk::color::light_red_f << "[Error] SDL2 could not be "
"initialized.\nDetails according to SDL2: " << SDL_GetError() <<
jpk::color::reset << std::endl;
init = false;
}
else if(o)
std::cout << jpk::color::light_green_f << "[Info] SDL2 has been " <<
"initialized successfully. Time: " << ms.stop() << "ms." <<
jpk::color::reset << std::endl;
}
jpk::Display::SDL2Helper::~SDL2Helper(void)
{
if(init)
SDL_Quit();
}
jpk::Display::Display(const std::string& t, const unsigned int& x,
const unsigned int& y, const unsigned int& w,
const unsigned int& h, const uint32_t& f, std::string s) :
window(nullptr),
glContext(nullptr),
state(WindowState::READY)
{
jpk::measure<> ms;
window = SDL_CreateWindow(t.c_str(), x, y, w, h, f | SDL_WINDOW_OPENGL |
SDL_WINDOW_HIDDEN);
if(window == nullptr)
{
std::cerr << jpk::color::light_red_f << "[Error] The instance of " <<
"class 'Display' couldn't be created.\nDetails according to " <<
"SDL2: " << SDL_GetError() << jpk::color::reset <<
std::endl;
state = WindowState::EXIT;
}
else
{
glContext = SDL_GL_CreateContext(window);
if(glContext == nullptr)
{
std::cerr << jpk::color::light_red_f << "[Error] The GL Context " <<
"of the instance of class 'Display' couldn't be " <<
"initialized.\nDetails according to SDL2: " <<
SDL_GetError() << jpk::color::reset << std::endl;
state = WindowState::EXIT;
}
else
{
GLenum error(glewInit());
if(error != GLEW_OK)
{
std::cerr << jpk::color::light_red_f << "[Error] GLEW " <<
"failed to initialize.\nDetails according to GLEW: " <<
glewGetErrorString(error) << jpk::color::reset <<
std::endl;
state = WindowState::EXIT;
}
else
{
bool noSupport(false);
if(s.length() > 0)
{
s += " ";
size_t found(s.find(" "));
while(found != std::string::npos)
{
std::string ext(s);
ext.erase(found);
s.erase(0, found+1);
if(!glewIsSupported(ext.c_str()) &&
!wglewIsSupported(ext.c_str()))
{
std::cout << jpk::color::light_red_f << "[Error] " <<
"The following GLEW extension is not " <<
"supported: " << ext << "." <<
jpk::color::reset << std::endl;
noSupport = true;
}
found = s.find(" ");
}
}
if(!noSupport)
{
std::cout << jpk::color::light_green_f << "[Info] The " <<
"instance of class 'Display' has successfully " <<
"been created! Time: " << ms.stop() << "ms." <<
jpk::color::reset << std::endl;
if(!(f & SDL_WINDOW_HIDDEN))
SDL_ShowWindow(window);
}
else
state = WindowState::EXIT;
}
}
}
}
jpk::Display::~Display(void)
{
if(glContext != nullptr)
SDL_GL_DeleteContext(glContext);
if(window != nullptr)
SDL_DestroyWindow(window);
}
bool jpk::Display::SDL_InitStatus(void)
{
return helper.init;
}
void jpk::Display::Update(const unsigned int& n, void (*f)(SDL_Event&&, jpk::Display&))
{
SDL_GL_SwapWindow(window);
static std::list<SDL_Event> events;
SDL_Event e;
while(SDL_PollEvent(&e))
events.push_back(e);
if(n != 0)
for(unsigned int i(0); i < n ;i++)
{
f(std::move(events.front()), *this);
events.pop_front();
}
else
{
const unsigned int numEvents(events.size());
for(unsigned int i(0); i < numEvents ;i++)
{
f(std::move(events.front()), *this);
events.pop_front();
}
}
}
void jpk::Display::Show(void)
{
if(window != nullptr)
SDL_ShowWindow(window);
}
void jpk::Display::Hide(void)
{
if(window != nullptr)
SDL_HideWindow(window);
}
jpk::Display::WindowState& jpk::Display::GetWindowState(void)
{
return state;
}
显示.h
#ifndef DISPLAY_H
#define DISPLAY_H
#define SDL_MAIN_HANDLED
#define SDL_INIT_MODULES SDL_INIT_EVERYTHING
#define SDL_OUTPUT_MSG false
#include <string>
#include <iostream>
#include <SDL.h>
namespace jpk
{
class Display
{
public:
enum class WindowState
{
READY,
EXIT
};
Display(const std::string& title, const unsigned int& pos_x,
const unsigned int& pos_y, const unsigned int& width,
const unsigned int& height, const uint32_t& flags = 0,
std::string support = "");
~Display(void);
Display(const Display&) = delete;
Display& operator=(const Display&) = delete;
static bool SDL_InitStatus(void);
WindowState& GetWindowState(void);
void Update(const unsigned int& numEvents,
void (*eventFunc)(SDL_Event&&, jpk::Display&));
void Show(void);
void Hide(void);
private:
struct SDL2Helper
{
SDL2Helper(const uint32_t& flags, const bool& output = true);
~SDL2Helper(void);
SDL2Helper(const SDL2Helper&) = delete;
SDL2Helper& operator=(const SDL2Helper&) = delete;
bool init;
};
SDL_Window* window;
SDL_GLContext glContext;
WindowState state;
static SDL2Helper helper;
};
}
#endif /* DISPLAY_H */
jtime.h
#ifndef JTIME_H
#define JTIME_H
#include <chrono>
#include <utility>
#ifndef CLOCK_TYPE
#define CLOCK_TYPE std::chrono::steady_clock
#endif // CLOCK_TYPE
namespace jpk
{
template<typename TimeT = std::chrono::milliseconds> class measure
{
public:
measure(void) :
t(CLOCK_TYPE::now())
{}
~measure(void) {}
measure(const measure&) = delete;
measure& operator=(const measure&) = delete;
void start(void)
{
t = CLOCK_TYPE::now();
}
typename TimeT::rep stop(void)
{
return std::chrono::duration_cast<TimeT>(CLOCK_TYPE::now()-t).count();
}
TimeT stop_chrono(void)
{
return std::chrono::duration_cast<TimeT>(CLOCK_TYPE::now()-t);
}
template<typename F, typename... Args> static
typename TimeT::rep duration_single(F func, Args&&... args)
{
auto start(CLOCK_TYPE::now());
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(CLOCK_TYPE::now()-start).count();
}
template<typename F, typename... Args> static typename TimeT::rep
duration_average(const unsigned int& tries, F func, Args&&... args)
{
typename TimeT::rep* times = new typename TimeT::rep[tries];
typename TimeT::rep time(0.0);
for(unsigned int i(0); i < tries ;i++)
times[i] = duration_single(func, args...);
for(unsigned int i(0); i < tries ;i++)
time += times[i];
delete[] times;
return double(time)/double(tries);
}
template<typename F, typename... Args> static
TimeT duration_chrono(F func, Args&&... args)
{
auto start(CLOCK_TYPE::now());
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(CLOCK_TYPE::now()-start);
}
private:
CLOCK_TYPE::time_point t;
};
template<typename TimeT = std::chrono::milliseconds>
void wait(const typename TimeT::rep& time)
{
CLOCK_TYPE::time_point start(CLOCK_TYPE::now());
while(std::chrono::duration_cast<TimeT>(CLOCK_TYPE::now() - start).count()
< time)
{
// Just stop doing anything
}
}
}
#endif /* JTIME_H */
颜色.h
#ifndef COLOR_H
#define COLOR_H
#include <string>
#include <iostream>
#if defined(_WIN32) && !defined(JPK_USE_ANSI)
#include <windows.h>
#endif // _WIN32
namespace jpk
{
class color_t
{
public:
color_t(const unsigned int& col);
#if !defined(_WIN32) || defined(JPK_USE_ANSI)
color_t(const std::string& esc);
#endif // _WIN32
virtual ~color_t(void);
color_t(const color_t&) = delete;
color_t& operator=(const color_t&) = delete;
void use(std::ostream& out) const;
friend std::ostream& operator<<(std::ostream&, const jpk::color_t&);
private:
#if defined(_WIN32) && !defined(JPK_USE_ANSI)
const unsigned int c;
static bool reset_attr_got;
static WORD reset_attr;
#else
const std::string seq;
#endif // _WIN32
};
struct color
{
enum colors
{
BLACK_F,
BLUE_F,
GREEN_F,
CYAN_F,
RED_F,
MAGENTA_F,
BROWN_F,
GREY_F,
DARKGREY_F,
LIGHTBLUE_F,
LIGHTGREEN_F,
LIGHTCYAN_F,
LIGHTRED_F,
LIGHTMAGENTA_F,
YELLOW_F,
WHITE_F,
BLACK_B,
BLUE_B,
GREEN_B,
CYAN_B,
RED_B,
MAGENTA_B,
YELLOW_B,
WHITE_B,
RESET
};
color(void) = delete;
~color(void) = delete;
static color_t black_f;
static color_t red_f;
static color_t green_f;
static color_t brown_f;
static color_t blue_f;
static color_t magenta_f;
static color_t cyan_f;
static color_t grey_f;
static color_t dark_grey_f;
static color_t light_red_f;
static color_t light_green_f;
static color_t yellow_f;
static color_t light_blue_f;
static color_t light_magenta_f;
static color_t light_cyan_f;
static color_t white_f;
static color_t black_b;
static color_t red_b;
static color_t green_b;
static color_t yellow_b;
static color_t blue_b;
static color_t magenta_b;
static color_t cyan_b;
static color_t white_b;
static color_t reset;
};
}
#if !defined(_WIN32) || defined(JPK_USE_ANSI)
std::string getAnsiEsc(const unsigned int& col)
{
switch(col)
{
case jpk::color::BLACK_F: return "\033[22;30m";
case jpk::color::RED_F: return "\033[22;31m";
case jpk::color::GREEN_F: return "\033[22;32m";
case jpk::color::BROWN_F: return "\033[22;33m";
case jpk::color::BLUE_F: return "\033[22;34m";
case jpk::color::MAGENTA_F: return "\033[22;35m";
case jpk::color::CYAN_F: return "\033[22;36m";
case jpk::color::GREY_F: return "\033[22;37m";
case jpk::color::DARKGREY_F: return "\033[01;30m";
case jpk::color::LIGHTRED_F: return "\033[01;31m";
case jpk::color::LIGHTGREEN_F: return "\033[01;32m";
case jpk::color::YELLOW_F: return "\033[01;33m";
case jpk::color::LIGHTBLUE_F: return "\033[01;34m";
case jpk::color::LIGHTMAGENTA_F: return "\033[01;35m";
case jpk::color::LIGHTCYAN_F: return "\033[01;36m";
case jpk::color::WHITE_F: return "\033[01;37m";
case jpk::color::BLACK_B: return "\033[40m";
case jpk::color::RED_B: return "\033[41m";
case jpk::color::GREEN_B: return "\033[42m";
case jpk::color::YELLOW_B: return "\033[43m";
case jpk::color::BLUE_B: return "\033[44m";
case jpk::color::MAGENTA_B: return "\033[45m";
case jpk::color::CYAN_B: return "\033[46m";
case jpk::color::WHITE_B: return "\033[47m";
case jpk::color::RESET: return "\033[0m";
}
return "";
}
#endif // _WIN32
jpk::color_t::color_t(const unsigned int& col) :
#if defined(_WIN32) && !defined(JPK_USE_ANSI)
c(col)
{
if(!reset_attr_got)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
reset_attr = csbi.wAttributes;
reset_attr_got = true;
}
#else
seq(jpk::getAnsiEsc(col))
{}
jpk::color_t::color_t(const std::string& esc) :
seq(esc)
{
#endif // _WIN32
}
jpk::color_t::~color_t(void) {}
#if defined(_WIN32) && !defined(JPK_USE_ANSI)
bool jpk::color_t::reset_attr_got(false);
WORD jpk::color_t::reset_attr(0);
void jpk::color_t::use(std::ostream& out) const
{
if(c <= jpk::color::RESET)
{
HANDLE hConsole(GetStdHandle(STD_OUTPUT_HANDLE));
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
if(c < jpk::color::BLACK_B)
SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFFF0) | (WORD)c);
else if((c > jpk::color::WHITE_F) && (c < jpk::color::RESET))
SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFF0F) | (((WORD)(c - jpk::color::BLACK_B)) << 4));
else if(c == jpk::color::RESET)
SetConsoleTextAttribute(hConsole, reset_attr);
}
}
jpk::color_t jpk::color::black_f(jpk::color::BLACK_F);
jpk::color_t jpk::color::red_f(jpk::color::RED_F);
jpk::color_t jpk::color::green_f(jpk::color::GREEN_F);
jpk::color_t jpk::color::brown_f(jpk::color::BROWN_F);
jpk::color_t jpk::color::blue_f(jpk::color::BLUE_F);
jpk::color_t jpk::color::magenta_f(jpk::color::MAGENTA_F);
jpk::color_t jpk::color::cyan_f(jpk::color::CYAN_F);
jpk::color_t jpk::color::grey_f(jpk::color::GREY_F);
jpk::color_t jpk::color::dark_grey_f(jpk::color::DARKGREY_F);
jpk::color_t jpk::color::light_red_f(jpk::color::LIGHTRED_F);
jpk::color_t jpk::color::light_green_f(jpk::color::LIGHTGREEN_F);
jpk::color_t jpk::color::yellow_f(jpk::color::YELLOW_F);
jpk::color_t jpk::color::light_blue_f(jpk::color::LIGHTBLUE_F);
jpk::color_t jpk::color::light_magenta_f(jpk::color::LIGHTMAGENTA_F);
jpk::color_t jpk::color::light_cyan_f(jpk::color::LIGHTCYAN_F);
jpk::color_t jpk::color::white_f(jpk::color::WHITE_F);
jpk::color_t jpk::color::black_b(jpk::color::BLACK_B);
jpk::color_t jpk::color::red_b(jpk::color::RED_B);
jpk::color_t jpk::color::green_b(jpk::color::GREEN_B);
jpk::color_t jpk::color::yellow_b(jpk::color::YELLOW_B);
jpk::color_t jpk::color::blue_b(jpk::color::BLUE_B);
jpk::color_t jpk::color::magenta_b(jpk::color::MAGENTA_B);
jpk::color_t jpk::color::cyan_b(jpk::color::CYAN_B);
jpk::color_t jpk::color::white_b(jpk::color::WHITE_B);
jpk::color_t jpk::color::reset(jpk::color::RESET);
#else
void jpk::color_t::use(std::ostream& out) const
{
out << seq;
}
jpk::color_t jpk::color::black_f("\033[22;30m");
jpk::color_t jpk::color::red_f("\033[22;31m");
jpk::color_t jpk::color::green_f("\033[22;32m");
jpk::color_t jpk::color::brown_f("\033[22;33m");
jpk::color_t jpk::color::blue_f("\033[22;34m");
jpk::color_t jpk::color::magenta_f("\033[22;35m");
jpk::color_t jpk::color::cyan_f("\033[22;36m");
jpk::color_t jpk::color::grey_f("\033[22;37m");
jpk::color_t jpk::color::dark_grey_f("\033[01;30m");
jpk::color_t jpk::color::light_red_f("\033[01;31m");
jpk::color_t jpk::color::light_green_f("\033[01;32m");
jpk::color_t jpk::color::yellow_f("\033[01;33m");
jpk::color_t jpk::color::light_blue_f("\033[01;34m");
jpk::color_t jpk::color::light_magenta_f("\033[01;35m");
jpk::color_t jpk::color::light_cyan_f("\033[01;36m");
jpk::color_t jpk::color::white_f("\033[01;37m");
jpk::color_t jpk::color::black_b("\033[40m");
jpk::color_t jpk::color::red_b("\033[41m");
jpk::color_t jpk::color::green_b("\033[42m");
jpk::color_t jpk::color::yellow_b("\033[43m");
jpk::color_t jpk::color::blue_b("\033[44m");
jpk::color_t jpk::color::magenta_b("\033[45m");
jpk::color_t jpk::color::cyan_b("\033[46m");
jpk::color_t jpk::color::white_b("\033[47m");
jpk::color_t jpk::color::reset("\033[0m");
#endif // _WIN32
namespace jpk
{
std::ostream& operator<<(std::ostream& out, const color_t& col)
{
col.use(out);
return out;
}
}
#endif /* COLOR_H */