Get/Set Refresh Rate

To be able to change the refresh rate,
there are 2 new video extension functions:

1) VidExt_ListFullscreenRates
    This function allows you to retrieve a
    list of refresh rates for a given resolution

2) VidExt_SetVideoModeWithRate
    This function allows you to set a video mode,
    with a specified refresh rate
This commit is contained in:
Rosalie Wanders 2020-07-28 18:38:40 +02:00
parent a29b44251a
commit 4baba51077
7 changed files with 216 additions and 5 deletions

View file

@ -117,6 +117,8 @@ This is the most complicated interface, because it involves 3 components: the vi
** add m64p_video_flags parameter to the VidExt_SetVideoMode() function. Currently the flags are only used to notify the window manager that resizing is supported by the video plugin, and it should create a resizable window if possible. This may be extended in the future to support other features.
* '''VIDEXT_API_VERSION''' version 3.1.0:
** add VidExt_GL_GetDefaultFramebuffer() function in video extension. This function should be called to get the name of the default FBO.
* '''VIDEXT_API_VERSION''' version 3.2.0:
** add the VidExt_ListFullscreenRates and VidExt_SetVideoModeWithRate functions, which allow setting and getting the fullscreen refresh rate
* '''INPUT_API_VERSION''' version 2.0.1:
** add (optional) RenderCallback function to input plugin. This function is called by the core after rendering on screen text (OSD) and before the graphics plugin swaps the buffers. The purpose of this function is to enable the input plugin to draw on screen content, for example buttons in a touch input plugin. If this function is not present the core will ignore it and on screen rendering by the input plugin will be disabled.
* '''INPUT_API_VERSION''' version 2.1.0:

View file

@ -51,6 +51,22 @@ All of these functions should only be called from within the video plugin; they
<br />
{| border="1"
|Prototype
|'''<tt>m64p_error VidExt_ListFullscreenRates(m64p_2d_size Size, int *NumRates, int *Rates)</tt>'''
|-
|Input Parameters
|'''<tt>Size</tt>''' <tt>m64p_2d_size</tt> object, defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]] of the resolution you want to retrieve the fullscreen refresh rates from.<br />
'''<tt>NumRates</tt>''' Pointer to an integer which contains the size of '''<tt>Rates</tt>''' for input, and the number of size objects stored for output.<br />
'''<tt>Rates</tt>''' Pointer to an array of integers which will contain the refresh rates.
|-
|Requirements
|The video extension must be initialized before calling this function.
|-
|Usage
|This function is used to enumerate the available refresh rates for a given resolution. An '''<tt>m64p_2d_size</tt>''' object is passed into the function, which will contain the resolution of the refresh rates you want to retrieve, an array '''<tt>Rates</tt>''' is passed into the function, which is then filled (up to <tt>*'''NumRates'''</tt> objects) with resolution sizes. The number of sizes actually written is stored in the integer which is pointed to by '''<tt>NumSizes</tt>'''.
|}
<br />
{| border="1"
|Prototype
|'''<tt>m64p_error VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)</tt>'''
|-
|Input Parameters
@ -69,6 +85,25 @@ All of these functions should only be called from within the video plugin; they
<br />
{| border="1"
|Prototype
|'''<tt>m64p_error VidExt_SetVideoModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)</tt>'''
|-
|Input Parameters
|'''<tt>Width</tt>''' Horizontal resolution in pixels of desired video window<br />
'''<tt>Height</tt>''' Vertical resolution in pixels of desired video window<br />
'''<tt>RefreshRate</tt>''' Fullscreen refresh rate<br />
'''<tt>BitsPerPixel</tt>''' Pixel color resolution of desired video window. This value must be 16, 24, or 32<br />
'''<tt>ScreenMode</tt>''' Either <tt>M64VIDEO_WINDOWED</tt> or <tt>M64VIDEO_FULLSCREEN</tt><br />
'''<tt>Flags</tt>''' Logical-OR combination of flags which describes the video plugin's capabilities.
|-
|Requirements
|The video extension must be initialized before calling this function.
|-
|Usage
|This function creates a rendering window or switches into a fullscreen video mode. Any desired OpenGL attributes should be set before calling this function.
|}
<br />
{| border="1"
|Prototype
|'''<tt>m64p_error VidExt_SetCaption(const char *Title)</tt>'''
|-
|Input Parameters

View file

@ -69,9 +69,11 @@ VidExt_GL_GetAttribute;
VidExt_GL_SwapBuffers;
VidExt_Init;
VidExt_ListFullscreenModes;
VidExt_ListFullscreenRates;
VidExt_Quit;
VidExt_SetCaption;
VidExt_SetVideoMode;
VidExt_SetVideoModeWithRate;
VidExt_ToggleFullScreen;
VidExt_ResizeWindow;
VidExt_GL_GetDefaultFramebuffer;

View file

@ -400,7 +400,9 @@ typedef struct {
m64p_error (*VidExtFuncInit)(void);
m64p_error (*VidExtFuncQuit)(void);
m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *);
m64p_error (*VidExtFuncListRates)(m64p_2d_size, int *, int *);
m64p_error (*VidExtFuncSetMode)(int, int, int, int, int);
m64p_error (*VidExtFuncSetModeWithRate)(int, int, int, int, int, int);
m64p_function (*VidExtFuncGLGetProc)(const char*);
m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int);
m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *);

View file

@ -67,6 +67,16 @@ typedef m64p_error (*ptr_VidExt_ListFullscreenModes)(m64p_2d_size *, int *);
EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *, int *);
#endif
/* VidExt_ListFullscreenRates()
*
* This function is used to enumerate the available refresh rates for a fullscreen
* video mode.
*/
typedef m64p_error (*ptr_VidExt_ListFullscreenRates)(m64p_2d_size, int *, int *);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_ListFullscreenRates(m64p_2d_size, int *, int *);
#endif
/* VidExt_SetVideoMode()
*
* This function creates a rendering window or switches into a fullscreen
@ -78,6 +88,17 @@ typedef m64p_error (*ptr_VidExt_SetVideoMode)(int, int, int, m64p_video_mode, m6
EXPORT m64p_error CALL VidExt_SetVideoMode(int, int, int, m64p_video_mode, m64p_video_flags);
#endif
/* VidExt_SetVideoModeWithRate()
*
* This function creates a rendering window or switches into a fullscreen
* video mode. Any desired OpenGL attributes should be set before calling
* this function.
*/
typedef m64p_error (*ptr_VidExt_SetVideoModeWithRate)(int, int, int, int, m64p_video_mode, m64p_video_flags);
#if defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL VidExt_SetVideoModeWithRate(int, int, int, int, m64p_video_mode, m64p_video_flags);
#endif
/* VidExt_ResizeWindow()
*
* This function resizes the opengl rendering window to match the given size.

View file

@ -43,7 +43,7 @@
#endif
/* local variables */
static m64p_video_extension_functions l_ExternalVideoFuncTable = {12, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static m64p_video_extension_functions l_ExternalVideoFuncTable = {14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static int l_VideoExtensionActive = 0;
static int l_VideoOutputActive = 0;
static int l_Fullscreen = 0;
@ -56,14 +56,16 @@ m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionS
/* check input data */
if (VideoFunctionStruct == NULL)
return M64ERR_INPUT_ASSERT;
if (VideoFunctionStruct->Functions < 12)
if (VideoFunctionStruct->Functions < 14)
return M64ERR_INPUT_INVALID;
/* disable video extension if any of the function pointers are NULL */
if (VideoFunctionStruct->VidExtFuncInit == NULL ||
VideoFunctionStruct->VidExtFuncQuit == NULL ||
VideoFunctionStruct->VidExtFuncListModes == NULL ||
VideoFunctionStruct->VidExtFuncListRates == NULL ||
VideoFunctionStruct->VidExtFuncSetMode == NULL ||
VideoFunctionStruct->VidExtFuncSetModeWithRate == NULL ||
VideoFunctionStruct->VidExtFuncGLGetProc == NULL ||
VideoFunctionStruct->VidExtFuncGLSetAttr == NULL ||
VideoFunctionStruct->VidExtFuncGLGetAttr == NULL ||
@ -73,8 +75,8 @@ m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionS
VideoFunctionStruct->VidExtFuncResizeWindow == NULL ||
VideoFunctionStruct->VidExtFuncGLGetDefaultFramebuffer == NULL)
{
l_ExternalVideoFuncTable.Functions = 12;
memset(&l_ExternalVideoFuncTable.VidExtFuncInit, 0, 12 * sizeof(void *));
l_ExternalVideoFuncTable.Functions = 14;
memset(&l_ExternalVideoFuncTable.VidExtFuncInit, 0, 14 * sizeof(void *));
l_VideoExtensionActive = 0;
return M64ERR_SUCCESS;
}
@ -196,6 +198,53 @@ EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *SizeArray, int *
return M64ERR_SUCCESS;
}
EXPORT m64p_error CALL VidExt_ListFullscreenRates(m64p_2d_size Size, int *NumRates, int *Rates)
{
/* call video extension override if necessary */
if (l_VideoExtensionActive)
return (*l_ExternalVideoFuncTable.VidExtFuncListRates)(Size, NumRates, Rates);
#if SDL_VERSION_ATLEAST(2,0,0)
if (!SDL_WasInit(SDL_INIT_VIDEO))
return M64ERR_NOT_INIT;
int display = GetVideoDisplay();
int modeCount = SDL_GetNumDisplayModes(display);
SDL_DisplayMode displayMode;
if (modeCount < 1)
{
DebugMessage(M64MSG_ERROR, "SDL_GetNumDisplayModes failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
int rateCount = 0;
for (int i = 0; (i < modeCount) && (rateCount < *NumRates); i++)
{
if (SDL_GetDisplayMode(display, i, &displayMode) < 0)
{
DebugMessage(M64MSG_ERROR, "SDL_GetDisplayMode failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
/* skip when we're not at the right resolution */
if (displayMode.w != Size.uiWidth ||
displayMode.h != Size.uiHeight)
continue;
Rates[rateCount] = displayMode.refresh_rate;
rateCount++;
}
*NumRates = rateCount;
return M64ERR_SUCCESS;
#else
// SDL1 doesn't support getting refresh rates
return M64ERR_UNSUPPORTED;
#endif
}
EXPORT m64p_error CALL VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)
{
const SDL_VideoInfo *videoInfo;
@ -275,6 +324,106 @@ EXPORT m64p_error CALL VidExt_SetVideoMode(int Width, int Height, int BitsPerPix
return M64ERR_SUCCESS;
}
EXPORT m64p_error CALL VidExt_SetVideoModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)
{
/* call video extension override if necessary */
if (l_VideoExtensionActive)
{
m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncSetModeWithRate)(Width, Height, RefreshRate, BitsPerPixel, ScreenMode, Flags);
l_Fullscreen = (rval == M64ERR_SUCCESS && ScreenMode == M64VIDEO_FULLSCREEN);
l_VideoOutputActive = (rval == M64ERR_SUCCESS);
if (l_VideoOutputActive)
{
StateChanged(M64CORE_VIDEO_MODE, ScreenMode);
StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
}
return rval;
}
#if SDL_VERSION_ATLEAST(2,0,0)
if (!SDL_WasInit(SDL_INIT_VIDEO) || !SDL_VideoWindow)
return M64ERR_NOT_INIT;
int videoFlags = 0;
int display = GetVideoDisplay();
int modeCount = SDL_GetNumDisplayModes(display);
SDL_DisplayMode displayMode;
int modeFound = 0;
/* Get SDL video flags to use */
if (ScreenMode == M64VIDEO_WINDOWED)
videoFlags = 0;
else if (ScreenMode == M64VIDEO_FULLSCREEN)
videoFlags = SDL_WINDOW_FULLSCREEN;
else
return M64ERR_INPUT_INVALID;
if (modeCount < 1)
{
DebugMessage(M64MSG_ERROR, "SDL_GetNumDisplayModes failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
/* Attempt to find valid screen mode */
for (int i = 0; i < modeCount; i++)
{
if (SDL_GetDisplayMode(display, i, &displayMode) < 0)
{
DebugMessage(M64MSG_ERROR, "SDL_GetDisplayMode failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
/* skip when we're not at the right mode */
if (displayMode.w != Width ||
displayMode.h != Height ||
displayMode.refresh_rate != RefreshRate)
continue;
modeFound = 1;
break;
}
/* return when no modes with specifed size have been found */
if (modeFound == 0)
return M64ERR_INPUT_INVALID;
/* Set window in specified mode */
if (SDL_SetWindowFullscreen(SDL_VideoWindow, videoFlags) < 0)
{
DebugMessage(M64MSG_ERROR, "SDL_SetWindowFullscreen failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
if (ScreenMode == M64VIDEO_FULLSCREEN)
{
if (SDL_SetWindowDisplayMode(SDL_VideoWindow, &displayMode) < 0)
{
DebugMessage(M64MSG_ERROR, "SDL_SetWindowDisplayMode failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
}
SDL_ShowCursor(SDL_DISABLE);
/* set swap interval/VSync */
if (SDL_GL_SetSwapInterval(l_SwapControl) != 0)
{
DebugMessage(M64MSG_ERROR, "SDL swap interval (VSync) set failed: %s", SDL_GetError());
return M64ERR_SYSTEM_FAIL;
}
l_Fullscreen = (ScreenMode == M64VIDEO_FULLSCREEN);
l_VideoOutputActive = 1;
StateChanged(M64CORE_VIDEO_MODE, ScreenMode);
StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height);
return M64ERR_SUCCESS;
#else
// SDL1 doesn't support setting refresh rates
return M64ERR_UNSUPPORTED;
#endif
}
EXPORT m64p_error CALL VidExt_ResizeWindow(int Width, int Height)
{
const SDL_VideoInfo *videoInfo;

View file

@ -30,7 +30,7 @@
#define FRONTEND_API_VERSION 0x020102
#define CONFIG_API_VERSION 0x020301
#define DEBUG_API_VERSION 0x020001
#define VIDEXT_API_VERSION 0x030100
#define VIDEXT_API_VERSION 0x030200
#define NETPLAY_API_VERSION 0x010000
#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)