我正在使用SDL 2.0.4和GLEW 1.13.0,似乎SDL2中存在某种fps限制。我知道这一点,因为我做了一些时间测量。
更具体地说,我没有绘制任何东西,但如果我在主循环中调用SDL_GL_SwapWindow(),则每个循环大约需要16毫秒。没有这个电话,几乎没有时间。当SDL_GL_SwapWindow是主循环中唯一的函数调用时,它甚至需要16毫秒。这意味着,在SDL2中必须启用某种fps限制或vsync。所以我的问题是:如何禁用上述限制?
我找到的唯一一个与我的问题非常相似的主题是:SDL_GL_SwapWindow bad performance。但是这个帖子中的答案并没有对我有所帮助。此外,这似乎不是由我的计算机引起的,因为使用FreeGLUT完成的类似代码不会出现此问题。
所有文件的简要概述:
INotifyCollectionChanged
我的代码:
的main.cpp
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()
display.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.h
#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;
}
jtime.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 */
color.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 */
答案 0 :(得分:1)
这与SDL无关,但与图形驱动程序的OpenGL设置无关。当交换缓冲区时,操作可以与显示器刷新同步,从而不会出现撕裂假象。如果您的程序绘制速度快于显示器能够重绘,那么在一个显示的框架内可以显示几个&#34;条纹&#34;渲染将出现,每个延迟的时间是渲染第一个。 因此,通常你实际上_want_你的重绘是FPS限制并同步到显示刷新。有许多API可以在程序中有选择地启用或禁用它(尽管驱动程序总是可以选择覆盖那个)。在OpenGL(它是API SDL_GL_SwapBuffers)的情况下,通过API来控制这是所谓的&#34;交换间隔&#34; API。详细信息可以在OpenGL wiki中找到:https://www.opengl.org/wiki/Swap_Interval