Skip to content

Commit

Permalink
UPBGE: Fix bge.render.[get/set]Vsync. (#834)
Browse files Browse the repository at this point in the history
Previously bge.render.getVsync wasn't returning the value set by setVsync when
VSYNC_ADAPTIVE was used. It can be justified by the fact that adaptive is set
by using a negative swap interval value but the GLX get function still returns
a positive swap interval value and the flag GLX_LATE_SWAPS_TEAR_EXT meaning
adaptive is enabled.

In any case GLX could refuse a swap interval and the user should be able to do
setVsync(getVsync()) with no change on the swap control. To achieve this behaviour
RAS_ICanvas store the current swap control in a enum variable m_controlSwap,
this variable is used in getter GetSwapControl used by bge.render.getVsync().
The setter is virtual and overloaded in each canvas implementation, they use
a common table to find the swap interval associated to the swap control mode:
RAS_ICanvas::swapInterval.

Finally KX_PythonInit is using swap control enum value from RAS_ICanvas instead
of the one from DNA to avoid conversions.

Fix issue #820.
  • Loading branch information
panzergame authored Sep 29, 2018
1 parent e1b316a commit dbff6df
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 53 deletions.
8 changes: 5 additions & 3 deletions source/blender/makesdna/DNA_scene_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,9 +900,11 @@ typedef struct GameData {
#define OBSTSIMULATION_TOI_cells 2

/* GameData.vsync */
#define VSYNC_ON 0
#define VSYNC_OFF 1
#define VSYNC_ADAPTIVE 2
enum {
VSYNC_ON = 0,
VSYNC_OFF,
VSYNC_ADAPTIVE
};

/* GameData.flag */
#define GAME_RESTRICT_ANIM_UPDATES (1 << 0)
Expand Down
10 changes: 3 additions & 7 deletions source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,10 @@ void KX_BlenderCanvas::SwapBuffers()
wm_window_swap_buffers(m_win);
}

void KX_BlenderCanvas::SetSwapInterval(int interval)
void KX_BlenderCanvas::SetSwapControl(SwapControl control)
{
wm_window_set_swap_interval(m_win, interval);
}

bool KX_BlenderCanvas::GetSwapInterval(int &intervalOut)
{
return wm_window_get_swap_interval(m_win, &intervalOut);
wm_window_set_swap_interval(m_win, swapInterval[control]);
RAS_ICanvas::SetSwapControl(control);
}

void KX_BlenderCanvas::GetDisplayDimensions(int &width, int &height)
Expand Down
3 changes: 1 addition & 2 deletions source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ class KX_BlenderCanvas : public RAS_ICanvas
virtual void Init();

virtual void SwapBuffers();
virtual void SetSwapInterval(int interval);
virtual bool GetSwapInterval(int &intervalOut);
virtual void SetSwapControl(SwapControl control);

virtual void GetDisplayDimensions(int &width, int &height);
virtual void ResizeWindow(int width, int height);
Expand Down
14 changes: 3 additions & 11 deletions source/gameengine/GamePlayer/GPG_Canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,20 +211,12 @@ void GPG_Canvas::SwapBuffers()
}
}

void GPG_Canvas::SetSwapInterval(int interval)
void GPG_Canvas::SetSwapControl(SwapControl control)
{
if (m_window) {
m_window->setSwapInterval(interval);
m_window->setSwapInterval(swapInterval[control]);
}
}

bool GPG_Canvas::GetSwapInterval(int& intervalOut)
{
if (m_window) {
return (bool)m_window->getSwapInterval(intervalOut);
}

return false;
RAS_ICanvas::SetSwapControl(control);
}

void GPG_Canvas::GetDisplayDimensions(int &width, int &height)
Expand Down
3 changes: 1 addition & 2 deletions source/gameengine/GamePlayer/GPG_Canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ class GPG_Canvas : public RAS_ICanvas
virtual void SetMousePosition(int x, int y);
virtual void SetMouseState(RAS_MouseState mousestate);
virtual void SwapBuffers();
virtual void SetSwapInterval(int interval);
virtual bool GetSwapInterval(int& intervalOut);
virtual void SetSwapControl(SwapControl control);

virtual void ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen);
virtual float GetMouseNormalizedX(int x);
Expand Down
21 changes: 8 additions & 13 deletions source/gameengine/Ketsji/KX_PythonInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,29 +1298,24 @@ static PyObject *gPyGetMipmapping(PyObject *)

static PyObject *gPySetVsync(PyObject *, PyObject *args)
{
int interval;
int control;

if (!PyArg_ParseTuple(args, "i:setVsync", &interval)) {
if (!PyArg_ParseTuple(args, "i:setVsync", &control)) {
return nullptr;
}

if (interval < 0 || interval > VSYNC_ADAPTIVE) {
if (control < 0 || control >= RAS_ICanvas::SWAP_CONTROL_MAX) {
PyErr_SetString(PyExc_ValueError, "Rasterizer.setVsync(value): value must be VSYNC_OFF, VSYNC_ON, or VSYNC_ADAPTIVE");
return nullptr;
}

if (interval == VSYNC_ADAPTIVE) {
interval = -1;
}
KX_GetActiveEngine()->GetCanvas()->SetSwapInterval((interval == VSYNC_ON) ? 1 : 0);
KX_GetActiveEngine()->GetCanvas()->SetSwapControl((RAS_ICanvas::SwapControl)control);
Py_RETURN_NONE;
}

static PyObject *gPyGetVsync(PyObject *)
{
int interval = 0;
KX_GetActiveEngine()->GetCanvas()->GetSwapInterval(interval);
return PyLong_FromLong(interval);
return PyLong_FromLong(KX_GetActiveEngine()->GetCanvas()->GetSwapControl());
}

static PyObject *gPyShowFramerate(PyObject *, PyObject *args)
Expand Down Expand Up @@ -2200,9 +2195,9 @@ PyMODINIT_FUNC initRasterizerPythonBinding()
KX_MACRO_addTypesToDict(d, RAS_MIPMAP_LINEAR, RAS_Rasterizer::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);
KX_MACRO_addTypesToDict(d, VSYNC_OFF, RAS_ICanvas::VSYNC_OFF);
KX_MACRO_addTypesToDict(d, VSYNC_ON, RAS_ICanvas::VSYNC_ON);
KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, RAS_ICanvas::VSYNC_ADAPTIVE);

/* stereoscopy */
KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_Rasterizer::RAS_STEREO_LEFTEYE);
Expand Down
18 changes: 6 additions & 12 deletions source/gameengine/Launcher/LA_Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,13 @@ void LA_Launcher::InitEngine()
// Create the canvas, rasterizer and rendertools.
m_canvas = CreateCanvas(m_rasterizer);

// Copy current vsync mode to restore at the game end.
m_canvas->GetSwapInterval(m_savedData.vsync);
static const RAS_ICanvas::SwapControl swapControlTable[] = {
RAS_ICanvas::VSYNC_ON, // VSYNC_ON
RAS_ICanvas::VSYNC_OFF, // VSYNC_OFF
RAS_ICanvas::VSYNC_ADAPTIVE // VSYNC_ADAPTIVE
};

if (gm.vsync == VSYNC_ADAPTIVE) {
m_canvas->SetSwapInterval(-1);
}
else {
m_canvas->SetSwapInterval((gm.vsync == VSYNC_ON) ? 1 : 0);
}
m_canvas->SetSwapControl(swapControlTable[gm.vsync]);

// Set canvas multisamples.
m_canvas->SetSamples(m_samples);
Expand Down Expand Up @@ -326,13 +324,9 @@ void LA_Launcher::ExitEngine()

// Set anisotropic settign back to its original value.
m_rasterizer->SetAnisotropicFiltering(m_savedData.anisotropic);

// Set mipmap setting back to its original value.
m_rasterizer->SetMipmapping(m_savedData.mipmap);

// Set vsync mode back to original value.
m_canvas->SetSwapInterval(m_savedData.vsync);

if (m_converter) {
delete m_converter;
m_converter = nullptr;
Expand Down
1 change: 0 additions & 1 deletion source/gameengine/Launcher/LA_Launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class LA_Launcher

/// Saved data to restore at the game end.
struct SavedData {
int vsync;
RAS_Rasterizer::MipmapOption mipmap;
int anisotropic;
} m_savedData;
Expand Down
16 changes: 16 additions & 0 deletions source/gameengine/Rasterizer/RAS_ICanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,16 @@ struct ScreenshotTaskData {
*/
void save_screenshot_thread_func(TaskPool *__restrict pool, void *taskdata, int threadid);

const int RAS_ICanvas::swapInterval[RAS_ICanvas::SWAP_CONTROL_MAX] = {
0, // VSYNC_OFF
1, // VSYNC_ON
-1 // VSYNC_ADAPTIVE
};

RAS_ICanvas::RAS_ICanvas(RAS_Rasterizer *rasty)
:m_samples(0),
m_hdrType(RAS_Rasterizer::RAS_HDR_NONE),
m_swapControl(VSYNC_OFF),
m_frame(1)
{
m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
Expand All @@ -87,6 +93,16 @@ RAS_ICanvas::~RAS_ICanvas()
}
}

void RAS_ICanvas::SetSwapControl(SwapControl control)
{
m_swapControl = control;
}

RAS_ICanvas::SwapControl RAS_ICanvas::GetSwapControl() const
{
return m_swapControl;
}

void RAS_ICanvas::SetSamples(int samples)
{
m_samples = samples;
Expand Down
16 changes: 14 additions & 2 deletions source/gameengine/Rasterizer/RAS_ICanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ class RAS_ICanvas
MOUSE_NORMAL
};

enum SwapControl
{
VSYNC_OFF = 0,
VSYNC_ON,
VSYNC_ADAPTIVE,
SWAP_CONTROL_MAX
};

RAS_ICanvas(RAS_Rasterizer *rasty);
virtual ~RAS_ICanvas();

Expand All @@ -77,8 +85,8 @@ class RAS_ICanvas

/// probably needs some arguments for PS2 in future
virtual void SwapBuffers() = 0;
virtual void SetSwapInterval(int interval) = 0;
virtual bool GetSwapInterval(int& intervalOut) = 0;
virtual void SetSwapControl(SwapControl control);
SwapControl GetSwapControl() const;

void SetSamples(int samples);
int GetSamples() const;
Expand Down Expand Up @@ -152,6 +160,9 @@ class RAS_ICanvas
}

protected:
/// Swap interval value of each swap control mode.
static const int swapInterval[SWAP_CONTROL_MAX];

struct Screenshot
{
std::string path;
Expand All @@ -167,6 +178,7 @@ class RAS_ICanvas
int m_samples;
RAS_Rasterizer::HdrType m_hdrType;

SwapControl m_swapControl;
RAS_MouseState m_mousestate;
/// frame number for screenshots.
int m_frame;
Expand Down

0 comments on commit dbff6df

Please sign in to comment.