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); GLFWAPI void glfwSetErrorCallback(GLFWerrorfun cbfun);
/* Video mode functions */ /* Video mode functions */
GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount); GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count);
GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode); GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode);
/* Gamma ramp functions */ /* 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 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>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>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.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</code> token to <code>GLFW_WINDOWED</code></li>
<li>Renamed <code>GLFW_WINDOW_NO_RESIZE</code> to <code>GLFW_WINDOW_RESIZABLE</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 // Get a list of available video modes
//======================================================================== //========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{ {
CGDisplayModeRef mode;
CFArrayRef modes; CFArrayRef modes;
CFIndex count, i; CFIndex count, i;
int stored = 0; GLFWvidmode* result;
modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL); modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL);
count = CFArrayGetCount(modes); 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); mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (modeIsGood(mode)) if (modeIsGood(mode))
list[stored++] = vidmodeFromCGDisplayMode(mode); {
result[*found] vidmodeFromCGDisplayMode(mode);
(*found)++;
}
} }
CFRelease(modes); CFRelease(modes);
return stored; return result;
} }

View File

@ -68,6 +68,16 @@ static int compareVideoModes(const void* firstPtr, const void* secondPtr)
////// GLFW internal API ////// ////// 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" // 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 // Get a list of available video modes
//======================================================================== //========================================================================
GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount) GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count)
{ {
int count;
if (!_glfwInitialized) if (!_glfwInitialized)
{ {
_glfwSetError(GLFW_NOT_INITIALIZED, NULL); _glfwSetError(GLFW_NOT_INITIALIZED, NULL);
return 0; return NULL;
} }
if (maxcount <= 0) if (count == NULL)
{ {
_glfwSetError(GLFW_INVALID_VALUE, _glfwSetError(GLFW_INVALID_VALUE, NULL);
"glfwGetVideoModes: Parameter 'maxcount' must be " return NULL;
"greater than zero");
return 0;
} }
if (list == NULL) free(_glfwLibrary.modes);
{
_glfwSetError(GLFW_INVALID_VALUE,
"glfwGetVideoModes: Parameter 'list' cannot be NULL");
return 0;
}
count = _glfwPlatformGetVideoModes(list, maxcount); _glfwLibrary.modes = _glfwPlatformGetVideoModes(count);
if (count > 0) if (_glfwLibrary.modes)
qsort(list, count, sizeof(GLFWvidmode), compareVideoModes); qsort(_glfwLibrary.modes, *count, sizeof(GLFWvidmode), compareVideoModes);
return count; return _glfwLibrary.modes;
} }

View File

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

View File

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

View File

@ -182,71 +182,78 @@ void _glfwRestoreVideoMode(void)
// Get a list of available video modes // Get a list of available video modes
//======================================================================== //========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{ {
int count, success, mode, i, j; int dmIndex = 0, count = 0;
int m1, m2, bpp, r, g, b; GLFWvidmode* result = NULL;
DEVMODE dm;
// Loop through all video modes and extract all the UNIQUE modes *found = 0;
count = 0;
mode = 0;
do for (;;)
{ {
// Get video mode properties int i;
GLFWvidmode mode;
DEVMODE dm;
ZeroMemory(&dm, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE); dm.dmSize = sizeof(DEVMODE);
success = EnumDisplaySettings(NULL, mode, &dm);
// Is it a valid mode? (only list depths >= 15 bpp) if (!EnumDisplaySettings(NULL, dmIndex, &dm))
if (success && dm.dmBitsPerPel >= 15) break;
dmIndex++;
if (dm.dmBitsPerPel < 15)
{ {
// Convert to RGB, and back to bpp ("mask out" alpha bits etc) // Skip modes with less than 15 BPP
_glfwSplitBPP(dm.dmBitsPerPel, &r, &g, &b); continue;
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++;
}
} }
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 <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -325,92 +326,94 @@ void _glfwRestoreVideoMode(void)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct _glfwResolution typedef struct
{ {
int width; int width;
int height; int height;
}; } _GLFWvidsize;
//======================================================================== //========================================================================
// List available video modes // List available video modes
//======================================================================== //========================================================================
int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) GLFWvidmode* _glfwPlatformGetVideoModes(int* found)
{ {
int count, k, l, r, g, b, rgba, gl; XVisualInfo* visuals;
int depth;
XVisualInfo* vislist;
XVisualInfo dummy; XVisualInfo dummy;
int viscount, rgbcount, rescount; int i, j, visualCount, sizeCount, rgbCount;
int* rgbarray; int* rgbs;
struct _glfwResolution* resarray; _GLFWvidsize* sizes;
GLFWvidmode* result;
// Get list of visuals visuals = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &visualCount);
vislist = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &viscount); if (visuals == NULL)
if (vislist == NULL)
{ {
_glfwSetError(GLFW_PLATFORM_ERROR, _glfwSetError(GLFW_PLATFORM_ERROR,
"X11/GLX: Failed to retrieve the available visuals"); "X11/GLX: Failed to retrieve the available visuals");
return 0; return 0;
} }
rgbarray = (int*) malloc(sizeof(int) * viscount); // Build array of available RGB channel depths
rgbcount = 0;
// Build RGB array rgbs = (int*) malloc(sizeof(int) * visualCount);
for (k = 0; k < viscount; k++) rgbCount = 0;
for (i = 0; i < visualCount; i++)
{ {
// Does the visual support OpenGL & true color? int gl, rgba, rgb, r, g, b;
glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_USE_GL, &gl);
glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_RGBA, &rgba); glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_USE_GL, &gl);
if (gl && rgba) glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_RGBA, &rgba);
if (!gl || !rgba)
{ {
// Get color depth for this visual // The visual lacks OpenGL or true color, so skip it
depth = vislist[k].depth; continue;
// 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++;
}
} }
// 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; sizeCount = 0;
resarray = NULL; sizes = NULL;
// Build resolution array // Build array of available resolutions
if (_glfwLibrary.X11.RandR.available) if (_glfwLibrary.X11.RandR.available)
{ {
#if defined(_GLFW_HAS_XRANDR) #if defined(_GLFW_HAS_XRANDR)
XRRScreenConfiguration* sc; XRRScreenConfiguration* sc;
XRRScreenSize* sizelist; XRRScreenSize* rrSizes;
int sizecount;
sc = XRRGetScreenInfo(_glfwLibrary.X11.display, _glfwLibrary.X11.root); 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; sizes[i].width = rrSizes[i].width;
resarray[rescount].height = sizelist[k].height; sizes[i].height = rrSizes[i].height;
rescount++;
} }
XRRFreeScreenConfigInfo(sc); XRRFreeScreenConfigInfo(sc);
@ -419,69 +422,75 @@ int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount)
else if (_glfwLibrary.X11.VidMode.available) else if (_glfwLibrary.X11.VidMode.available)
{ {
#if defined(_GLFW_HAS_XF86VIDMODE) #if defined(_GLFW_HAS_XF86VIDMODE)
XF86VidModeModeInfo** modelist; XF86VidModeModeInfo** modes;
int modecount, width, height; int modeCount;
XF86VidModeGetAllModeLines(_glfwLibrary.X11.display, XF86VidModeGetAllModeLines(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen, _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; _GLFWvidsize size;
height = modelist[k]->vdisplay; size.width = modes[i]->hdisplay;
size.height = modes[i]->vdisplay;
// Is this mode unique? for (j = 0; j < sizeCount; j++)
for (l = 0; l < rescount; l++)
{ {
if (width == resarray[l].width && height == resarray[l].height) if (memcmp(sizes + j, &size, sizeof(_GLFWvidsize)) == 0)
break; break;
} }
if (l >= rescount) if (j < sizeCount)
{ {
resarray[rescount].width = width; // This size is a duplicate, so skip it
resarray[rescount].height = height; continue;
rescount++;
} }
sizes[sizeCount] = size;
sizeCount++;
} }
XFree(modelist); XFree(modes);
#endif /*_GLFW_HAS_XF86VIDMODE*/ #endif /*_GLFW_HAS_XF86VIDMODE*/
} }
if (!resarray) if (!sizeCount)
{ {
rescount = 1; sizeCount = 1;
resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * rescount); sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize));
resarray[0].width = DisplayWidth(_glfwLibrary.X11.display, sizes[0].width = DisplayWidth(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen); _glfwLibrary.X11.screen);
resarray[0].height = DisplayHeight(_glfwLibrary.X11.display, sizes[0].height = DisplayHeight(_glfwLibrary.X11.display,
_glfwLibrary.X11.screen); _glfwLibrary.X11.screen);
} }
// Build permutations of colors and resolutions // Build all permutations of channel depths and resolutions
count = 0;
for (k = 0; k < rgbcount && count < maxcount; k++) 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; result[*found].width = sizes[j].width;
list[count].height = resarray[l].height; result[*found].height = sizes[j].height;
list[count].redBits = (rgbarray[k] >> 16) & 255; result[*found].redBits = (rgbs[i] >> 16) & 255;
list[count].greenBits = (rgbarray[k] >> 8) & 255; result[*found].greenBits = (rgbs[i] >> 8) & 255;
list[count].blueBits = rgbarray[k] & 255; result[*found].blueBits = rgbs[i] & 255;
count++;
(*found)++;
} }
} }
free(resarray); free(sizes);
free(rgbarray); 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) static void list_modes(void)
{ {
size_t count, i; size_t count, i;
GLFWvidmode desktop_mode; GLFWvidmode desktop_mode;
GLFWvidmode* modes = get_video_modes(&count); GLFWvidmode* modes = glfwGetVideoModes(&count);
glfwGetDesktopMode(&desktop_mode); glfwGetDesktopMode(&desktop_mode);
printf("Desktop mode: %s\n", format_mode(&desktop_mode)); printf("Desktop mode: %s\n", format_mode(&desktop_mode));
@ -128,15 +110,13 @@ static void list_modes(void)
putchar('\n'); putchar('\n');
} }
free(modes);
} }
static void test_modes(void) static void test_modes(void)
{ {
int width, height; int width, height;
size_t i, count; size_t i, count;
GLFWvidmode* modes = get_video_modes(&count); GLFWvidmode* modes = glfwGetVideoModes(&count);
glfwSetWindowSizeCallback(window_size_callback); glfwSetWindowSizeCallback(window_size_callback);
glfwSetWindowCloseCallback(window_close_callback); glfwSetWindowCloseCallback(window_close_callback);
@ -207,8 +187,6 @@ static void test_modes(void)
glfwPollEvents(); glfwPollEvents();
window = NULL; window = NULL;
} }
free(modes);
} }
int main(int argc, char** argv) int main(int argc, char** argv)