I am using SDL 2.0.4 and GLEW 1.13.0 and it seems like there is some kind of fps limit in SDL2. I know this, because I did some time measurement.
To be more specific, I do not draw anything, but if I call SDL_GL_SwapWindow() in my main loop, each cycle takes about 16 milliseconds. Without this call it takes almost no time at all. It even takes 16 milliseconds, when SDL_GL_SwapWindow is the only function call in the main loop. This means, that there has to be some kind of fps limitation or vsync enabled in SDL2. So my question is: How do I disable said limitation?
The only thread I found, that somewhat closely resembles my question, is the following: SDL_GL_SwapWindow bad performance . But the answers in this thread don't really are of help to me. Furthermore, this doesn't seem to be caused by my computer, because the issue doesn't occur on similar code done with FreeGLUT.
Brief overview over all files:
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()
My Code:
main.cpp
#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;
}
}
display.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;
}
display.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 */
color.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 */