Made video mode retrieval dynamic.

This commit is contained in:
Camilla Berglund 2012-08-02 18:03:43 +02:00
parent 957ecdc9a0
commit 871e1a70d7
9 changed files with 201 additions and 193 deletions

View File

@ -520,7 +520,7 @@ GLFWAPI const char* glfwErrorString(int error);
GLFWAPI void glfwSetErrorCallback(GLFWerrorfun cbfun);
/* Video mode functions */
GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount);
GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count);
GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode);
/* Gamma ramp functions */

View File

@ -294,6 +294,7 @@ version of GLFW.</p>
<li>Changed buffer bit depth parameters of <code>glfwOpenWindow</code> to window hints</li>
<li>Changed <code>glfwOpenWindow</code> and <code>glfwSetWindowTitle</code> to use UTF-8 encoded strings</li>
<li>Changed <code>glfwGetProcAddress</code> to return a (generic) function pointer</li>
<li>Changed <code>glfwGetVideoModes</code> to return a dynamic, unlimited number of video modes</li>
<li>Renamed <code>glfw.h</code> to <code>glfw3.h</code> to avoid conflicts with 2.x series</li>
<li>Renamed <code>GLFW_WINDOW</code> token to <code>GLFW_WINDOWED</code></li>
<li>Renamed <code>GLFW_WINDOW_NO_RESIZE</code> to <code>GLFW_WINDOW_RESIZABLE</code></li>

View File

@ -197,25 +197,31 @@ void _glfwRestoreVideoMode(void)
// Get a list of available video modes
//========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount)
GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{
CGDisplayModeRef mode;
CFArrayRef modes;
CFIndex count, i;
int stored = 0;
GLFWvidmode* result;
modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL);
count = CFArrayGetCount(modes);
for (i = 0; i < count && stored < maxcount; i++)
result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * count);
for (i = 0; i < count; i++)
{
CGDisplayModeRef mode;
mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (modeIsGood(mode))
list[stored++] = vidmodeFromCGDisplayMode(mode);
{
result[*found] vidmodeFromCGDisplayMode(mode);
(*found)++;
}
}
CFRelease(modes);
return stored;
return result;
}

View File

@ -68,6 +68,16 @@ static int compareVideoModes(const void* firstPtr, const void* secondPtr)
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
//========================================================================
// Lexical comparison of GLFW video modes
//========================================================================
int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second)
{
return compareVideoModes(first, second);
}
//========================================================================
// Convert BPP to RGB bits based on "best guess"
//========================================================================
@ -100,36 +110,27 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
// Get a list of available video modes
//========================================================================
GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount)
GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count)
{
int count;
if (!_glfwInitialized)
{
_glfwSetError(GLFW_NOT_INITIALIZED, NULL);
return 0;
return NULL;
}
if (maxcount <= 0)
if (count == NULL)
{
_glfwSetError(GLFW_INVALID_VALUE,
"glfwGetVideoModes: Parameter 'maxcount' must be "
"greater than zero");
return 0;
_glfwSetError(GLFW_INVALID_VALUE, NULL);
return NULL;
}
if (list == NULL)
{
_glfwSetError(GLFW_INVALID_VALUE,
"glfwGetVideoModes: Parameter 'list' cannot be NULL");
return 0;
}
free(_glfwLibrary.modes);
count = _glfwPlatformGetVideoModes(list, maxcount);
if (count > 0)
qsort(list, count, sizeof(GLFWvidmode), compareVideoModes);
_glfwLibrary.modes = _glfwPlatformGetVideoModes(count);
if (_glfwLibrary.modes)
qsort(_glfwLibrary.modes, *count, sizeof(GLFWvidmode), compareVideoModes);
return count;
return _glfwLibrary.modes;
}

View File

@ -84,6 +84,9 @@ GLFWAPI void glfwTerminate(void)
if (!_glfwPlatformTerminate())
return;
if (_glfwLibrary.modes)
free(_glfwLibrary.modes);
_glfwInitialized = GL_FALSE;
}

View File

@ -251,6 +251,8 @@ struct _GLFWlibrary
int originalRampSize;
GLboolean rampChanged;
GLFWvidmode* modes;
// This is defined in the current port's platform.h
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
_GLFW_PLATFORM_LIBRARY_OPENGL_STATE;
@ -287,7 +289,7 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y);
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
// Fullscreen
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount);
GLFWvidmode* _glfwPlatformGetVideoModes(int* count);
void _glfwPlatformGetDesktopMode(GLFWvidmode* mode);
// Gamma ramp
@ -335,6 +337,7 @@ void _glfwPlatformCopyContext(_GLFWwindow* src, _GLFWwindow* dst, unsigned long
//========================================================================
// Fullscren management (fullscreen.c)
int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second);
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
// Error handling (error.c)

View File

@ -182,71 +182,78 @@ void _glfwRestoreVideoMode(void)
// Get a list of available video modes
//========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount)
GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{
int count, success, mode, i, j;
int m1, m2, bpp, r, g, b;
DEVMODE dm;
int dmIndex = 0, count = 0;
GLFWvidmode* result = NULL;
// Loop through all video modes and extract all the UNIQUE modes
count = 0;
mode = 0;
*found = 0;
do
for (;;)
{
// Get video mode properties
int i;
GLFWvidmode mode;
DEVMODE dm;
ZeroMemory(&dm, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE);
success = EnumDisplaySettings(NULL, mode, &dm);
// Is it a valid mode? (only list depths >= 15 bpp)
if (success && dm.dmBitsPerPel >= 15)
if (!EnumDisplaySettings(NULL, dmIndex, &dm))
break;
dmIndex++;
if (dm.dmBitsPerPel < 15)
{
// Convert to RGB, and back to bpp ("mask out" alpha bits etc)
_glfwSplitBPP(dm.dmBitsPerPel, &r, &g, &b);
bpp = r + g + b;
// Mode "code" for this mode
m1 = (bpp << 25) | (dm.dmPelsWidth * dm.dmPelsHeight);
// Insert mode in list (sorted), and avoid duplicates
for (i = 0; i < count; i++)
{
// Mode "code" for already listed mode
bpp = list[i].redBits + list[i].greenBits + list[i].blueBits;
m2 = (bpp << 25) | (list[i].width * list[i].height);
if (m1 <= m2)
break;
}
// New entry at the end of the list?
if (i >= count)
{
list[count].width = dm.dmPelsWidth;
list[count].height = dm.dmPelsHeight;
list[count].redBits = r;
list[count].greenBits = g;
list[count].blueBits = b;
count ++;
}
// Insert new entry in the list?
else if (m1 < m2)
{
for (j = count; j > i; j--)
list[j] = list[j - 1];
list[i].width = dm.dmPelsWidth;
list[i].height = dm.dmPelsHeight;
list[i].redBits = r;
list[i].greenBits = g;
list[i].blueBits = b;
count++;
}
// Skip modes with less than 15 BPP
continue;
}
mode++;
}
while (success && (count < maxcount));
return count;
mode.width = dm.dmPelsWidth;
mode.height = dm.dmPelsHeight;
_glfwSplitBPP(dm.dmBitsPerPel,
&mode.redBits,
&mode.greenBits,
&mode.blueBits);
for (i = 0; i < *found; i++)
{
if (_glfwCompareVideoModes(result + i, &mode) == 0)
break;
}
if (i < *found)
{
// This is a duplicate, so skip it
continue;
}
if (*found == count)
{
void* larger;
if (count)
count *= 2;
else
count = 128;
larger = realloc(result, count * sizeof(GLFWvidmode));
if (!larger)
{
free(result);
_glfwSetError(GLFW_OUT_OF_MEMORY, NULL);
return NULL;
}
result = (GLFWvidmode*) larger;
}
result[*found] = mode;
(*found)++;
}
return result;
}

View File

@ -32,6 +32,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
//////////////////////////////////////////////////////////////////////////
@ -325,92 +326,94 @@ void _glfwRestoreVideoMode(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
struct _glfwResolution
typedef struct
{
int width;
int height;
};
} _GLFWvidsize;
//========================================================================
// List available video modes
//========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount)
GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{
int count, k, l, r, g, b, rgba, gl;
int depth;
XVisualInfo* vislist;
XVisualInfo* visuals;
XVisualInfo dummy;
int viscount, rgbcount, rescount;
int* rgbarray;
struct _glfwResolution* resarray;
int i, j, visualCount, sizeCount, rgbCount;
int* rgbs;
_GLFWvidsize* sizes;
GLFWvidmode* result;
// Get list of visuals
vislist = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &viscount);
if (vislist == NULL)
visuals = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &visualCount);
if (visuals == NULL)
{
_glfwSetError(GLFW_PLATFORM_ERROR,
"X11/GLX: Failed to retrieve the available visuals");
return 0;
}
rgbarray = (int*) malloc(sizeof(int) * viscount);
rgbcount = 0;
// Build array of available RGB channel depths
// Build RGB array
for (k = 0; k < viscount; k++)
rgbs = (int*) malloc(sizeof(int) * visualCount);
rgbCount = 0;
for (i = 0; i < visualCount; i++)
{
// Does the visual support OpenGL & true color?
glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_USE_GL, &gl);
glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_RGBA, &rgba);
if (gl && rgba)
int gl, rgba, rgb, r, g, b;
glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_USE_GL, &gl);
glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_RGBA, &rgba);
if (!gl || !rgba)
{
// Get color depth for this visual
depth = vislist[k].depth;
// Convert to RGB
_glfwSplitBPP(depth, &r, &g, &b);
depth = (r << 16) | (g << 8) | b;
// Is this mode unique?
for (l = 0; l < rgbcount; l++)
{
if (depth == rgbarray[l])
break;
}
if (l >= rgbcount)
{
rgbarray[rgbcount] = depth;
rgbcount++;
}
// The visual lacks OpenGL or true color, so skip it
continue;
}
// Convert to RGB channel depths and encode
_glfwSplitBPP(visuals[i].depth, &r, &g, &b);
rgb = (r << 16) | (g << 8) | b;
for (j = 0; j < rgbCount; j++)
{
if (rgbs[j] == rgb)
break;
}
if (j < rgbCount)
{
// This channel depth is a duplicate, so skip it
continue;
}
rgbs[rgbCount] = rgb;
rgbCount++;
}
XFree(vislist);
XFree(visuals);
rescount = 0;
resarray = NULL;
sizeCount = 0;
sizes = NULL;
// Build resolution array
// Build array of available resolutions
if (_glfwLibrary.X11.RandR.available)
{
#if defined(_GLFW_HAS_XRANDR)
XRRScreenConfiguration* sc;
XRRScreenSize* sizelist;
int sizecount;
XRRScreenSize* rrSizes;
sc = XRRGetScreenInfo(_glfwLibrary.X11.display, _glfwLibrary.X11.root);
sizelist = XRRConfigSizes(sc, &sizecount);
rrSizes = XRRConfigSizes(sc, &sizeCount);
resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * sizecount);
sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * sizeCount);
for (k = 0; k < sizecount; k++)
for (i = 0; i < sizeCount; i++)
{
resarray[rescount].width = sizelist[k].width;
resarray[rescount].height = sizelist[k].height;
rescount++;
sizes[i].width = rrSizes[i].width;
sizes[i].height = rrSizes[i].height;
}
XRRFreeScreenConfigInfo(sc);
@ -419,69 +422,75 @@ int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount)
else if (_glfwLibrary.X11.VidMode.available)
{
#if defined(_GLFW_HAS_XF86VIDMODE)
XF86VidModeModeInfo** modelist;
int modecount, width, height;
XF86VidModeModeInfo** modes;
int modeCount;
XF86VidModeGetAllModeLines(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen,
&modecount, &modelist);
&modeCount, &modes);
resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * modecount);
sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * modeCount);
for (k = 0; k < modecount; k++)
for (i = 0; i < modeCount; i++)
{
width = modelist[k]->hdisplay;
height = modelist[k]->vdisplay;
_GLFWvidsize size;
size.width = modes[i]->hdisplay;
size.height = modes[i]->vdisplay;
// Is this mode unique?
for (l = 0; l < rescount; l++)
for (j = 0; j < sizeCount; j++)
{
if (width == resarray[l].width && height == resarray[l].height)
if (memcmp(sizes + j, &size, sizeof(_GLFWvidsize)) == 0)
break;
}
if (l >= rescount)
if (j < sizeCount)
{
resarray[rescount].width = width;
resarray[rescount].height = height;
rescount++;
// This size is a duplicate, so skip it
continue;
}
sizes[sizeCount] = size;
sizeCount++;
}
XFree(modelist);
XFree(modes);
#endif /*_GLFW_HAS_XF86VIDMODE*/
}
if (!resarray)
if (!sizeCount)
{
rescount = 1;
resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * rescount);
sizeCount = 1;
sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize));
resarray[0].width = DisplayWidth(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen);
resarray[0].height = DisplayHeight(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen);
sizes[0].width = DisplayWidth(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen);
sizes[0].height = DisplayHeight(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen);
}
// Build permutations of colors and resolutions
count = 0;
for (k = 0; k < rgbcount && count < maxcount; k++)
// Build all permutations of channel depths and resolutions
result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * rgbCount * sizeCount);
*found = 0;
for (i = 0; i < rgbCount; i++)
{
for (l = 0; l < rescount && count < maxcount; l++)
for (j = 0; j < sizeCount; j++)
{
list[count].width = resarray[l].width;
list[count].height = resarray[l].height;
list[count].redBits = (rgbarray[k] >> 16) & 255;
list[count].greenBits = (rgbarray[k] >> 8) & 255;
list[count].blueBits = rgbarray[k] & 255;
count++;
result[*found].width = sizes[j].width;
result[*found].height = sizes[j].height;
result[*found].redBits = (rgbs[i] >> 16) & 255;
result[*found].greenBits = (rgbs[i] >> 8) & 255;
result[*found].blueBits = rgbs[i] & 255;
(*found)++;
}
}
free(resarray);
free(rgbarray);
free(sizes);
free(rgbs);
return count;
return result;
}

View File

@ -90,29 +90,11 @@ static void key_callback(GLFWwindow dummy, int key, int action)
}
}
static GLFWvidmode* get_video_modes(size_t* found)
{
size_t count = 0;
GLFWvidmode* modes = NULL;
for (;;)
{
count += 256;
modes = realloc(modes, sizeof(GLFWvidmode) * count);
*found = glfwGetVideoModes(modes, count);
if (*found < count)
break;
}
return modes;
}
static void list_modes(void)
{
size_t count, i;
GLFWvidmode desktop_mode;
GLFWvidmode* modes = get_video_modes(&count);
GLFWvidmode* modes = glfwGetVideoModes(&count);
glfwGetDesktopMode(&desktop_mode);
printf("Desktop mode: %s\n", format_mode(&desktop_mode));
@ -128,15 +110,13 @@ static void list_modes(void)
putchar('\n');
}
free(modes);
}
static void test_modes(void)
{
int width, height;
size_t i, count;
GLFWvidmode* modes = get_video_modes(&count);
GLFWvidmode* modes = glfwGetVideoModes(&count);
glfwSetWindowSizeCallback(window_size_callback);
glfwSetWindowCloseCallback(window_close_callback);
@ -207,8 +187,6 @@ static void test_modes(void)
glfwPollEvents();
window = NULL;
}
free(modes);
}
int main(int argc, char** argv)