open_toontown_panda3d/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm

282 lines
9.6 KiB
Plaintext

/**
* 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."
*
* @file cocoaGraphicsStateGuardian.mm
* @author rdb
* @date 2012-05-14
*/
#include "cocoaGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#include "lightReMutexHolder.h"
#include <mach-o/dyld.h>
#import <AppKit/AppKit.h>
#import <OpenGL/CGLRenderers.h>
#ifndef kCGLRendererIDMatchingMask
// For older versions of Mac OS X
#define kCGLRendererIDMatchingMask 0x00FE7F00
#endif
TypeHandle CocoaGraphicsStateGuardian::_type_handle;
/**
*
*/
CocoaGraphicsStateGuardian::
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGraphicsStateGuardian *share_with) :
GLGraphicsStateGuardian(engine, pipe)
{
_share_context = nil;
_context = nil;
if (share_with != (CocoaGraphicsStateGuardian *)NULL) {
_prepared_objects = share_with->get_prepared_objects();
_share_context = share_with->_context;
}
}
/**
*
*/
CocoaGraphicsStateGuardian::
~CocoaGraphicsStateGuardian() {
if (_context != nil) {
[_context clearDrawable];
[_context release];
}
}
/**
* Gets the FrameBufferProperties to match the indicated config.
*/
void CocoaGraphicsStateGuardian::
get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_format, int screen) {
properties.clear();
// Now update our framebuffer_mode and bit depth appropriately.
GLint double_buffer, stereo, aux_buffers, color_float, color_size,
alpha_size, depth_size, stencil_size, accum_size, sample_buffers,
samples, renderer_id, accelerated, window, pbuffer;
[pixel_format getValues:&double_buffer forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:screen];
[pixel_format getValues:&stereo forAttribute:NSOpenGLPFAStereo forVirtualScreen:screen];
[pixel_format getValues:&aux_buffers forAttribute:NSOpenGLPFAAuxBuffers forVirtualScreen:screen];
[pixel_format getValues:&color_float forAttribute:NSOpenGLPFAColorFloat forVirtualScreen:screen];
[pixel_format getValues:&color_size forAttribute:NSOpenGLPFAColorSize forVirtualScreen:screen];
[pixel_format getValues:&alpha_size forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:screen];
[pixel_format getValues:&depth_size forAttribute:NSOpenGLPFADepthSize forVirtualScreen:screen];
[pixel_format getValues:&stencil_size forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:screen];
[pixel_format getValues:&accum_size forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:screen];
[pixel_format getValues:&sample_buffers forAttribute:NSOpenGLPFASampleBuffers forVirtualScreen:screen];
[pixel_format getValues:&samples forAttribute:NSOpenGLPFASamples forVirtualScreen:screen];
[pixel_format getValues:&renderer_id forAttribute:NSOpenGLPFARendererID forVirtualScreen:screen];
[pixel_format getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:screen];
[pixel_format getValues:&window forAttribute:NSOpenGLPFAWindow forVirtualScreen:screen];
[pixel_format getValues:&pbuffer forAttribute:NSOpenGLPFAPixelBuffer forVirtualScreen:screen];
properties.set_back_buffers(double_buffer);
properties.set_stereo(stereo);
properties.set_rgb_color(1);
properties.set_float_color(color_float);
properties.set_color_bits(color_size);
properties.set_stencil_bits(stencil_size);
properties.set_depth_bits(depth_size);
properties.set_alpha_bits(alpha_size);
properties.set_accum_bits(accum_size);
if (sample_buffers > 0) {
properties.set_multisamples(samples);
}
// TODO: add aux buffers
// Extract the renderer ID bits and check if our renderer matches the known
// software renderers.
renderer_id &= kCGLRendererIDMatchingMask;
if (renderer_id == kCGLRendererGenericID ||
renderer_id == kCGLRendererGenericFloatID ||
renderer_id == kCGLRendererAppleSWID) {
properties.set_force_software(1);
}
if (accelerated) {
properties.set_force_hardware(1);
}
}
/**
* Selects a visual or fbconfig for all the windows and buffers that use this
* gsg. Also creates the GL context and obtains the visual.
*/
void CocoaGraphicsStateGuardian::
choose_pixel_format(const FrameBufferProperties &properties,
CGDirectDisplayID display,
bool need_pbuffer) {
_context = nil;
_fbprops.clear();
// Neither Cocoa nor CGL seem to have a mechanism to query the available
// pixel formats, unfortunately, so the only thing we can do is ask for one
// with the properties we have requested.
pvector<NSOpenGLPixelFormatAttribute> attribs;
attribs.reserve(15);
// Picked this up from the pyglet source - seems to be necessary to support
// RAGE-II, which is not compliant.
attribs.push_back(NSOpenGLPFAAllRenderers);
// Don't let it fall back to a different renderer.
attribs.push_back(NSOpenGLPFANoRecovery);
// Consider pixel formats with properties equal to or better than we
// requested.
attribs.push_back(NSOpenGLPFAMinimumPolicy);
if (!properties.is_single_buffered()) {
attribs.push_back(NSOpenGLPFADoubleBuffer);
}
if (properties.is_stereo()) {
attribs.push_back(NSOpenGLPFAStereo);
}
int aux_buffers = properties.get_aux_rgba() + properties.get_aux_hrgba() + properties.get_aux_float();
attribs.push_back(NSOpenGLPFAAuxBuffers);
attribs.push_back(aux_buffers);
attribs.push_back(NSOpenGLPFAColorSize);
attribs.push_back(properties.get_color_bits());
attribs.push_back(NSOpenGLPFADepthSize);
attribs.push_back(properties.get_depth_bits());
attribs.push_back(NSOpenGLPFAStencilSize);
attribs.push_back(properties.get_stencil_bits());
// Curious case - if we request anything less than 8 alpha bits, then on
// some ATI cards, it will grab a pixel format with just 2 alpha bits, which
// just shows a white window and nothing else. Might have something to do
// with the compositing window manager. Omitting it altogether seems to
// make it grab one with 8 bits, though. Dirty hack. Needs more research.
if (properties.get_alpha_bits() > 0) {
attribs.push_back(NSOpenGLPFAAlphaSize);
attribs.push_back(max(8, properties.get_alpha_bits()));
}
if (properties.get_multisamples() > 0) {
attribs.push_back(NSOpenGLPFASampleBuffers);
attribs.push_back(1);
attribs.push_back(NSOpenGLPFASamples);
attribs.push_back(properties.get_multisamples());
attribs.push_back(NSOpenGLPFAMultisample);
}
if (properties.get_force_software()) {
// Request the generic software renderer.
attribs.push_back(NSOpenGLPFARendererID);
attribs.push_back(kCGLRendererGenericFloatID);
}
if (properties.get_force_hardware()) {
attribs.push_back(NSOpenGLPFAAccelerated);
}
attribs.push_back(NSOpenGLPFAWindow);
if (need_pbuffer) {
attribs.push_back(NSOpenGLPFAPixelBuffer);
}
// Required when going fullscreen, optional when windowed
attribs.push_back(NSOpenGLPFAScreenMask);
attribs.push_back(CGDisplayIDToOpenGLDisplayMask(display));
// End of the array
attribs.push_back((NSOpenGLPixelFormatAttribute)0);
// Create the format.
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
if (format == nil) {
cocoadisplay_cat.error() <<
"Could not find a usable pixel format.\n";
return;
}
// For now, I'm just using the first virtual screen.
cocoadisplay_cat.debug() <<
"Pixel format has " << [format numberOfVirtualScreens] << " virtual screens.\n";
get_properties(_fbprops, format, 0);
// TODO: print out renderer
_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:_share_context];
[format release];
if (_context == nil) {
cocoadisplay_cat.error() <<
"Failed to create OpenGL context!\n";
return;
}
// Set vsync setting on the context
GLint swap = sync_video ? 1 : 0;
[_context setValues:&swap forParameter:NSOpenGLCPSwapInterval];
cocoadisplay_cat.debug()
<< "Created context " << _context << ": " << _fbprops << "\n";
}
/**
* Queries the runtime version of OpenGL in use.
*/
void CocoaGraphicsStateGuardian::
query_gl_version() {
GLGraphicsStateGuardian::query_gl_version();
// We output to glgsg_cat instead of glxdisplay_cat, since this is where the
// GL version has been output, and it's nice to see the two of these
// together.
if (glgsg_cat.is_debug()) {
// XXX this is supposed to work, but the NSOpenGLGetVersion symbol cannot
// be found when I do this
// GLint major, minor; NSOpenGLGetVersion(&major, &minor);
// glgsg_cat.debug() << "NSOpenGLVersion = " << major << "." << minor <<
// "\n";
}
}
/**
* Returns the pointer to the GL extension function with the indicated name.
* It is the responsibility of the caller to ensure that the required
* extension is defined in the OpenGL runtime prior to calling this; it is an
* error to call this for a function that is not defined.
*/
void *CocoaGraphicsStateGuardian::
do_get_extension_func(const char *name) {
char* fullname = (char*) malloc(strlen(name) + 2);
strcpy(fullname + 1, name);
fullname[0] = '_';
// Believe it or not, but this is actually the Apple-recommended way to do
// it. I know, right?
if (NSIsSymbolNameDefined(fullname)) {
NSSymbol symbol = NSLookupAndBindSymbol(fullname);
free(fullname);
return (void *) NSAddressOfSymbol(symbol);
}
cocoadisplay_cat.warning() <<
"do_get_extension_func failed for " << fullname << "!\n";
free(fullname);
return NULL;
}