diff options
22 files changed, 266 insertions, 1 deletions
diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst index c3bcf19c01b..5a80b7fa5c1 100644 --- a/doc/python_api/rst/bge.render.rst +++ b/doc/python_api/rst/bge.render.rst @@ -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 diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index a92d0d33b65..aae90179be5 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -666,6 +666,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 * \return An intean success indicator. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index a2d3e9b91fb..35577075263 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -205,6 +205,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. */ diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index b73ff26c259..8d4498ed759 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -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) diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 588de0911e3..77ee4db8543 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -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; */ @@ -205,6 +209,23 @@ public: } /** + * 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 */ virtual void setAcceptDragOperation(bool canAccept); diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index b0d0b1a5b5d..c264686fbb1 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -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() { diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 2fd1f5b37f4..6fdc963f30a 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -212,6 +212,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. */ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 25d7c181b68..3173736c2a5 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -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; +} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index b8471b41a11..7cbdcdeec21 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -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. diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 38e49853454..025d86204f2 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -414,6 +414,9 @@ class RENDER_PT_game_system(RenderButtonsPanel, Panel): col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT' row = layout.row() + row.prop(gs, "vsync") + + row = layout.row() row.prop(gs, "raster_storage") row = layout.row() diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 70541f7cec5..062107f834e 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -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 ***************** */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 22fa2423f61..d7e938fec7c 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -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); diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index bb4c3fd2cbc..5703527eae0 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -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; } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp index 3bd1c02f12e..3089b3fd44d 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp @@ -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 diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h index c201d866efe..c5318b882fa 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h @@ -80,6 +80,16 @@ public: void SwapBuffers( ); + + void + SetSwapInterval( + int interval + ); + + int + GetSwapInterval( + ); + void ResizeWindow( int width, diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index 61598995040..6ed4866579c 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -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 */ diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.h b/source/gameengine/BlenderRoutines/KX_BlenderGL.h index 54e76ff6489..8032d9a594a 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.h @@ -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); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index bedee5d9a47..6f7a87804dc 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -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); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp index a1d00dad0e1..e0559385ee6 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp @@ -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) diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h index 6168d96b337..6e1f86cac0e 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h @@ -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); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 7845c113643..e595f24a662 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -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 diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h index 1b1e43a5257..9e8a6e8ccf6 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.h +++ b/source/gameengine/Rasterizer/RAS_ICanvas.h @@ -105,6 +105,17 @@ public: void SwapBuffers( )=0; + + virtual + void + SetSwapInterval( + int interval + )=0; + + virtual + int + GetSwapInterval( + )=0; virtual void |