Getting Monitor's supported resolutions

Does Panda offer any access to hardware info. Specifically whether a given resolution is supported by the monitor?

Can’t find anything in the documentation about this - hopefully I didn’t miss anything. I’m hoping to avoid having to dig into the win32 api.

Thanks!

Sure does. Take a look at the GraphicsPipe class API reference:
panda3d.org/apiref.php?page=GraphicsPipe
You can get an instance of that by simply accessing ‘base.pipe’, once the window has been opened (meaning, DirectStart imported).

Using base.pipe.getDisplayInformation(), which returns a DisplayInformation object, you can query all the supported resolutions and more CPU info.

Sometimes you would want to query this information before opening the window. So, I don’t import DirectStart, but instead, do this:

from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "window-type none")
from direct.showbase.ShowBase import ShowBase

Then, when I want to initialize “base” and query the resolutions, I do something like this:

ShowBase()
base.makeDefaultPipe()
di = base.pipe.getDisplayInformation()
winProps = WindowProperties()
winProps.setFullscreen(True)

sizes = []

for index in range(di.getTotalDisplayModes()):
  sizes += (di.getDisplayModeWidth(index), di.getDisplayModeHeight(index))

# This just chooses the first resolution that the OS reports, but
#   you probably want something smarter than this.
# I catch this with an 'if' because some OS'es might
#   not report any resolutions.
if (len(sizes) > 0):
  size = sizes[0]
  winProps.setSize(*size)

# Finally! Open that window.
base.openDefaultWindow(props = winProps)

genius - thanks!

hrm - apparently unavailable in 1.3.2 - le sigh

Really, 1.3.2? Wow, that’s ancient. Is there a particular reason why you’re not using 1.6.2?

haha yep - 140k lines of reasons actually =(

So no dice on this function call. I am pretty much stuck with digging through python win32 stuff then? I doubt that the python layer has access to the directx object which would also give me this kind of information…

Have you actually tried upgrading?

Assuming you haven’t heavily modified Panda itself, I think there’s every reason to believe an upgrade would be smooth, even with 140k lines of code. After all, Disney keeps both of its own MMO’s, as big as they are (and they are big), on the leading edge of Panda development without too much effort. There are lots of good reasons for you to do the same; Panda has come pretty far in the three years since 1.3. Especially because you have a tendency to ask for features, like querying desktop properties or better memory management tools, that are available in 1.6 but lacking in 1.3.

On the other hand, if you have in fact modified Panda heavily, then I understand why an upgrade would be difficult. Not much I can do for you in this case, other than to belatedly point out the advantages to both parties for contributing modifications back to the mainline codebase as soon as possible. :slight_smile:

David

I totally second that.
If you don’t feel like upgrading all the way, the DisplayInformation functionality was new in 1.4.0. So you could always upgrade step-by-step, first to the stable release of the 1.4.x branch (which is 1.4.3).

Well, its heartening to hear that! I don’t know that it will actually happen, but the input that it should be fairly easy to do so is good to have.

Thanks for the feedback guys!

For a personal project I am messing around with 1.6.2 and OS X. This query returns 0 supported modes, but of course I can start the game in many. I’m guessing this busy work hasn’t been implemented for OSX yet? ( i assume that it has been in opengl. ) I’m digging around in the cxx files looking for where all this information is gathered up, but to be perfectly honest it is slow. Mostly because I don’t know the file structure, inheritance scheme or very much C++… anyway - any ideas where I might look if I wanted to supplement this area of the engine for OSX? Thanks in advance!

I believe this has only been done for Windows so far. (It’s not related to OpenGL; OpenGL doesn’t have interfaces for this kind of stuff. It has to be queried directly from the operating system.)

This has to be implemented by the GraphicsPipe constructor for the particular interface. In the case of Windows, it is implemented by the WinGraphicsPipe constructor, from which all of the DirectX/OpenGL GraphicsPipes inherit from on Windows. On OSX, there is only the osxGraphicsPipe, which is defined in panda/src/osxdisplay/osxGraphicsPipe.cxx.

The information needs to be placed in the pipe’s _display_information member.

David

It would be great if this could be done, because this is one of those points where Panda doesn’t work the same way on all platforms.
For the linux+freebsd case, a bug report is pending with Xrandr support, which I’ll probably implement sooner or later if nobody else beats me to it.

So if you’d like to volunteer to implement the OSX DisplayInformation stuff, that would be very much appreciated!

I am 90% of the way there, but to be honest I haven’t looked at C/C++ in a long time so it is slow… and I work on this about once a week.

Anyway, I have all the display modes gathered up in the displaymode struct array and I can access/print them fine from the C++ side of things, but I must be doing something wrong.

Here is a print out ( the modes are constrained to non-stretching, hardware safe, same bit depth or greater options )

C++ value prints:
Number of displaymodes returned: 7
640 x 480 x 32
800 x 500 x 32
800 x 600 x 32
1024 x 640 x 32
1024 x 768 x 32
1152 x 720 x 32
1280 x 800 x 32

python value prints ( excludes the bit depth ):
157 480
102926748 -1073746920
103792768 1292873
1687965 -1073745860
2021152 2016800
-1073745784 -1073746712
2035488 1618509

my C++ code:

number = CFArrayGetCount( displayModeArray );
printf( “Number of displaymodes returned: %d\n”, number );
DisplayMode displays[ number ];

for(i = 0; i < number; i++) {

	displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i);
	_display_information -> _total_display_modes++;
	
	displays[i].width = (int)GetModeWidth (displayMode);
	displays[i].height = (int)GetModeHeight (displayMode);
	displays[i].bits_per_pixel = (int)GetModeBitsPerPixel (displayMode);
	displays[i].refresh_rate = (int)GetModeRefreshRate (displayMode);
	
	printf( "%i x %i x %i\n", displays[i].width, displays[i].height, displays[i].bits_per_pixel );

}

_display_information -> _display_mode_array = displays;

the GetMode calls return a long, the displaymode struct wants an int so I cast it, but I think without that it does the same as it is cast via the assignment anyway? correct me if i am wrong.

So, I think I am missing an understanding of pointers, or something along those lines.

Thanks for any help!

My code does some culling of possible display modes - i will be happy to post it once i finish this last issue, but I am not sure that this will mimic the behavior of the windows code exactly.

DisplayMode displays[ number ];
...
_display_information -> _display_mode_array = displays; 

You are creating a local array, displays, and then assigning that local pointer into _display_information. As soon as the function returns, though, all local variables are released, including your local array; and so now _display_information holds a pointer to garbage memory.

You should allocate an array on the heap instead:

DisplayMode *displays = new DisplayMode[ number ];

David

*almost NT

I am sure there is a better way to return this info ( like a submission via cvs ) but I don’t have this setup and I will probably not work on this again for a week, so for now here is my use of someone else’s very neat code (this is osxgraphicspipe.cxx in its entirety for merging back into the base, or just reference for other osx’rs):

////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "osxGraphicsPipe.h"
#include "config_osxdisplay.h"
#include "osxGraphicsWindow.h"
#include "osxGraphicsBuffer.h"
#include "osxGraphicsStateGuardian.h"
#include "pnmImage.h"
#import <Carbon/Carbon.h>

//------------------------------------------------------------------------------------------
//	Conversion by Jim Wrenholt, Nordic Software,  June 2006
//					based on original Cocoa GameShell by Keith Bauer
//------------------------------------------------------------------------------------------
//#include "CGDirectDisplayAdditions.h"

// some macros to make code more readable.
#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
#define GetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)

#define GetModeSafeForHardware(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware)
#define GetModeStretched(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsStretched)

#define MAX_DISPLAYS 32

//------------------------------------------------------------------------------------------
Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) 
{
	// get a boolean from the dictionary
	Boolean value = false;
	CFBooleanRef boolRef;
	boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
	if (boolRef != NULL)
		value = CFBooleanGetValue(boolRef); 	
	return value;
}
//------------------------------------------------------------------------------------------
long GetDictionaryLong(CFDictionaryRef theDict, const void* key) 
{
	// get a long from the dictionary
	long value = 0;
	CFNumberRef numRef;
	numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); 
	if (numRef != NULL)
		CFNumberGetValue(numRef, kCFNumberLongType, &value); 	
	return value;
}
//------------------------------------------------------------------------------------------
static CFComparisonResult CompareModes (const void *val1,const void *val2,void *context)
{
	// CFArray comparison callback for sorting display modes.
#pragma unused(context)
	CFDictionaryRef thisMode = (CFDictionaryRef)val1;
	CFDictionaryRef otherMode = (CFDictionaryRef)val2;
	
	long width = GetModeWidth(thisMode);
	long otherWidth = GetModeWidth(otherMode);
	
	long height = GetModeHeight(thisMode);
	long otherHeight = GetModeHeight(otherMode);
	
	// sort modes in screen size order
	if (width * height < otherWidth * otherHeight)
	{
		return kCFCompareLessThan;
	}
	else if (width * height > otherWidth * otherHeight)
	{
		return kCFCompareGreaterThan;
	}
	
	// sort modes by bits per pixel
	long bitsPerPixel = GetModeBitsPerPixel(thisMode);
	long otherBitsPerPixel = GetModeBitsPerPixel(otherMode);
	
	if (bitsPerPixel < otherBitsPerPixel)
	{
		return kCFCompareLessThan;
	}
	else if (bitsPerPixel > otherBitsPerPixel)
	{
		return kCFCompareGreaterThan;
	}
	
	// sort modes by refresh rate.
	long refreshRate = GetModeRefreshRate(thisMode);
	long otherRefreshRate = GetModeRefreshRate(otherMode);
	
	if (refreshRate < otherRefreshRate)
	{
		return kCFCompareLessThan;
	}
	else if (refreshRate > otherRefreshRate)
	{
		return kCFCompareGreaterThan;
	}
	
	return kCFCompareEqualTo;
}
//------------------------------------------------------------------------------------------
CFArrayRef GSCGDisplayAvailableModesUsefulForOpenGL(CGDirectDisplayID display) 
{
	// get a list of all possible display modes for this system.
	CFArrayRef availableModes = CGDisplayAvailableModes(display);
	unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
	
	// creat mutable array to hold the display modes we are interested int.
	CFMutableArrayRef usefulModes = CFArrayCreateMutable(kCFAllocatorDefault, numberOfAvailableModes, NULL);
	
	// get the current bits per pixel.
	long currentModeBitsPerPixel = GetModeBitsPerPixel(CGDisplayCurrentMode(display));
	
	unsigned int i;
	for (i= 0; i<numberOfAvailableModes; ++i)
	{
		// look at each mode in the available list
		CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
		
		// we are only interested in modes with the same bits per pixel as current.
		//	to allow for switching from fullscreen to windowed modes.
		// that are safe for this hardward
		// that are not stretched.
		long bitsPerPixel = GetModeBitsPerPixel(mode);
		Boolean safeForHardware = GetModeSafeForHardware(mode);
		Boolean stretched = GetModeStretched(mode);
		
		if ((bitsPerPixel != currentModeBitsPerPixel) || (!safeForHardware) || (stretched))
		{
			continue; // skip this mode
		}
		
		long width = GetModeWidth(mode);
		long height = GetModeHeight(mode);
		long refreshRate = GetModeRefreshRate(mode);
		
		Boolean replaced = false;
		Boolean skipped = false;
		
		// now check to see if we already added a mode like this one.
		//	we want the highest refresh rate for this width/height
		unsigned int j;
		unsigned int currentNumberOfUsefulModes =  CFArrayGetCount(usefulModes);
		for (j = 0; j < currentNumberOfUsefulModes; ++j)
		{
			CFDictionaryRef otherMode = (CFDictionaryRef)CFArrayGetValueAtIndex(usefulModes, j);
			
			long otherWidth = GetModeWidth(otherMode);
			long otherHeight = GetModeHeight(otherMode);
			
			if ((otherWidth == width) && (otherHeight == height))
			{
				long otherRefreshRate = GetModeRefreshRate(otherMode);
				
				if (otherRefreshRate < refreshRate)
				{
					// replace lower refresh rate.
					const void* value = mode;
					CFArrayReplaceValues(usefulModes, CFRangeMake(j ,1), &value, 1);
					replaced = true;
					break;
				}
				else if (otherRefreshRate > refreshRate)
				{
					skipped = true;
					break;
				}
			}
		}
		
		// this is a useful mode so add it to the array.
		if (!replaced && !skipped)
		{
			CFArrayAppendValue(usefulModes, mode);
		}
		
	}
	
	// now sort the useful mode array, using the comparison callback.
	CFArraySortValues( usefulModes, 
					  CFRangeMake(0, CFArrayGetCount(usefulModes)), 
					  (CFComparatorFunction) CompareModes, NULL);
	
	// return the CFArray of the useful display modes.
	return usefulModes;
}

TypeHandle osxGraphicsPipe::_type_handle;
  
////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
osxGraphicsPipe::
osxGraphicsPipe() {
	
	CGDirectDisplayID display, displayArray[MAX_DISPLAYS] ;
	CGDisplayCount numDisplays;
	CFDictionaryRef displayMode;
	
	CFArrayRef displayModeArray;
	int number, i;
	
	CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays); 
	display = displayArray [numDisplays - 1]; 
	displayModeArray = GSCGDisplayAvailableModesUsefulForOpenGL( display );
	
	number = CFArrayGetCount( displayModeArray );
	//printf( "Number of displaymodes returned: %d\n", number );
	DisplayMode *displays = new DisplayMode[ number ];
	
	for(i = 0; i < number; i++) { 
		
		displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i);
		_display_information -> _total_display_modes++;
		
		displays[i].width = (signed int)GetModeWidth (displayMode);
		displays[i].height = (signed int)GetModeHeight (displayMode);
		displays[i].bits_per_pixel = (signed int)GetModeBitsPerPixel (displayMode);
		displays[i].refresh_rate = (signed int)GetModeRefreshRate (displayMode);
		
		//printf( "%i x %i x %i\n", displays[i].width, displays[i].height, displays[i].bits_per_pixel );
	
	}
	
	_display_information -> _display_mode_array = displays;
	
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::Destructor
//       Access: Public, Virtual
//  Description: 
////////////////////////////////////////////////////////////////////
osxGraphicsPipe::
~osxGraphicsPipe() {
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::get_interface_name
//       Access: Published, Virtual
//  Description: Returns the name of the rendering interface
//               associated with this GraphicsPipe.  This is used to
//               present to the user to allow him/her to choose
//               between several possible GraphicsPipes available on a
//               particular platform, so the name should be meaningful
//               and unique for a given platform.
////////////////////////////////////////////////////////////////////
string osxGraphicsPipe::
get_interface_name() const {
  return "OpenGL";
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::pipe_constructor
//       Access: Public, Static
//  Description: This function is passed to the GraphicsPipeSelection
//               object to allow the user to make a default
//               osxGraphicsPipe.
////////////////////////////////////////////////////////////////////
PT(GraphicsPipe) osxGraphicsPipe::
pipe_constructor() {
  return new osxGraphicsPipe;
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::get_preferred_window_thread
//       Access: Public, Virtual
//  Description: Returns an indication of the thread in which this
//               GraphicsPipe requires its window processing to be
//               performed: typically either the app thread (e.g. X)
//               or the draw thread (Windows).
////////////////////////////////////////////////////////////////////
GraphicsPipe::PreferredWindowThread 
osxGraphicsPipe::get_preferred_window_thread() const {
  return PWT_app;
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::create_cg_image
//       Access: Public, Static
//  Description: Creates a new Quartz bitmap image with the data in
//               the indicated PNMImage.  The caller should eventually
//               free this image via CGImageRelease.
////////////////////////////////////////////////////////////////////
CGImageRef osxGraphicsPipe::
create_cg_image(const PNMImage &pnm_image) {
  size_t width = pnm_image.get_x_size();
  size_t height = pnm_image.get_y_size();

#ifdef PGM_BIGGRAYS
  size_t bytes_per_component = 2;
#else
  size_t bytes_per_component = 1;
#endif
  size_t bits_per_component = bytes_per_component * 8;
  size_t num_components = pnm_image.get_num_channels();

  size_t bits_per_pixel = num_components * bits_per_component;
  size_t bytes_per_row = num_components * bytes_per_component * width;

  size_t num_bytes = bytes_per_row * height;
  bool has_alpha;
  bool is_grayscale;

  CFStringRef color_space_name = NULL;
  switch (pnm_image.get_color_type()) {
  case PNMImage::CT_grayscale:
    color_space_name = kCGColorSpaceGenericGray;
    has_alpha = false;
    is_grayscale = true;
    break;

  case PNMImage::CT_two_channel:
    color_space_name = kCGColorSpaceGenericGray;
    has_alpha = true;
    is_grayscale = true;
    break;

  case PNMImage::CT_color:
    color_space_name = kCGColorSpaceGenericRGB;
    has_alpha = false;
    is_grayscale = false;
    break;

  case PNMImage::CT_four_channel:
    color_space_name = kCGColorSpaceGenericRGB;
    has_alpha = true;
    is_grayscale = false;
    break;

  case PNMImage::CT_invalid:
    // Shouldn't get here.
    nassertr(false, NULL);
    break;
  }
  nassertr(color_space_name != NULL, NULL);

  CGColorSpaceRef color_space = CGColorSpaceCreateWithName(color_space_name);
  nassertr(color_space != NULL, NULL);

  CGBitmapInfo bitmap_info = 0;
#ifdef PGM_BIGGRAYS
  bitmap_info |= kCGBitmapByteOrder16Host;
#endif
  if (has_alpha) {
    bitmap_info |= kCGImageAlphaLast;
  }

  // Now convert the pixel data to a format friendly to
  // CGImageCreate().
  char *char_array = (char *)PANDA_MALLOC_ARRAY(num_bytes);

  xelval *dp = (xelval *)char_array;
  for (size_t yi = 0; yi < height; ++yi) {
    for (size_t xi = 0; xi < width; ++xi) {
      if (is_grayscale) {
        *dp++ = (xelval)(pnm_image.get_gray(xi, yi) * PGM_MAXMAXVAL);
      } else {
        *dp++ = (xelval)(pnm_image.get_red(xi, yi) * PGM_MAXMAXVAL);
        *dp++ = (xelval)(pnm_image.get_green(xi, yi) * PGM_MAXMAXVAL);
        *dp++ = (xelval)(pnm_image.get_blue(xi, yi) * PGM_MAXMAXVAL);
      }
      if (has_alpha) {
        *dp++ = (xelval)(pnm_image.get_alpha(xi, yi) * PGM_MAXMAXVAL);
      }
    }
  }
  nassertr((void *)dp == (void *)(char_array + num_bytes), NULL);

  CGDataProviderRef provider = 
    CGDataProviderCreateWithData(NULL, char_array, num_bytes, release_data);
  nassertr(provider != NULL, NULL);

  CGImageRef image = CGImageCreate
    (width, height, bits_per_component, bits_per_pixel, bytes_per_row,
     color_space, bitmap_info, provider,
     NULL, false, kCGRenderingIntentDefault);
  nassertr(image != NULL, NULL);

  CGColorSpaceRelease(color_space);
  CGDataProviderRelease(provider);

  return image;
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::release_data
//       Access: Private, Static
//  Description: This callback is assigned to delete the data array
//               allocated within create_cg_image().
////////////////////////////////////////////////////////////////////
void osxGraphicsPipe::
release_data(void *info, const void *data, size_t size) {
  char *char_array = (char *)data;
  PANDA_FREE_ARRAY(char_array);
}

////////////////////////////////////////////////////////////////////
//     Function: osxGraphicsPipe::make_output
//       Access: Protected, Virtual
//  Description: Creates a new window on the pipe, if possible.
////////////////////////////////////////////////////////////////////
PT(GraphicsOutput) osxGraphicsPipe::
make_output(const string &name,
            const FrameBufferProperties &fb_prop,
            const WindowProperties &win_prop,
            int flags,
            GraphicsEngine *engine,
            GraphicsStateGuardian *gsg,
            GraphicsOutput *host,
            int retry,
            bool &precertify) {
  if (!_is_valid) {
    return NULL;
  }
  
  osxGraphicsStateGuardian *osxgsg = 0;
  if (gsg != 0) {
    DCAST_INTO_R(osxgsg, gsg, NULL);
  }
  
  // First thing to try: a osxGraphicsWindow

  if (retry == 0) {
    if (((flags&BF_require_parasite)!=0)||
        ((flags&BF_refuse_window)!=0)||
        ((flags&BF_resizeable)!=0)||
        ((flags&BF_size_track_host)!=0)||
        ((flags&BF_can_bind_color)!=0)||
        ((flags&BF_can_bind_every)!=0)) {
      return NULL;
    }
    return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop,
                                 flags, gsg, host);
  }
  
  // Second thing to try: a glGraphicsBuffer
  
  if (retry == 1) {
    if ((host==0)||
        ((flags&BF_require_parasite)!=0)||
        ((flags&BF_require_window)!=0)) {
      return NULL;
    }
    // Early failure - if we are sure that this buffer WONT
    // meet specs, we can bail out early.
    if ((flags & BF_fb_props_optional)==0) {
      if ((fb_prop.get_indexed_color() > 0)||
          (fb_prop.get_back_buffers() > 0)||
          (fb_prop.get_accum_bits() > 0)||
          (fb_prop.get_multisamples() > 0)) {
        return NULL;
      }
    }
    // Early success - if we are sure that this buffer WILL
    // meet specs, we can precertify it.
    if ((osxgsg != 0) &&
        (osxgsg->is_valid()) &&
        (!osxgsg->needs_reset()) &&
        (osxgsg->_supports_framebuffer_object) &&
        (osxgsg->_glDrawBuffers != 0)&&
        (fb_prop.is_basic())) {
      precertify = true;
    }
    return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host);
  }
  
  // Third thing to try: an osxGraphicsBuffer
  if (retry == 2) {
    if ((!support_render_texture)||
        ((flags&BF_require_parasite)!=0)||
        ((flags&BF_require_window)!=0)||
        ((flags&BF_resizeable)!=0)||
        ((flags&BF_size_track_host)!=0)||
        ((flags&BF_can_bind_every)!=0)) {
      return NULL;
    }
    return new osxGraphicsBuffer(engine, this, name, fb_prop, win_prop,
                                 flags, gsg, host);
  }

  // Nothing else left to try.
  return NULL;
}

Oh, I entirely forgot about this thread. gerakinis, could you diff it against the original file and email/post the patch somewhere?

For the record, I just implemented resolution switching support under Linux, and querying the list of supported resolutions. Will be in 1.7.0.

Hello, in the last post by gerakinis he proposed a solution for OSX. Has this solution been applied in Panda 1.7.0?

Because, if I run the following code on Windows and Linux:

import direct.directbase.DirectStart
di = base.pipe.getDisplayInformation()
sizes = []
for index in range( di.getTotalDisplayModes() ):
  sizes += [ ( di.getDisplayModeWidth( index ), di.getDisplayModeHeight( index ) ) ]
print sizes
run()

I see the expected behaviour (it prints a list with all supported resolutions), but if I run it on OSX it prints an empty list. Is that the expected behaviour (as rdb wrote, but before the gerakinis’s proposal)?

I updated the gerakinis’s patch to the current trunk. I tested it (the code that I wrote in my previous post now has the expected behaviour). I post it here (if this could be useful to someone).

Index: panda/src/osxdisplay/osxGraphicsPipe.cxx
===================================================================
RCS file: /cvsroot/panda3d/panda/src/osxdisplay/osxGraphicsPipe.cxx,v
retrieving revision 1.22
diff -u -5 -r1.22 osxGraphicsPipe.cxx
--- panda/src/osxdisplay/osxGraphicsPipe.cxx	13 Apr 2010 23:05:07 -0000	1.22
+++ panda/src/osxdisplay/osxGraphicsPipe.cxx	19 Jul 2010 10:19:35 -0000
@@ -15,10 +15,149 @@
 #include "osxGraphicsBuffer.h"
 #include "osxGraphicsStateGuardian.h"
 #include "pnmImage.h"
 #include "subprocessWindow.h"
 #include "nativeWindowHandle.h"
+#import <Carbon/Carbon.h>
+
+// some macros to make code more readable.
+#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
+#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
+#define GetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
+#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
+#define GetModeSafeForHardware(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware)
+#define GetModeStretched(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsStretched)
+#define MAX_DISPLAYS 32
+
+Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) {
+  // get a boolean from the dictionary
+  Boolean value = false;
+  CFBooleanRef boolRef;
+  boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
+  if (boolRef != NULL)
+    value = CFBooleanGetValue(boolRef);    
+  return value;
+}
+
+long GetDictionaryLong(CFDictionaryRef theDict, const void* key) {
+  // get a long from the dictionary
+  long value = 0;
+  CFNumberRef numRef;
+  numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
+  if (numRef != NULL)
+    CFNumberGetValue(numRef, kCFNumberLongType, &value);    
+  return value;
+}
+
+static CFComparisonResult CompareModes (const void *val1,const void *val2,void *context) {
+  // CFArray comparison callback for sorting display modes.
+#pragma unused(context)
+  CFDictionaryRef thisMode = (CFDictionaryRef)val1;
+  CFDictionaryRef otherMode = (CFDictionaryRef)val2;
+   
+  long width = GetModeWidth(thisMode);
+  long otherWidth = GetModeWidth(otherMode);
+  long height = GetModeHeight(thisMode);
+  long otherHeight = GetModeHeight(otherMode);
+   
+  // sort modes in screen size order
+  if (width * height < otherWidth * otherHeight) {
+    return kCFCompareLessThan;
+  } else if (width * height > otherWidth * otherHeight) {
+    return kCFCompareGreaterThan;
+  }
+   
+  // sort modes by bits per pixel
+  long bitsPerPixel = GetModeBitsPerPixel(thisMode);
+  long otherBitsPerPixel = GetModeBitsPerPixel(otherMode);   
+  if (bitsPerPixel < otherBitsPerPixel) {
+    return kCFCompareLessThan;
+  } else if (bitsPerPixel > otherBitsPerPixel) {
+    return kCFCompareGreaterThan;
+  }
+   
+  // sort modes by refresh rate.
+  long refreshRate = GetModeRefreshRate(thisMode);
+  long otherRefreshRate = GetModeRefreshRate(otherMode);   
+  if (refreshRate < otherRefreshRate) {
+    return kCFCompareLessThan;
+  } else if (refreshRate > otherRefreshRate) {
+    return kCFCompareGreaterThan;
+  }
+     
+  return kCFCompareEqualTo;
+}
+
+CFArrayRef GSCGDisplayAvailableModesUsefulForOpenGL(CGDirectDisplayID display) {
+  // get a list of all possible display modes for this system.
+  CFArrayRef availableModes = CGDisplayAvailableModes(display);
+  unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
+  
+  // creat mutable array to hold the display modes we are interested int.
+  CFMutableArrayRef usefulModes = CFArrayCreateMutable(kCFAllocatorDefault, numberOfAvailableModes, NULL);
+  
+  // get the current bits per pixel.
+  long currentModeBitsPerPixel = GetModeBitsPerPixel(CGDisplayCurrentMode(display));
+  
+  unsigned int i;
+  for (i= 0; i<numberOfAvailableModes; ++i) {
+    // look at each mode in the available list
+    CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
+     
+    // we are only interested in modes with the same bits per pixel as current.
+    //   to allow for switching from fullscreen to windowed modes.
+    // that are safe for this hardward
+    // that are not stretched.
+    long bitsPerPixel = GetModeBitsPerPixel(mode);
+    Boolean safeForHardware = GetModeSafeForHardware(mode);
+    Boolean stretched = GetModeStretched(mode);
+    
+    if ((bitsPerPixel != currentModeBitsPerPixel) || (!safeForHardware) || (stretched)) {
+      continue; // skip this mode
+    }
+     
+    long width = GetModeWidth(mode);
+    long height = GetModeHeight(mode);
+    long refreshRate = GetModeRefreshRate(mode);     
+    Boolean replaced = false;
+    Boolean skipped = false;
+     
+    // now check to see if we already added a mode like this one.
+    //   we want the highest refresh rate for this width/height
+    unsigned int j;
+    unsigned int currentNumberOfUsefulModes =  CFArrayGetCount(usefulModes);
+    for (j = 0; j < currentNumberOfUsefulModes; ++j) {
+      CFDictionaryRef otherMode = (CFDictionaryRef)CFArrayGetValueAtIndex(usefulModes, j);       
+      long otherWidth = GetModeWidth(otherMode);
+      long otherHeight = GetModeHeight(otherMode);       
+      if ((otherWidth == width) && (otherHeight == height)) {
+        long otherRefreshRate = GetModeRefreshRate(otherMode);          
+        if (otherRefreshRate < refreshRate) {
+          // replace lower refresh rate.
+          const void* value = mode;
+          CFArrayReplaceValues(usefulModes, CFRangeMake(j ,1), &value, 1);
+          replaced = true;
+          break;
+        }
+        else if (otherRefreshRate > refreshRate) {
+          skipped = true;
+          break;
+        }
+      }
+    }     
+    // this is a useful mode so add it to the array.
+    if (!replaced && !skipped) {
+      CFArrayAppendValue(usefulModes, mode);
+    }     
+  }   
+  // now sort the useful mode array, using the comparison callback.
+  CFArraySortValues( usefulModes,
+    CFRangeMake(0, CFArrayGetCount(usefulModes)),
+    (CFComparatorFunction) CompareModes, NULL);  
+  // return the CFArray of the useful display modes.
+  return usefulModes;
+} 
 
 TypeHandle osxGraphicsPipe::_type_handle;
   
 ////////////////////////////////////////////////////////////////////
 //     Function: osxGraphicsPipe::Constructor
@@ -28,10 +167,30 @@
 osxGraphicsPipe::
 osxGraphicsPipe() {
   CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay);
   _display_width = CGRectGetWidth(display_bounds);
   _display_height = CGRectGetHeight(display_bounds);
+  
+  CGDirectDisplayID display, displayArray[MAX_DISPLAYS] ;
+  CGDisplayCount numDisplays;
+  CFDictionaryRef displayMode;  
+  CFArrayRef displayModeArray;
+  int number, i;  
+  CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays);
+  display = displayArray [numDisplays - 1];
+  displayModeArray = GSCGDisplayAvailableModesUsefulForOpenGL( display );   
+  number = CFArrayGetCount( displayModeArray );
+  DisplayMode *displays = new DisplayMode[ number ];  
+  for(i = 0; i < number; i++) {      
+     displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i);
+     _display_information -> _total_display_modes++;      
+     displays[i].width = (signed int)GetModeWidth (displayMode);
+     displays[i].height = (signed int)GetModeHeight (displayMode);
+     displays[i].bits_per_pixel = (signed int)GetModeBitsPerPixel (displayMode);
+     displays[i].refresh_rate = (signed int)GetModeRefreshRate (displayMode);
+  }   
+  _display_information -> _display_mode_array = displays; 
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: osxGraphicsPipe::Destructor
 //       Access: Public, Virtual

Excellent, thanks! I have applied the patch to the trunk.

David