forked from bartvdbraak/blender
BGE: Adding vsync control. Users can enable vsync, disable vsync, or use adaptive vsync via UI options in the render properties, or by using the new Python method bge.render.setVsync(). Win32 and X11 support are done via EXT_swap_control. Support for using EXT_swap_control on OS X still needs to be added to Ghost.
This commit is contained in:
parent
2840edba84
commit
29f8dfd37a
@ -62,6 +62,18 @@ Constants
|
||||
.. data:: KX_BLENDER_GLSL_MATERIAL
|
||||
|
||||
Materials approximating blender materials with GLSL.
|
||||
|
||||
.. DATA:: VSYNC_OFF
|
||||
|
||||
Disables vsync
|
||||
|
||||
.. DATA:: VSYNC_ON
|
||||
|
||||
Enables vsync
|
||||
|
||||
.. DATA:: VSYNC_ADAPTIVE
|
||||
|
||||
Enables adaptive vsync if supported. Adaptive vsync enables vsync if the framerate is above the monitors refresh rate. Otherwise, vsync is diabled if the framerate is too low.
|
||||
|
||||
*********
|
||||
Functions
|
||||
@ -289,3 +301,15 @@ Functions
|
||||
|
||||
Disable the motion blur effect.
|
||||
|
||||
.. function:: setVsync(value)
|
||||
|
||||
Set the vsync value
|
||||
|
||||
:arg value: One of VSYNC_OFF, VSYNC_ON, VSYNC_ADAPTIVE
|
||||
:type value: integer
|
||||
|
||||
.. function:: getVsync()
|
||||
|
||||
Get the current vsync value
|
||||
|
||||
:rtype: One of VSYNC_OFF, VSYNC_ON, VSYNC_ADAPTIVE
|
||||
|
@ -665,6 +665,19 @@ extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle,
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle);
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interval);
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \return An integer.
|
||||
*/
|
||||
extern int GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle);
|
||||
|
||||
/**
|
||||
* Activates the drawing context of this window.
|
||||
* \param windowhandle The handle to the window
|
||||
|
@ -204,6 +204,19 @@ public:
|
||||
*/
|
||||
virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
virtual GHOST_TSuccess setSwapInterval(int interval) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \return An integer.
|
||||
*/
|
||||
virtual int getSwapInterval() = 0;
|
||||
|
||||
/**
|
||||
* Activates the drawing context of this window.
|
||||
* \return A boolean success indicator.
|
||||
|
@ -691,6 +691,19 @@ GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle)
|
||||
return window->swapBuffers();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interval)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
|
||||
|
||||
return window->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
|
||||
|
||||
return window->getSwapInterval();
|
||||
}
|
||||
|
||||
|
||||
GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle)
|
||||
|
@ -67,6 +67,8 @@ public:
|
||||
* virtual GHOST_TWindowOrder getOrder(void) = 0;
|
||||
* virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0;
|
||||
* virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
* virtual GHOST_TSuccess setSwapInterval() = 0;
|
||||
* virtual int getSwapInterval() = 0;
|
||||
* virtual GHOST_TSuccess activateDrawingContext() = 0;
|
||||
* virtual GHOST_TSuccess invalidate() = 0;
|
||||
*/
|
||||
@ -110,6 +112,8 @@ public:
|
||||
* virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0;
|
||||
* virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0;
|
||||
* virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
* virtual GHOST_TSuccess setSwapInterval() = 0;
|
||||
* virtual int getSwapInterval() = 0;
|
||||
* virtual GHOST_TSuccess activateDrawingContext() = 0;
|
||||
* virtual GHOST_TSuccess invalidate() = 0;
|
||||
*/
|
||||
@ -204,6 +208,23 @@ public:
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
virtual GHOST_TSuccess setSwapInterval(int interval) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \return An integer.
|
||||
*/
|
||||
virtual int getSwapInterval() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
|
||||
*/
|
||||
|
@ -648,6 +648,20 @@ GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
|
||||
return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWin32::setSwapInterval(int interval)
|
||||
{
|
||||
if (!WGL_EXT_swap_control)
|
||||
return GHOST_kFailure;
|
||||
return wglSwapIntervalEXT(interval) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
|
||||
}
|
||||
|
||||
int GHOST_WindowWin32::getSwapInterval()
|
||||
{
|
||||
if (WGL_EXT_swap_control)
|
||||
return wglGetSwapIntervalEXT();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
|
||||
{
|
||||
|
@ -211,6 +211,19 @@ public:
|
||||
*/
|
||||
virtual GHOST_TSuccess swapBuffers();
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
virtual GHOST_TSuccess setSwapInterval(int interval);
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \return An integer.
|
||||
*/
|
||||
virtual int getSwapInterval();
|
||||
|
||||
/**
|
||||
* Activates the drawing context of this window.
|
||||
* \return Indication of success.
|
||||
|
@ -30,6 +30,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <GL/glxew.h>
|
||||
|
||||
#include "GHOST_WindowX11.h"
|
||||
#include "GHOST_SystemX11.h"
|
||||
#include "STR_String.h"
|
||||
@ -1513,3 +1515,23 @@ endFullScreen() const
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess
|
||||
GHOST_WindowX11::
|
||||
setSwapInterval(int interval) {
|
||||
if (!GLX_EXT_swap_control)
|
||||
return GHOST_kFailure;
|
||||
glXSwapIntervalEXT(m_display, m_window, interval);
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
int
|
||||
GHOST_WindowX11::
|
||||
getSwapInterval() {
|
||||
if (GLX_EXT_swap_control) {
|
||||
unsigned int value;
|
||||
glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &value);
|
||||
return (int)value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -235,6 +235,19 @@ public:
|
||||
|
||||
GHOST_TSuccess endFullScreen() const;
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
virtual GHOST_TSuccess setSwapInterval(int interval);
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \return An integer.
|
||||
*/
|
||||
virtual int getSwapInterval();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Tries to install a rendering context in this window.
|
||||
|
@ -413,6 +413,9 @@ class RENDER_PT_game_system(RenderButtonsPanel, Panel):
|
||||
col.prop(gs, "use_display_lists")
|
||||
col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT'
|
||||
|
||||
row = layout.row()
|
||||
row.prop(gs, "vsync")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(gs, "raster_storage")
|
||||
|
||||
|
@ -1324,6 +1324,16 @@ void wm_window_swap_buffers(wmWindow *win)
|
||||
#endif
|
||||
}
|
||||
|
||||
void wm_window_set_swap_interval (wmWindow *win, int interval)
|
||||
{
|
||||
GHOST_SetSwapInterval(win->ghostwin, interval);
|
||||
}
|
||||
|
||||
int wm_window_get_swap_interval (wmWindow *win)
|
||||
{
|
||||
return GHOST_GetSwapInterval(win->ghostwin);
|
||||
}
|
||||
|
||||
|
||||
/* ******************* exported api ***************** */
|
||||
|
||||
|
@ -58,6 +58,8 @@ void wm_window_lower (wmWindow *win);
|
||||
void wm_window_set_size (wmWindow *win, int width, int height);
|
||||
void wm_window_get_position (wmWindow *win, int *posx_r, int *posy_r);
|
||||
void wm_window_swap_buffers (wmWindow *win);
|
||||
void wm_window_set_swap_interval (wmWindow *win, int interval);
|
||||
int wm_window_get_swap_interval (wmWindow *win);
|
||||
|
||||
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
|
||||
|
||||
|
@ -284,6 +284,14 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
|
||||
canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
|
||||
else
|
||||
canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
|
||||
|
||||
// Setup vsync
|
||||
int previous_vsync = canvas->GetSwapInterval();
|
||||
if (startscene->gm.vsync == VSYNC_ADAPTIVE)
|
||||
canvas->SetSwapInterval(-1);
|
||||
else
|
||||
canvas->SetSwapInterval(startscene->gm.vsync); // VSYNC_OFF == 0, VSYNC_ON == 1, so this works
|
||||
|
||||
RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
|
||||
RAS_IRasterizer* rasterizer = NULL;
|
||||
//Don't use displaylists with VBOs
|
||||
@ -663,6 +671,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
|
||||
}
|
||||
if (canvas)
|
||||
{
|
||||
canvas->SetSwapInterval(previous_vsync); // Set the swap interval back
|
||||
delete canvas;
|
||||
canvas = NULL;
|
||||
}
|
||||
|
@ -66,6 +66,16 @@ void KX_BlenderCanvas::SwapBuffers()
|
||||
BL_SwapBuffers(m_win);
|
||||
}
|
||||
|
||||
void KX_BlenderCanvas::SetSwapInterval(int interval)
|
||||
{
|
||||
BL_SetSwapInterval(m_win, interval);
|
||||
}
|
||||
|
||||
int KX_BlenderCanvas::GetSwapInterval()
|
||||
{
|
||||
return BL_GetSwapInterval(m_win);
|
||||
}
|
||||
|
||||
void KX_BlenderCanvas::ResizeWindow(int width, int height)
|
||||
{
|
||||
// Not implemented for the embedded player
|
||||
|
@ -80,6 +80,16 @@ public:
|
||||
void
|
||||
SwapBuffers(
|
||||
);
|
||||
|
||||
void
|
||||
SetSwapInterval(
|
||||
int interval
|
||||
);
|
||||
|
||||
int
|
||||
GetSwapInterval(
|
||||
);
|
||||
|
||||
void
|
||||
ResizeWindow(
|
||||
int width,
|
||||
|
@ -98,6 +98,16 @@ void BL_MakeDrawable(wmWindowManager *wm, wmWindow *win)
|
||||
wm_window_make_drawable(wm, win);
|
||||
}
|
||||
|
||||
void BL_SetSwapInterval(struct wmWindow *win, int interval)
|
||||
{
|
||||
wm_window_set_swap_interval(win, interval);
|
||||
}
|
||||
|
||||
int BL_GetSwapInterval(struct wmWindow *win)
|
||||
{
|
||||
return wm_window_get_swap_interval(win);
|
||||
}
|
||||
|
||||
static void DisableForText()
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* needed for texture fonts otherwise they render as wireframe */
|
||||
|
@ -43,6 +43,8 @@ struct wmWindowManager;
|
||||
|
||||
// special swapbuffers, that takes care of which area (viewport) needs to be swapped
|
||||
void BL_SwapBuffers(struct wmWindow *win);
|
||||
void BL_SetSwapInterval(struct wmWindow *win, int interval);
|
||||
int BL_GetSwapInterval(struct wmWindow *win);
|
||||
|
||||
void BL_MakeDrawable(struct wmWindowManager *wm, struct wmWindow *win);
|
||||
|
||||
|
@ -582,7 +582,12 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
|
||||
m_canvas = new GPG_Canvas(window);
|
||||
if (!m_canvas)
|
||||
return false;
|
||||
|
||||
|
||||
if (gm->vsync == VSYNC_ADAPTIVE)
|
||||
m_canvas->SetSwapInterval(-1);
|
||||
else
|
||||
m_canvas->SetSwapInterval(gm->vsync); // VSYNC_OFF == 0, VSYNC_ON == 1, so this works
|
||||
|
||||
m_canvas->Init();
|
||||
if (gm->flag & GAME_SHOW_MOUSE)
|
||||
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
|
||||
|
@ -107,6 +107,20 @@ void GPG_Canvas::SwapBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
void GPG_Canvas::SetSwapInterval(int interval)
|
||||
{
|
||||
if (m_window)
|
||||
m_window->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int GPG_Canvas::GetSwapInterval()
|
||||
{
|
||||
if (m_window)
|
||||
return m_window->getSwapInterval();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GPG_Canvas::ResizeWindow(int width, int height)
|
||||
{
|
||||
if (m_window->getState() == GHOST_kWindowStateFullScreen)
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
virtual void SetMousePosition(int x, int y);
|
||||
virtual void SetMouseState(RAS_MouseState mousestate);
|
||||
virtual void SwapBuffers();
|
||||
virtual void SetSwapInterval(int interval);
|
||||
virtual int GetSwapInterval();
|
||||
|
||||
virtual int GetMouseX(int x) { return x; }
|
||||
virtual int GetMouseY(int y) { return y; }
|
||||
virtual float GetMouseNormalizedX(int x);
|
||||
|
@ -1372,6 +1372,29 @@ static PyObject *gPyGetMipmapping(PyObject *)
|
||||
return PyLong_FromLong(gp_Rasterizer->GetMipmapping());
|
||||
}
|
||||
|
||||
static PyObject *gPySetVsync(PyObject *, PyObject *args)
|
||||
{
|
||||
int interval;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:setVsync", &interval))
|
||||
return NULL;
|
||||
|
||||
if (interval < VSYNC_OFF || interval > VSYNC_ADAPTIVE) {
|
||||
PyErr_SetString(PyExc_ValueError, "Rasterizer.setVsync(value): value must be VSYNC_OFF, VSYNC_ON, or VSYNC_ADAPTIVE");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (interval == VSYNC_ADAPTIVE)
|
||||
interval = -1;
|
||||
gp_Canvas->SetSwapInterval(interval);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *gPyGetVsync(PyObject *)
|
||||
{
|
||||
return PyLong_FromLong(gp_Canvas->GetSwapInterval());
|
||||
}
|
||||
|
||||
static struct PyMethodDef rasterizer_methods[] = {
|
||||
{"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
|
||||
METH_VARARGS, "getWindowWidth doc"},
|
||||
@ -1417,6 +1440,8 @@ static struct PyMethodDef rasterizer_methods[] = {
|
||||
{"getFullScreen", (PyCFunction) gPyGetFullScreen, METH_NOARGS, ""},
|
||||
{"setMipmapping", (PyCFunction) gPySetMipmapping, METH_VARARGS, ""},
|
||||
{"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""},
|
||||
{"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""},
|
||||
{"getVsync", (PyCFunction) gPyGetVsync, METH_NOARGS, ""},
|
||||
{ NULL, (PyCFunction) NULL, 0, NULL }
|
||||
};
|
||||
|
||||
@ -2189,6 +2214,11 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
|
||||
KX_MACRO_addTypesToDict(d, RAS_MIPMAP_NEAREST, RAS_IRasterizer::RAS_MIPMAP_NEAREST);
|
||||
KX_MACRO_addTypesToDict(d, RAS_MIPMAP_LINEAR, RAS_IRasterizer::RAS_MIPMAP_LINEAR);
|
||||
|
||||
/* for get/setVsync */
|
||||
KX_MACRO_addTypesToDict(d, VSYNC_OFF, VSYNC_OFF);
|
||||
KX_MACRO_addTypesToDict(d, VSYNC_ON, VSYNC_ON);
|
||||
KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, VSYNC_ADAPTIVE);
|
||||
|
||||
// XXXX Add constants here
|
||||
|
||||
// Check for errors
|
||||
|
@ -105,6 +105,17 @@ public:
|
||||
void
|
||||
SwapBuffers(
|
||||
)=0;
|
||||
|
||||
virtual
|
||||
void
|
||||
SetSwapInterval(
|
||||
int interval
|
||||
)=0;
|
||||
|
||||
virtual
|
||||
int
|
||||
GetSwapInterval(
|
||||
)=0;
|
||||
|
||||
virtual
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user