cocoa: Split out GL-specific code into new cocoagldisplay module

This makes it possible to create subclasses for tinydisplay and vulkandisplay without having to duplicate code
This commit is contained in:
rdb 2023-03-20 21:39:56 +01:00
parent 4bb6d8f6d8
commit 545ede9d94
31 changed files with 990 additions and 508 deletions

View File

@ -3288,6 +3288,8 @@ if GetTarget() == 'windows':
CopyAllHeaders('panda/src/wgldisplay')
elif GetTarget() == 'darwin':
CopyAllHeaders('panda/src/cocoadisplay')
if not PkgSkip('GL'):
CopyAllHeaders('panda/src/cocoagldisplay')
elif GetTarget() == 'android':
CopyAllHeaders('panda/src/android')
CopyAllHeaders('panda/src/androiddisplay')
@ -4647,15 +4649,24 @@ if GetTarget() not in ['windows', 'darwin'] and not PkgSkip("GL") and not PkgSki
# DIRECTORY: panda/src/cocoadisplay/
#
if GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and not PkgSkip("GL"):
OPTS=['DIR:panda/src/cocoadisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL']
if GetTarget() == 'darwin' and not PkgSkip("COCOA"):
OPTS=['DIR:panda/src/cocoadisplay', 'BUILDING:PANDAGL', 'COCOA']
TargetAdd('p3cocoadisplay_composite1.obj', opts=OPTS, input='p3cocoadisplay_composite1.mm')
#
# DIRECTORY: panda/src/cocoagldisplay/
#
if GetTarget() == 'darwin' and not PkgSkip("COCOA") and not PkgSkip("GL"):
OPTS=['DIR:panda/src/cocoagldisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL']
TargetAdd('p3cocoagldisplay_composite1.obj', opts=OPTS, input='p3cocoagldisplay_composite1.mm')
OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL']
TargetAdd('pandagl_pandagl.obj', opts=OPTS, input='pandagl.cxx')
TargetAdd('libpandagl.dll', input='pandagl_pandagl.obj')
TargetAdd('libpandagl.dll', input='p3glgsg_config_glgsg.obj')
TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj')
TargetAdd('libpandagl.dll', input='p3cocoadisplay_composite1.obj')
TargetAdd('libpandagl.dll', input='p3cocoagldisplay_composite1.obj')
if not PkgSkip('PANDAFX'):
TargetAdd('libpandagl.dll', input='libpandafx.dll')
TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)

View File

@ -8,6 +8,7 @@ add_subdirectory(src/audiotraits)
add_subdirectory(src/chan)
add_subdirectory(src/char)
add_subdirectory(src/cocoadisplay)
add_subdirectory(src/cocoagldisplay)
add_subdirectory(src/collide)
add_subdirectory(src/configfiles)
add_subdirectory(src/cull)

View File

@ -13,9 +13,9 @@ elseif(HAVE_WGL)
set(PANDAGL_PIPE_TYPE "wglGraphicsPipe")
elseif(HAVE_COCOA)
list(APPEND PANDAGL_LINK_TARGETS p3cocoadisplay)
set(PANDAGL_PIPE_TYPE "CocoaGraphicsPipe")
set(PANDAGL_PIPE_INCLUDE "cocoaGraphicsPipe.h")
list(APPEND PANDAGL_LINK_TARGETS p3cocoagldisplay p3cocoadisplay)
set(PANDAGL_PIPE_TYPE "CocoaGLGraphicsPipe")
set(PANDAGL_PIPE_INCLUDE "cocoaGLGraphicsPipe.h")
else()
message("") # Add extra line before error

View File

@ -13,9 +13,9 @@
#include "wglGraphicsPipe.h"
#endif
#if defined(HAVE_COCOA)
#include "config_cocoadisplay.h"
#include "cocoaGraphicsPipe.h"
#ifdef HAVE_COCOA
#include "config_cocoagldisplay.h"
#include "cocoaGLGraphicsPipe.h"
#endif
#ifdef HAVE_GLX
@ -46,8 +46,8 @@ init_libpandagl() {
init_libwgldisplay();
#endif // HAVE_GL
#if defined(HAVE_COCOA)
init_libcocoadisplay();
#ifdef HAVE_COCOA
init_libcocoagldisplay();
#endif
#ifdef HAVE_GLX
@ -69,8 +69,8 @@ get_pipe_type_pandagl() {
return wglGraphicsPipe::get_class_type().get_index();
#endif
#if defined(HAVE_COCOA)
return CocoaGraphicsPipe::get_class_type().get_index();
#ifdef HAVE_COCOA
return CocoaGLGraphicsPipe::get_class_type().get_index();
#endif
#ifdef HAVE_GLX

View File

@ -1,13 +1,11 @@
if(NOT APPLE OR NOT HAVE_GL OR NOT HAVE_COCOA)
if(NOT APPLE OR NOT HAVE_COCOA)
return()
endif()
set(P3COCOADISPLAY_HEADERS
config_cocoadisplay.h
cocoaGraphicsBuffer.h cocoaGraphicsBuffer.I
cocoaGraphicsPipe.h cocoaGraphicsPipe.I
cocoaGraphicsWindow.h cocoaGraphicsWindow.I
cocoaGraphicsStateGuardian.h cocoaGraphicsStateGuardian.I
cocoaPandaApp.h
cocoaPandaView.h
cocoaPandaWindow.h
@ -17,9 +15,7 @@ set(P3COCOADISPLAY_HEADERS
set(P3COCOADISPLAY_SOURCES
config_cocoadisplay.mm
cocoaGraphicsBuffer.mm
cocoaGraphicsPipe.mm
cocoaGraphicsStateGuardian.mm
cocoaGraphicsWindow.mm
cocoaPandaApp.mm
cocoaPandaView.mm
@ -31,7 +27,7 @@ set(P3COCOADISPLAY_SOURCES
composite_sources(p3cocoadisplay P3COCOADISPLAY_SOURCES)
add_component_library(p3cocoadisplay SYMBOL BUILDING_PANDA_COCOADISPLAY
${P3COCOADISPLAY_HEADERS} ${P3COCOADISPLAY_SOURCES})
target_link_libraries(p3cocoadisplay p3glgsg panda)
target_link_libraries(p3cocoadisplay panda)
# Frameworks:
find_library(APPLICATIONSERVICES_LIBRARY ApplicationServices)
@ -46,5 +42,5 @@ mark_as_advanced(
APPLICATIONSERVICES_LIBRARY APPKIT_LIBRARY CARBON_LIBRARY CORE_VIDEO_LIBRARY)
if(NOT BUILD_METALIBS)
install(TARGETS p3cocoadisplay EXPORT OpenGL COMPONENT OpenGL DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS p3cocoadisplay EXPORT Core COMPONENT Core DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

View File

@ -15,22 +15,12 @@
#define COCOAGRAPHICSPIPE_H
#include "pandabase.h"
#include "graphicsWindow.h"
#include "graphicsPipe.h"
#include "lightMutex.h"
#include "lightReMutex.h"
#ifdef __OBJC__
#import <AppKit/NSScreen.h>
#else
struct NSScreen;
#endif
#include <ApplicationServices/ApplicationServices.h>
class FrameBufferProperties;
/**
* This graphics pipe represents the interface for creating OpenGL graphics
* This graphics pipe represents the base class for pipes that create
* windows on a Cocoa-based (e.g. Mac OS X) client.
*/
class EXPCL_PANDA_COCOADISPLAY CocoaGraphicsPipe : public GraphicsPipe {
@ -40,32 +30,15 @@ public:
INLINE CGDirectDisplayID get_display_id() const;
virtual std::string get_interface_name() const;
static PT(GraphicsPipe) pipe_constructor();
public:
virtual PreferredWindowThread get_preferred_window_thread() const;
protected:
virtual PT(GraphicsOutput) make_output(const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsEngine *engine,
GraphicsStateGuardian *gsg,
GraphicsOutput *host,
int retry,
bool &precertify);
virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine);
private:
void load_display_information();
// This is the Quartz display identifier.
CGDirectDisplayID _display;
friend class CocoaGraphicsWindow;
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -12,11 +12,7 @@
*/
#include "cocoaGraphicsPipe.h"
#include "cocoaGraphicsBuffer.h"
#include "cocoaGraphicsWindow.h"
#include "cocoaGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#include "frameBufferProperties.h"
#include "displayInformation.h"
#import <Foundation/NSAutoreleasePool.h>
@ -32,9 +28,6 @@ TypeHandle CocoaGraphicsPipe::_type_handle;
*/
CocoaGraphicsPipe::
CocoaGraphicsPipe(CGDirectDisplayID display) : _display(display) {
_supported_types = OT_window | OT_buffer | OT_texture_buffer;
_is_valid = true;
[[NSAutoreleasePool alloc] init];
// Put Cocoa into thread-safe mode by spawning a thread which immediately
@ -110,7 +103,7 @@ load_display_information() {
}
CFRelease(encoding);
}
if (modes != NULL) {
if (modes != nullptr) {
CFRelease(modes);
}
@ -135,26 +128,6 @@ CocoaGraphicsPipe::
~CocoaGraphicsPipe() {
}
/**
* 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.
*/
std::string CocoaGraphicsPipe::
get_interface_name() const {
return "OpenGL";
}
/**
* This function is passed to the GraphicsPipeSelection object to allow the
* user to make a default CocoaGraphicsPipe.
*/
PT(GraphicsPipe) CocoaGraphicsPipe::
pipe_constructor() {
return new CocoaGraphicsPipe;
}
/**
* Returns an indication of the thread in which this GraphicsPipe requires its
* window processing to be performed: typically either the app thread (e.g.
@ -166,95 +139,3 @@ CocoaGraphicsPipe::get_preferred_window_thread() const {
// only be called from the main thread!
return PWT_app;
}
/**
* Creates a new window on the pipe, if possible.
*/
PT(GraphicsOutput) CocoaGraphicsPipe::
make_output(const std::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;
}
CocoaGraphicsStateGuardian *cocoagsg = 0;
if (gsg != 0) {
DCAST_INTO_R(cocoagsg, gsg, NULL);
}
// First thing to try: a CocoaGraphicsWindow
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_rtt_cumulative)!=0)||
((flags&BF_can_bind_color)!=0)||
((flags&BF_can_bind_every)!=0)||
((flags&BF_can_bind_layered)!=0)) {
return NULL;
}
return new CocoaGraphicsWindow(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
// Second thing to try: a GLGraphicsBuffer. This requires a context, so if
// we don't have a host window, we instead create a CocoaGraphicsBuffer,
// which wraps around GLGraphicsBuffer and manages a context.
if (retry == 1) {
if (!gl_support_fbo ||
(flags & (BF_require_parasite | 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() ||
fb_prop.get_back_buffers() > 0 ||
fb_prop.get_accum_bits() > 0) {
return NULL;
}
}
if (cocoagsg != NULL && cocoagsg->is_valid() && !cocoagsg->needs_reset()) {
if (!cocoagsg->_supports_framebuffer_object ||
cocoagsg->_glDrawBuffers == NULL) {
return NULL;
} else if (fb_prop.is_basic()) {
// Early success - if we are sure that this buffer WILL meet specs, we
// can precertify it.
precertify = true;
}
}
if (host != NULL) {
return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
} else {
return new CocoaGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
}
// Nothing else left to try.
return NULL;
}
/**
* This is called when make_output() is used to create a
* CallbackGraphicsWindow. If the GraphicsPipe can construct a GSG that's not
* associated with any particular window object, do so now, assuming the
* correct graphics context has been set up externally.
*/
PT(GraphicsStateGuardian) CocoaGraphicsPipe::
make_callback_gsg(GraphicsEngine *engine) {
return new CocoaGraphicsStateGuardian(engine, this, NULL);
}

View File

@ -19,11 +19,21 @@
#include "cocoaGraphicsPipe.h"
#include "graphicsWindow.h"
#ifdef __OBJC__
#import <AppKit/NSEvent.h>
#import <AppKit/NSView.h>
#import <AppKit/NSWindow.h>
#import <CoreVideo/CoreVideo.h>
#else
#include <objc/objc.h>
typedef objc_object NSCursor;
typedef objc_object NSData;
typedef objc_object NSEvent;
typedef objc_object NSImage;
typedef objc_object NSView;
typedef objc_object NSWindow;
typedef unsigned long NSUInteger;
#endif
/**
* An interface to the Cocoa system for managing OpenGL windows under Mac OS
@ -41,13 +51,13 @@ public:
virtual ~CocoaGraphicsWindow();
virtual bool move_pointer(int device, int x, int y);
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
virtual void end_flip();
virtual void process_events();
virtual void set_properties_now(WindowProperties &properties);
virtual void update_context();
virtual void unbind_context();
void handle_move_event();
void handle_resize_event();
void handle_minimize_event(bool minimized);
@ -81,7 +91,7 @@ private:
ButtonHandle map_key(unsigned short c) const;
ButtonHandle map_raw_key(unsigned short keycode) const;
private:
protected:
NSWindow *_window;
NSView *_view;
NSUInteger _modifier_keys;
@ -90,7 +100,6 @@ private:
PT(GraphicsWindowInputDevice) _input;
bool _mouse_hidden;
bool _context_needs_update;
bool _vsync_enabled = false;
CGDisplayModeRef _fullscreen_mode;
CGDisplayModeRef _windowed_mode;

View File

@ -12,7 +12,6 @@
*/
#include "cocoaGraphicsWindow.h"
#include "cocoaGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#include "cocoaGraphicsPipe.h"
#include "cocoaPandaApp.h"
@ -40,7 +39,6 @@
#import <AppKit/NSImage.h>
#import <AppKit/NSScreen.h>
#import <AppKit/NSText.h>
#import <OpenGL/OpenGL.h>
#import <Carbon/Carbon.h>
TypeHandle CocoaGraphicsWindow::_type_handle;
@ -108,7 +106,7 @@ CocoaGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGraphicsPipe *cocoa_pipe;
DCAST_INTO_V(cocoa_pipe, _pipe);
_display = cocoa_pipe->_display;
_display = cocoa_pipe->get_display_id();
}
/**
@ -161,147 +159,6 @@ move_pointer(int device, int x, int y) {
return false;
}
/**
* This function will be called within the draw thread before beginning
* rendering for a given frame. It should do whatever setup is required, and
* return true if the frame should be rendered, or false if it should be
* skipped.
*/
bool CocoaGraphicsWindow::
begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == (GraphicsStateGuardian *)NULL) {
return false;
}
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_R(cocoagsg, _gsg, false);
nassertr(cocoagsg->_context != nil, false);
nassertr(_view != nil, false);
// Place a lock on the context.
cocoagsg->lock_context();
// Set the drawable.
// Although not recommended, it is technically possible to use the same
// context with multiple different-sized windows. If that happens, the
// context needs to be updated accordingly.
if ([cocoagsg->_context view] != _view) {
// XXX I'm not 100% sure that changing the view requires it to update.
_context_needs_update = true;
[cocoagsg->_context setView:_view];
if (cocoadisplay_cat.is_spam()) {
cocoadisplay_cat.spam()
<< "Switching context to view " << _view << "\n";
}
}
// Update the context if necessary, to make it reallocate buffers etc.
if (_context_needs_update) {
if ([NSThread isMainThread]) {
[cocoagsg->_context update];
_context_needs_update = false;
} else {
cocoagsg->unlock_context();
return false;
}
}
// Lock the view for drawing.
if (!_properties.get_fullscreen()) {
nassertr_always([_view lockFocusIfCanDraw], false);
}
// Make the context current.
[cocoagsg->_context makeCurrentContext];
// Now that we have made the context current to a window, we can reset the
// GSG state if this is the first time it has been used. (We can't just
// call reset() when we construct the GSG, because reset() requires having a
// current context.)
cocoagsg->reset_if_new();
if (mode == FM_render) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame(current_thread);
}
/**
* This function will be called within the draw thread after rendering is
* completed for a given frame. It should do whatever finalization is
* required.
*/
void CocoaGraphicsWindow::
end_frame(FrameMode mode, Thread *current_thread) {
end_frame_spam(mode);
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
if (!_properties.get_fullscreen()) {
[_view unlockFocus];
}
// Release the context.
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
cocoagsg->unlock_context();
if (mode == FM_render) {
// end_render_texture();
copy_to_textures();
}
_gsg->end_frame(current_thread);
if (mode == FM_render) {
trigger_flip();
clear_cube_map_selection();
}
}
/**
* This function will be called within the draw thread after begin_flip() has
* been called on all windows, to finish the exchange of the front and back
* buffers.
*
* This should cause the window to wait for the flip, if necessary.
*/
void CocoaGraphicsWindow::
end_flip() {
if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
if (_vsync_enabled) {
AtomicAdjust::Integer cur_frame = ClockObject::get_global_clock()->get_frame_count();
if (AtomicAdjust::set(cocoagsg->_last_wait_frame, cur_frame) != cur_frame) {
cocoagsg->_swap_lock.lock();
cocoagsg->_swap_condition.wait();
cocoagsg->_swap_lock.unlock();
}
}
cocoagsg->lock_context();
// Swap the front and back buffer.
[cocoagsg->_context flushBuffer];
// Flush the window
[[_view window] flushWindow];
cocoagsg->unlock_context();
}
GraphicsWindow::end_flip();
}
/**
* Do whatever processing is necessary to ensure that the window responds to
* user events. Also, honor any requests recently made via
@ -351,15 +208,7 @@ process_events() {
[pool release];
if (_context_needs_update && _gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();
_context_needs_update = false;
[cocoagsg->_context update];
cocoagsg->unlock_context();
}
update_context();
}
}
@ -369,34 +218,6 @@ process_events() {
*/
bool CocoaGraphicsWindow::
open_window() {
CocoaGraphicsPipe *cocoa_pipe;
DCAST_INTO_R(cocoa_pipe, _pipe, false);
// GSG CreationInitialization
CocoaGraphicsStateGuardian *cocoagsg;
if (_gsg == 0) {
// There is no old gsg. Create a new one.
cocoagsg = new CocoaGraphicsStateGuardian(_engine, _pipe, NULL);
cocoagsg->choose_pixel_format(_fb_properties, cocoa_pipe->_display, false);
_gsg = cocoagsg;
} else {
// If the old gsg has the wrong pixel format, create a new one that shares
// with the old gsg.
DCAST_INTO_R(cocoagsg, _gsg, false);
if (!cocoagsg->get_fb_properties().subsumes(_fb_properties)) {
cocoagsg = new CocoaGraphicsStateGuardian(_engine, _pipe, cocoagsg);
cocoagsg->choose_pixel_format(_fb_properties, cocoa_pipe->_display, false);
_gsg = cocoagsg;
}
}
if (cocoagsg->_context == nil) {
// Could not obtain a proper context.
_gsg.clear();
close_window();
return false;
}
// Fill in the blanks.
if (!_properties.has_origin()) {
_properties.set_origin(-2, -2);
@ -476,7 +297,7 @@ open_window() {
NSEnumerator *e = [[NSScreen screens] objectEnumerator];
while (screen = (NSScreen *) [e nextObject]) {
NSNumber *num = [[screen deviceDescription] objectForKey: @"NSScreenNumber"];
if (cocoa_pipe->_display == (CGDirectDisplayID) [num longValue]) {
if (_display == (CGDirectDisplayID) [num longValue]) {
break;
}
}
@ -545,19 +366,16 @@ open_window() {
}
}
// Lock the context, so we can safely operate on it.
cocoagsg->lock_context();
// Create the NSView to render to.
NSRect rect = NSMakeRect(0, 0, _properties.get_x_size(), _properties.get_y_size());
_view = [[CocoaPandaView alloc] initWithFrame:rect context:cocoagsg->_context window:this];
if (_parent_window_handle == (WindowHandle *)NULL) {
_view = [[CocoaPandaView alloc] initWithFrame:rect window:this];
if (_parent_window_handle == nullptr) {
[_window setContentView:_view];
[_window makeFirstResponder:_view];
}
// Check if we have an NSView to attach our NSView to.
if (parent_nsview != NULL) {
if (parent_nsview != nullptr) {
[parent_nsview addSubview:_view];
}
@ -566,7 +384,7 @@ open_window() {
_window_handle = NativeWindowHandle::make_int((size_t) _view);
// And tell our parent window that we're now its child.
if (_parent_window_handle != (WindowHandle *)NULL) {
if (_parent_window_handle != nullptr) {
_parent_window_handle->attach_child(_window_handle);
}
@ -672,29 +490,6 @@ open_window() {
}
}
// Make the context current.
_context_needs_update = false;
[cocoagsg->_context makeCurrentContext];
[cocoagsg->_context setView:_view];
[cocoagsg->_context update];
cocoagsg->reset_if_new();
// Release the context.
cocoagsg->unlock_context();
if (!cocoagsg->is_valid()) {
close_window();
return false;
}
if (!cocoagsg->get_fb_properties().verify_hardware_software
(_fb_properties, cocoagsg->get_gl_renderer())) {
close_window();
return false;
}
_fb_properties = cocoagsg->get_fb_properties();
// Reset dead key state.
_dead_key_state = 0;
@ -710,8 +505,6 @@ open_window() {
CGAssociateMouseAndMouseCursorPosition(NO);
}
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
return true;
}
@ -730,15 +523,8 @@ close_window() {
_cursor = nil;
}
if (_gsg != (GraphicsStateGuardian *)NULL) {
CocoaGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
cocoagsg->lock_context();
[cocoagsg->_context clearDrawable];
cocoagsg->unlock_context();
}
if (_gsg != nullptr) {
unbind_context();
_gsg.clear();
}
@ -756,8 +542,6 @@ close_window() {
_view = nil;
}
_vsync_enabled = false;
GraphicsWindow::close_window();
}
@ -1148,18 +932,24 @@ set_properties_now(WindowProperties &properties) {
}
if (_context_needs_update && _gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();
_context_needs_update = false;
[cocoagsg->_context update];
cocoagsg->unlock_context();
}
update_context();
}
}
/**
*
*/
void CocoaGraphicsWindow::
update_context() {
}
/**
*
*/
void CocoaGraphicsWindow::
unbind_context() {
}
/**
* Returns an appropriate CGDisplayModeRef for the given width and height, or
* NULL if none was found.
@ -1663,17 +1453,9 @@ handle_close_event() {
_window = nil;
// Get rid of the GSG
if (_gsg != (GraphicsStateGuardian *)NULL) {
CocoaGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
cocoagsg->lock_context();
[cocoagsg->_context clearDrawable];
cocoagsg->unlock_context();
}
if (_gsg != nullptr) {
unbind_context();
_gsg.clear();
_vsync_enabled = false;
}
// Dump the view, too

View File

@ -0,0 +1,154 @@
diff a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm (rejected hunks)
@@ -161,152 +159,6 @@
return false;
}
-
-/**
- * This function will be called within the draw thread before beginning
- * rendering for a given frame. It should do whatever setup is required, and
- * return true if the frame should be rendered, or false if it should be
- * skipped.
- */
-bool CocoaGraphicsWindow::
-begin_frame(FrameMode mode, Thread *current_thread) {
- PStatTimer timer(_make_current_pcollector, current_thread);
-
- begin_frame_spam(mode);
- if (_gsg == (GraphicsStateGuardian *)NULL) {
- return false;
- }
-
- CocoaGraphicsStateGuardian *cocoagsg;
- DCAST_INTO_R(cocoagsg, _gsg, false);
- nassertr(cocoagsg->_context != nil, false);
- nassertr(_view != nil, false);
-
- // Place a lock on the context.
- cocoagsg->lock_context();
-
- // Set the drawable.
- // Although not recommended, it is technically possible to use the same
- // context with multiple different-sized windows. If that happens, the
- // context needs to be updated accordingly.
- if ([cocoagsg->_context view] != _view) {
- // XXX I'm not 100% sure that changing the view requires it to update.
- _context_needs_update = true;
- [cocoagsg->_context setView:_view];
-
- if (cocoadisplay_cat.is_spam()) {
- cocoadisplay_cat.spam()
- << "Switching context to view " << _view << "\n";
- }
- }
-
- // Update the context if necessary, to make it reallocate buffers etc.
- if (_context_needs_update) {
- if ([NSThread isMainThread]) {
- [cocoagsg->_context update];
- _context_needs_update = false;
- } else {
- cocoagsg->unlock_context();
- return false;
- }
- }
-
- // Lock the view for drawing.
- if (!_properties.get_fullscreen()) {
- nassertr_always([_view lockFocusIfCanDraw], false);
- }
-
- // Make the context current.
- [cocoagsg->_context makeCurrentContext];
-
- // Now that we have made the context current to a window, we can reset the
- // GSG state if this is the first time it has been used. (We can't just
- // call reset() when we construct the GSG, because reset() requires having a
- // current context.)
- cocoagsg->reset_if_new();
-
- if (mode == FM_render) {
- // begin_render_texture();
- clear_cube_map_selection();
- }
-
- _gsg->set_current_properties(&get_fb_properties());
- if (_gsg->begin_frame(current_thread)) {
- copy_async_screenshot();
- return true;
- } else {
- return false;
- }
-}
-
-/**
- * This function will be called within the draw thread after rendering is
- * completed for a given frame. It should do whatever finalization is
- * required.
- */
-void CocoaGraphicsWindow::
-end_frame(FrameMode mode, Thread *current_thread) {
- end_frame_spam(mode);
- nassertv(_gsg != (GraphicsStateGuardian *)NULL);
-
- if (!_properties.get_fullscreen()) {
- [_view unlockFocus];
- }
- // Release the context.
- CocoaGraphicsStateGuardian *cocoagsg;
- DCAST_INTO_V(cocoagsg, _gsg);
-
- cocoagsg->unlock_context();
-
- if (mode == FM_render) {
- // end_render_texture();
- copy_to_textures();
- }
-
- _gsg->end_frame(current_thread);
-
- if (mode == FM_render) {
- trigger_flip();
- clear_cube_map_selection();
- }
-}
-
-/**
- * This function will be called within the draw thread after begin_flip() has
- * been called on all windows, to finish the exchange of the front and back
- * buffers.
- *
- * This should cause the window to wait for the flip, if necessary.
- */
-void CocoaGraphicsWindow::
-end_flip() {
- if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
-
- CocoaGraphicsStateGuardian *cocoagsg;
- DCAST_INTO_V(cocoagsg, _gsg);
-
- if (_vsync_enabled) {
- AtomicAdjust::Integer cur_frame = ClockObject::get_global_clock()->get_frame_count();
- if (AtomicAdjust::set(cocoagsg->_last_wait_frame, cur_frame) != cur_frame) {
- cocoagsg->_swap_lock.lock();
- cocoagsg->_swap_condition.wait();
- cocoagsg->_swap_lock.unlock();
- }
- }
-
- cocoagsg->lock_context();
-
- // Swap the front and back buffer.
- [cocoagsg->_context flushBuffer];
-
- // Flush the window
- [[_view window] flushWindow];
-
- cocoagsg->unlock_context();
- }
- GraphicsWindow::end_flip();
-}
-
/**
* Do whatever processing is necessary to ensure that the window responds to
* user events. Also, honor any requests recently made via

View File

@ -14,18 +14,15 @@
#include "graphicsWindow.h"
#import <AppKit/NSView.h>
#import <AppKit/NSOpenGL.h>
class CocoaGraphicsWindow;
@interface CocoaPandaView : NSView {
@private
NSOpenGLContext *_context;
CocoaGraphicsWindow *_graphicsWindow;
}
- (id) initWithFrame:(NSRect)frameRect context:(NSOpenGLContext*)context window:(CocoaGraphicsWindow*)window;
- (NSOpenGLContext*) openGLContext;
- (id) initWithFrame:(NSRect)frameRect window:(CocoaGraphicsWindow*)window;
- (GraphicsWindow*) graphicsWindow;
- (void) drawRect:(NSRect)dirtyRect;

View File

@ -18,10 +18,9 @@
#include <OpenGL/gl.h>
@implementation CocoaPandaView
- (id) initWithFrame:(NSRect)frameRect context:(NSOpenGLContext*)context window:(CocoaGraphicsWindow*)window {
- (id) initWithFrame:(NSRect)frameRect window:(CocoaGraphicsWindow*)window {
self = [super initWithFrame: frameRect];
_context = context;
[self setCanDrawConcurrently:YES];
// If a layer ends up becoming attached to the view, tell AppKit we'll manage
@ -37,10 +36,6 @@
return self;
}
- (NSOpenGLContext*) openGLContext {
return _context;
}
- (GraphicsWindow*) graphicsWindow {
return _graphicsWindow;
}
@ -170,14 +165,9 @@
return YES;
}
-(void)setLayer:(CALayer*)layer
{
[super setLayer:layer];
-(void)setLayer:(CALayer*)layer {
[super setLayer:layer];
// Starting in macOS 10.14, a CALayer will still be attached to a view even
// if `wantsLayer` is false. If we don't update the context now, only a
// black screen will be rendered until the context is updated some other
// way (like through a window resize event).
[_context update];
_graphicsWindow->update_context();
}
@end

View File

@ -12,11 +12,8 @@
*/
#include "config_cocoadisplay.h"
#include "cocoaGraphicsBuffer.h"
#include "cocoaGraphicsPipe.h"
#include "cocoaGraphicsStateGuardian.h"
#include "cocoaGraphicsWindow.h"
#include "graphicsPipeSelection.h"
#include "dconfig.h"
#include "pandaSystem.h"
@ -50,15 +47,6 @@ init_libcocoadisplay() {
}
initialized = true;
CocoaGraphicsBuffer::init_type();
CocoaGraphicsPipe::init_type();
CocoaGraphicsStateGuardian::init_type();
CocoaGraphicsWindow::init_type();
GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr();
selection->add_pipe_type(CocoaGraphicsPipe::get_class_type(),
CocoaGraphicsPipe::pipe_constructor);
PandaSystem *ps = PandaSystem::get_global_ptr();
ps->set_system_tag("OpenGL", "window_system", "Cocoa");
}

View File

@ -1,10 +1,8 @@
#include "config_cocoadisplay.mm"
#include "cocoaGraphicsBuffer.mm"
#include "cocoaGraphicsPipe.mm"
#include "cocoaGraphicsStateGuardian.mm"
#include "cocoaGraphicsWindow.mm"
#include "cocoaPandaApp.mm"
#include "cocoaPandaView.mm"
#include "cocoaPandaWindow.mm"
#include "cocoaPandaWindowDelegate.mm"
#include "cocoaPandaAppDelegate.mm"
#include "config_cocoadisplay.mm"

View File

@ -0,0 +1,28 @@
if(NOT APPLE OR NOT HAVE_GL OR NOT HAVE_COCOA)
return()
endif()
set(P3COCOAGLDISPLAY_HEADERS
cocoaGLGraphicsBuffer.h cocoaGLGraphicsBuffer.I
cocoaGLGraphicsPipe.h cocoaGLGraphicsPipe.I
cocoaGLGraphicsStateGuardian.h cocoaGLGraphicsStateGuardian.I
cocoaGLGraphicsWindow.h cocoaGLGraphicsWindow.I
config_cocoagldisplay.h
)
set(P3COCOAGLDISPLAY_SOURCES
cocoaGLGraphicsBuffer.mm
cocoaGLGraphicsPipe.mm
cocoaGLGraphicsStateGuardian.mm
cocoaGLGraphicsWindow.mm
config_cocoagldisplay.mm
)
composite_sources(p3cocoagldisplay P3COCOAGLDISPLAY_SOURCES)
add_component_library(p3cocoagldisplay SYMBOL BUILDING_PANDA_COCOAGLDISPLAY
${P3COCOAGLDISPLAY_HEADERS} ${P3COCOAGLDISPLAY_SOURCES})
target_link_libraries(p3cocoagldisplay p3cocoadisplay p3glgsg panda)
if(NOT BUILD_METALIBS)
install(TARGETS p3cocoagldisplay EXPORT OpenGL COMPONENT OpenGL DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

View File

@ -6,7 +6,7 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsBuffer.I
* @file cocoaGLGraphicsBuffer.I
* @author rdb
* @date 2017-12-19
*/

View File

@ -6,7 +6,7 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsBuffer.h
* @file cocoaGLGraphicsBuffer.h
* @author rdb
* @date 2017-12-19
*/
@ -21,15 +21,15 @@
* This is a light wrapper around GLGraphicsBuffer (ie. FBOs) to interface
* with Cocoa contexts, so that it can be used without a host window.
*/
class EXPCL_PANDA_COCOADISPLAY CocoaGraphicsBuffer : public GLGraphicsBuffer {
class EXPCL_PANDA_COCOAGLDISPLAY CocoaGLGraphicsBuffer : public GLGraphicsBuffer {
public:
CocoaGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host);
CocoaGLGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host);
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
@ -44,7 +44,7 @@ public:
}
static void init_type() {
GLGraphicsBuffer::init_type();
register_type(_type_handle, "CocoaGraphicsBuffer",
register_type(_type_handle, "CocoaGLGraphicsBuffer",
GLGraphicsBuffer::get_class_type());
}
virtual TypeHandle get_type() const {
@ -56,6 +56,6 @@ private:
static TypeHandle _type_handle;
};
#include "cocoaGraphicsBuffer.I"
#include "cocoaGLGraphicsBuffer.I"
#endif

View File

@ -6,25 +6,25 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsBuffer.mm
* @file cocoaGLGraphicsBuffer.mm
* @author rdb
* @date 2017-12-19
*/
#include "cocoaGraphicsBuffer.h"
#include "cocoaGraphicsStateGuardian.h"
#include "cocoaGLGraphicsBuffer.h"
#include "cocoaGLGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#include "cocoaGraphicsPipe.h"
#import <OpenGL/OpenGL.h>
TypeHandle CocoaGraphicsBuffer::_type_handle;
TypeHandle CocoaGLGraphicsBuffer::_type_handle;
/**
*
*/
CocoaGraphicsBuffer::
CocoaGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGLGraphicsBuffer::
CocoaGLGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
@ -41,13 +41,13 @@ CocoaGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
* return true if the frame should be rendered, or false if it should be
* skipped.
*/
bool CocoaGraphicsBuffer::
bool CocoaGLGraphicsBuffer::
begin_frame(FrameMode mode, Thread *current_thread) {
if (_gsg == nullptr) {
return false;
}
CocoaGraphicsStateGuardian *cocoagsg;
CocoaGLGraphicsStateGuardian *cocoagsg;
DCAST_INTO_R(cocoagsg, _gsg, false);
nassertr(cocoagsg->_context != nil, false);
@ -66,14 +66,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
* completed for a given frame. It should do whatever finalization is
* required.
*/
void CocoaGraphicsBuffer::
void CocoaGLGraphicsBuffer::
end_frame(FrameMode mode, Thread *current_thread) {
nassertv(_gsg != nullptr);
GLGraphicsBuffer::end_frame(mode, current_thread);
// Release the context.
CocoaGraphicsStateGuardian *cocoagsg;
CocoaGLGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
cocoagsg->unlock_context();
}
@ -82,16 +82,16 @@ end_frame(FrameMode mode, Thread *current_thread) {
* Opens the buffer right now. Called from the window thread. Returns true
* if the buffer is successfully opened, or false if there was a problem.
*/
bool CocoaGraphicsBuffer::
bool CocoaGLGraphicsBuffer::
open_buffer() {
CocoaGraphicsPipe *cocoa_pipe;
DCAST_INTO_R(cocoa_pipe, _pipe, false);
// GSG CreationInitialization
CocoaGraphicsStateGuardian *cocoagsg;
CocoaGLGraphicsStateGuardian *cocoagsg;
if (_gsg == nullptr) {
// There is no old gsg. Create a new one.
cocoagsg = new CocoaGraphicsStateGuardian(_engine, _pipe, nullptr);
cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, nullptr);
cocoagsg->choose_pixel_format(_fb_properties, cocoa_pipe->get_display_id(), false);
_gsg = cocoagsg;
} else {
@ -99,7 +99,7 @@ open_buffer() {
// with the old gsg.
DCAST_INTO_R(cocoagsg, _gsg, false);
if (!cocoagsg->get_fb_properties().subsumes(_fb_properties)) {
cocoagsg = new CocoaGraphicsStateGuardian(_engine, _pipe, cocoagsg);
cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, cocoagsg);
cocoagsg->choose_pixel_format(_fb_properties, cocoa_pipe->get_display_id(), false);
_gsg = cocoagsg;
}
@ -153,11 +153,11 @@ open_buffer() {
/**
* Closes the buffer right now. Called from the window thread.
*/
void CocoaGraphicsBuffer::
void CocoaGLGraphicsBuffer::
close_buffer() {
if (_gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
CocoaGLGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGLGraphicsStateGuardian, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();

View File

@ -0,0 +1,12 @@
/**
* 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 cocoaGLGraphicsPipe.I
* @author rdb
* @date 2023-03-20
*/

View File

@ -0,0 +1,65 @@
/**
* 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 cocoaGLGraphicsPipe.h
* @author rdb
* @date 2023-03-20
*/
#ifndef COCOAGLGRAPHICSPIPE_H
#define COCOAGLGRAPHICSPIPE_H
#include "cocoaGraphicsPipe.h"
class FrameBufferProperties;
/**
* This graphics pipe represents the interface for creating OpenGL graphics
* windows on a Cocoa-based (e.g. Mac OS X) client.
*/
class EXPCL_PANDA_COCOAGLDISPLAY CocoaGLGraphicsPipe : public CocoaGraphicsPipe {
public:
CocoaGLGraphicsPipe(CGDirectDisplayID display = CGMainDisplayID());
virtual ~CocoaGLGraphicsPipe();
virtual std::string get_interface_name() const;
static PT(GraphicsPipe) pipe_constructor();
protected:
virtual PT(GraphicsOutput) make_output(const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsEngine *engine,
GraphicsStateGuardian *gsg,
GraphicsOutput *host,
int retry,
bool &precertify);
virtual PT(GraphicsStateGuardian) make_callback_gsg(GraphicsEngine *engine);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CocoaGraphicsPipe::init_type();
register_type(_type_handle, "CocoaGLGraphicsPipe",
CocoaGraphicsPipe::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cocoaGLGraphicsPipe.I"
#endif

View File

@ -0,0 +1,150 @@
/**
* 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 cocoaGLGraphicsPipe.mm
* @author rdb
* @date 2023-03-20
*/
#include "cocoaGLGraphicsPipe.h"
#include "cocoaGLGraphicsBuffer.h"
#include "cocoaGLGraphicsWindow.h"
#include "cocoaGLGraphicsStateGuardian.h"
#include "config_cocoagldisplay.h"
#include "frameBufferProperties.h"
TypeHandle CocoaGLGraphicsPipe::_type_handle;
/**
* Takes a CoreGraphics display ID, which defaults to the main display.
*/
CocoaGLGraphicsPipe::
CocoaGLGraphicsPipe(CGDirectDisplayID display) : CocoaGraphicsPipe(display) {
_supported_types = OT_window | OT_buffer | OT_texture_buffer;
_is_valid = true;
}
/**
*
*/
CocoaGLGraphicsPipe::
~CocoaGLGraphicsPipe() {
}
/**
* 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.
*/
std::string CocoaGLGraphicsPipe::
get_interface_name() const {
return "OpenGL";
}
/**
* This function is passed to the GraphicsPipeSelection object to allow the
* user to make a default CocoaGLGraphicsPipe.
*/
PT(GraphicsPipe) CocoaGLGraphicsPipe::
pipe_constructor() {
return new CocoaGLGraphicsPipe;
}
/**
* Creates a new window on the pipe, if possible.
*/
PT(GraphicsOutput) CocoaGLGraphicsPipe::
make_output(const std::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 nullptr;
}
CocoaGLGraphicsStateGuardian *cocoagsg = nullptr;
if (gsg != nullptr) {
DCAST_INTO_R(cocoagsg, gsg, nullptr);
}
// First thing to try: a CocoaGLGraphicsWindow
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_rtt_cumulative) != 0 ||
(flags & BF_can_bind_color) != 0 ||
(flags & BF_can_bind_every) != 0 ||
(flags & BF_can_bind_layered) != 0) {
return nullptr;
}
return new CocoaGLGraphicsWindow(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
// Second thing to try: a GLGraphicsBuffer. This requires a context, so if
// we don't have a host window, we instead create a CocoaGLGraphicsBuffer,
// which wraps around GLGraphicsBuffer and manages a context.
if (retry == 1) {
if (!gl_support_fbo ||
(flags & (BF_require_parasite | BF_require_window)) != 0) {
return nullptr;
}
// 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() ||
fb_prop.get_back_buffers() > 0 ||
fb_prop.get_accum_bits() > 0) {
return nullptr;
}
}
if (cocoagsg != nullptr && cocoagsg->is_valid() && !cocoagsg->needs_reset()) {
if (!cocoagsg->_supports_framebuffer_object ||
cocoagsg->_glDrawBuffers == nullptr) {
return nullptr;
}
else if (fb_prop.is_basic()) {
// Early success - if we are sure that this buffer WILL meet specs, we
// can precertify it.
precertify = true;
}
}
if (host != nullptr) {
return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
} else {
return new CocoaGLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
}
// Nothing else left to try.
return nullptr;
}
/**
* This is called when make_output() is used to create a
* CallbackGraphicsWindow. If the GraphicsPipe can construct a GSG that's not
* associated with any particular window object, do so now, assuming the
* correct graphics context has been set up externally.
*/
PT(GraphicsStateGuardian) CocoaGLGraphicsPipe::
make_callback_gsg(GraphicsEngine *engine) {
return new CocoaGLGraphicsStateGuardian(engine, this, nullptr);
}

View File

@ -6,7 +6,7 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsStateGuardian.I
* @file cocoaGLGraphicsStateGuardian.I
* @author rdb
* @date 2012-05-14
*/
@ -15,7 +15,7 @@
* Gets the FrameBufferProperties for all windows and buffers that use this
* GSG.
*/
INLINE const FrameBufferProperties &CocoaGraphicsStateGuardian::
INLINE const FrameBufferProperties &CocoaGLGraphicsStateGuardian::
get_fb_properties() const {
return _fbprops;
}
@ -23,7 +23,7 @@ get_fb_properties() const {
/**
* Locks the context.
*/
INLINE void CocoaGraphicsStateGuardian::
INLINE void CocoaGLGraphicsStateGuardian::
lock_context() {
nassertv(_context != nil);
CGLLockContext((CGLContextObj) [_context CGLContextObj]);
@ -32,7 +32,7 @@ lock_context() {
/**
* Unlocks the context.
*/
INLINE void CocoaGraphicsStateGuardian::
INLINE void CocoaGLGraphicsStateGuardian::
unlock_context() {
nassertv(_context != nil);
CGLUnlockContext((CGLContextObj) [_context CGLContextObj]);

View File

@ -6,13 +6,13 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsStateGuardian.h
* @file cocoaGLGraphicsStateGuardian.h
* @author rdb
* @date 2012-05-14
*/
#ifndef COCOAGRAPHICSSTATEGUARDIAN_H
#define COCOAGRAPHICSSTATEGUARDIAN_H
#ifndef COCOAGLGRAPHICSSTATEGUARDIAN_H
#define COCOAGLGRAPHICSSTATEGUARDIAN_H
#include "pandabase.h"
#include "cocoaGraphicsPipe.h"
@ -26,7 +26,7 @@
* A tiny specialization on GLGraphicsStateGuardian to add some Cocoa-specific
* information.
*/
class EXPCL_PANDA_COCOADISPLAY CocoaGraphicsStateGuardian : public GLGraphicsStateGuardian {
class EXPCL_PANDA_COCOAGLDISPLAY CocoaGLGraphicsStateGuardian : public GLGraphicsStateGuardian {
public:
INLINE const FrameBufferProperties &get_fb_properties() const;
void get_properties(FrameBufferProperties &properties,
@ -35,10 +35,10 @@ public:
CGDirectDisplayID display,
bool need_pbuffer);
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGraphicsStateGuardian *share_with);
CocoaGLGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGLGraphicsStateGuardian *share_with);
virtual ~CocoaGraphicsStateGuardian();
virtual ~CocoaGLGraphicsStateGuardian();
bool setup_vsync();
INLINE void lock_context();
@ -64,7 +64,7 @@ public:
}
static void init_type() {
GLGraphicsStateGuardian::init_type();
register_type(_type_handle, "CocoaGraphicsStateGuardian",
register_type(_type_handle, "CocoaGLGraphicsStateGuardian",
GLGraphicsStateGuardian::get_class_type());
}
virtual TypeHandle get_type() const {
@ -76,6 +76,6 @@ private:
static TypeHandle _type_handle;
};
#include "cocoaGraphicsStateGuardian.I"
#include "cocoaGLGraphicsStateGuardian.I"
#endif

View File

@ -6,12 +6,12 @@
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cocoaGraphicsStateGuardian.mm
* @file cocoaGLGraphicsStateGuardian.mm
* @author rdb
* @date 2012-05-14
*/
#include "cocoaGraphicsStateGuardian.h"
#include "cocoaGLGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#include "lightReMutexHolder.h"
@ -30,34 +30,34 @@
/**
* Called whenever a display wants a frame. The context argument contains the
* applicable CocoaGraphicsStateGuardian.
* applicable CocoaGLGraphicsStateGuardian.
*/
static CVReturn
display_link_cb(CVDisplayLinkRef link, const CVTimeStamp *now,
const CVTimeStamp* output_time, CVOptionFlags flags_in,
CVOptionFlags *flags_out, void *context) {
CocoaGraphicsStateGuardian *gsg = (CocoaGraphicsStateGuardian *)context;
CocoaGLGraphicsStateGuardian *gsg = (CocoaGLGraphicsStateGuardian *)context;
gsg->_swap_lock.lock();
gsg->_swap_condition.notify();
gsg->_swap_lock.unlock();
return kCVReturnSuccess;
}
TypeHandle CocoaGraphicsStateGuardian::_type_handle;
TypeHandle CocoaGLGraphicsStateGuardian::_type_handle;
/**
*
*/
CocoaGraphicsStateGuardian::
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGraphicsStateGuardian *share_with) :
CocoaGLGraphicsStateGuardian::
CocoaGLGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGLGraphicsStateGuardian *share_with) :
GLGraphicsStateGuardian(engine, pipe),
_swap_condition(_swap_lock)
{
_share_context = nil;
_context = nil;
if (share_with != (CocoaGraphicsStateGuardian *)NULL) {
if (share_with != (CocoaGLGraphicsStateGuardian *)NULL) {
_prepared_objects = share_with->get_prepared_objects();
_share_context = share_with->_context;
}
@ -66,8 +66,8 @@ CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
/**
*
*/
CocoaGraphicsStateGuardian::
~CocoaGraphicsStateGuardian() {
CocoaGLGraphicsStateGuardian::
~CocoaGLGraphicsStateGuardian() {
if (_format != nil) {
[_format release];
}
@ -88,7 +88,7 @@ CocoaGraphicsStateGuardian::
* Creates a CVDisplayLink, which tells us when the display the window is on
* will want a frame.
*/
bool CocoaGraphicsStateGuardian::
bool CocoaGLGraphicsStateGuardian::
setup_vsync() {
if (_display_link != nil) {
// Already set up.
@ -125,7 +125,7 @@ setup_vsync() {
/**
* Gets the FrameBufferProperties to match the indicated config.
*/
void CocoaGraphicsStateGuardian::
void CocoaGLGraphicsStateGuardian::
get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_format, int screen) {
properties.clear();
@ -210,7 +210,7 @@ get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_for
* 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::
void CocoaGLGraphicsStateGuardian::
choose_pixel_format(const FrameBufferProperties &properties,
CGDirectDisplayID display,
bool need_pbuffer) {
@ -357,7 +357,7 @@ choose_pixel_format(const FrameBufferProperties &properties,
/**
* Queries the runtime version of OpenGL in use.
*/
void CocoaGraphicsStateGuardian::
void CocoaGLGraphicsStateGuardian::
query_gl_version() {
GLGraphicsStateGuardian::query_gl_version();
@ -381,7 +381,7 @@ query_gl_version() {
* 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::
void *CocoaGLGraphicsStateGuardian::
do_get_extension_func(const char *name) {
char* fullname = (char*) malloc(strlen(name) + 2);
strcpy(fullname + 1, name);

View File

@ -0,0 +1,12 @@
/**
* 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 cocoaGLGraphicsWindow.I
* @author rdb
* @date 2023-03-18
*/

View File

@ -0,0 +1,66 @@
/**
* 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 cocoaGLGraphicsWindow.h
* @author rdb
* @date 2023-03-18
*/
#ifndef COCOAGLGRAPHICSWINDOW_H
#define COCOAGLGRAPHICSWINDOW_H
#include "cocoaGraphicsWindow.h"
/**
*
*/
class EXPCL_PANDA_COCOADISPLAY CocoaGLGraphicsWindow : public CocoaGraphicsWindow {
public:
CocoaGLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host);
virtual ~CocoaGLGraphicsWindow();
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
virtual void end_flip();
virtual void update_context();
virtual void unbind_context();
protected:
virtual bool open_window();
private:
bool _vsync_enabled = false;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CocoaGraphicsWindow::init_type();
register_type(_type_handle, "CocoaGLGraphicsWindow",
CocoaGraphicsWindow::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cocoaGLGraphicsWindow.I"
#endif

View File

@ -0,0 +1,274 @@
/**
* 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 cocoaGLGraphicsWindow.mm
* @author rdb
* @date 2023-03-18
*/
#include "cocoaGLGraphicsWindow.h"
#include "cocoaGLGraphicsStateGuardian.h"
#include "config_cocoadisplay.h"
#import <OpenGL/OpenGL.h>
TypeHandle CocoaGLGraphicsWindow::_type_handle;
/**
*
*/
CocoaGLGraphicsWindow::
CocoaGLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
const std::string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host) :
CocoaGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
{
}
/**
*
*/
CocoaGLGraphicsWindow::
~CocoaGLGraphicsWindow() {
}
/**
* This function will be called within the draw thread before beginning
* rendering for a given frame. It should do whatever setup is required, and
* return true if the frame should be rendered, or false if it should be
* skipped.
*/
bool CocoaGLGraphicsWindow::
begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == nullptr) {
return false;
}
CocoaGLGraphicsStateGuardian *cocoagsg;
DCAST_INTO_R(cocoagsg, _gsg, false);
nassertr(cocoagsg->_context != nil, false);
nassertr(_view != nil, false);
// Place a lock on the context.
cocoagsg->lock_context();
// Set the drawable.
// Although not recommended, it is technically possible to use the same
// context with multiple different-sized windows. If that happens, the
// context needs to be updated accordingly.
if ([cocoagsg->_context view] != _view) {
// XXX I'm not 100% sure that changing the view requires it to update.
_context_needs_update = true;
[cocoagsg->_context setView:_view];
if (cocoadisplay_cat.is_spam()) {
cocoadisplay_cat.spam()
<< "Switching context to view " << _view << "\n";
}
}
// Update the context if necessary, to make it reallocate buffers etc.
if (_context_needs_update) {
if ([NSThread isMainThread]) {
[cocoagsg->_context update];
_context_needs_update = false;
} else {
cocoagsg->unlock_context();
return false;
}
}
// Lock the view for drawing.
if (!_properties.get_fullscreen()) {
nassertr_always([_view lockFocusIfCanDraw], false);
}
// Make the context current.
[cocoagsg->_context makeCurrentContext];
// Now that we have made the context current to a window, we can reset the
// GSG state if this is the first time it has been used. (We can't just
// call reset() when we construct the GSG, because reset() requires having a
// current context.)
cocoagsg->reset_if_new();
if (mode == FM_render) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame(current_thread);
}
/**
* This function will be called within the draw thread after rendering is
* completed for a given frame. It should do whatever finalization is
* required.
*/
void CocoaGLGraphicsWindow::
end_frame(FrameMode mode, Thread *current_thread) {
end_frame_spam(mode);
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
if (!_properties.get_fullscreen()) {
[_view unlockFocus];
}
// Release the context.
CocoaGLGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
cocoagsg->unlock_context();
if (mode == FM_render) {
// end_render_texture();
copy_to_textures();
}
_gsg->end_frame(current_thread);
if (mode == FM_render) {
trigger_flip();
clear_cube_map_selection();
}
}
/**
* This function will be called within the draw thread after begin_flip() has
* been called on all windows, to finish the exchange of the front and back
* buffers.
*
* This should cause the window to wait for the flip, if necessary.
*/
void CocoaGLGraphicsWindow::
end_flip() {
if (_gsg != nullptr && _flip_ready) {
CocoaGLGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
if (_vsync_enabled) {
AtomicAdjust::Integer cur_frame = ClockObject::get_global_clock()->get_frame_count();
if (AtomicAdjust::set(cocoagsg->_last_wait_frame, cur_frame) != cur_frame) {
cocoagsg->_swap_lock.lock();
cocoagsg->_swap_condition.wait();
cocoagsg->_swap_lock.unlock();
}
}
cocoagsg->lock_context();
// Swap the front and back buffer.
[cocoagsg->_context flushBuffer];
[[_view window] flushWindow];
cocoagsg->unlock_context();
}
GraphicsWindow::end_flip();
}
/**
* Opens the window right now. Called from the window thread. Returns true
* if the window is successfully opened, or false if there was a problem.
*/
bool CocoaGLGraphicsWindow::
open_window() {
// GSG CreationInitialization
CocoaGLGraphicsStateGuardian *cocoagsg;
if (_gsg == nullptr) {
// There is no old gsg. Create a new one.
cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, nullptr);
cocoagsg->choose_pixel_format(_fb_properties, _display, false);
_gsg = cocoagsg;
} else {
// If the old gsg has the wrong pixel format, create a new one that shares
// with the old gsg.
DCAST_INTO_R(cocoagsg, _gsg, false);
if (!cocoagsg->get_fb_properties().subsumes(_fb_properties)) {
cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, cocoagsg);
cocoagsg->choose_pixel_format(_fb_properties, _display, false);
_gsg = cocoagsg;
}
}
if (cocoagsg->_context == nil) {
// Could not obtain a proper context.
_gsg.clear();
close_window();
return false;
}
if (!CocoaGraphicsWindow::open_window()) {
return false;
}
// Make the context current.
cocoagsg->lock_context();
_context_needs_update = false;
[cocoagsg->_context makeCurrentContext];
[cocoagsg->_context setView:_view];
[cocoagsg->_context update];
cocoagsg->reset_if_new();
cocoagsg->unlock_context();
if (!cocoagsg->is_valid()) {
close_window();
return false;
}
if (!cocoagsg->get_fb_properties().verify_hardware_software
(_fb_properties, cocoagsg->get_gl_renderer())) {
close_window();
return false;
}
_fb_properties = cocoagsg->get_fb_properties();
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
return true;
}
/**
* Updates the context.
*/
void CocoaGLGraphicsWindow::
update_context() {
CocoaGLGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGLGraphicsStateGuardian, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();
_context_needs_update = false;
[cocoagsg->_context update];
cocoagsg->unlock_context();
}
}
/**
* Unbinds the context from the window.
*/
void CocoaGLGraphicsWindow::
unbind_context() {
CocoaGLGraphicsStateGuardian *cocoagsg;
cocoagsg = DCAST(CocoaGLGraphicsStateGuardian, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();
[cocoagsg->_context clearDrawable];
cocoagsg->unlock_context();
}
}

View File

@ -0,0 +1,21 @@
/**
* 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 config_cocoagldisplay.h
* @author rdb
* @date 2023-03-20
*/
#ifndef CONFIG_COCOAGLDISPLAY_H
#define CONFIG_COCOAGLDISPLAY_H
#include "config_cocoadisplay.h"
extern EXPCL_PANDA_COCOAGLDISPLAY void init_libcocoagldisplay();
#endif

View File

@ -0,0 +1,60 @@
/**
* 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 config_cocoagldisplay.mm
* @author rdb
* @date 2023-03-20
*/
#include "config_cocoagldisplay.h"
#include "cocoaGLGraphicsBuffer.h"
#include "cocoaGLGraphicsPipe.h"
#include "cocoaGLGraphicsStateGuardian.h"
#include "cocoaGLGraphicsWindow.h"
#include "graphicsPipeSelection.h"
#include "dconfig.h"
#include "pandaSystem.h"
#if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_PANDA_COCOAGLDISPLAY)
#error Buildsystem error: BUILDING_PANDA_COCOAGLDISPLAY not defined
#endif
Configure(config_cocoagldisplay);
ConfigureFn(config_cocoagldisplay) {
init_libcocoagldisplay();
}
/**
* Initializes the library. This must be called at least once before any of
* the functions or classes in this library can be used. Normally it will be
* called by the static initializers and need not be called explicitly, but
* special cases exist.
*/
void
init_libcocoagldisplay() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
init_libcocoadisplay();
CocoaGLGraphicsBuffer::init_type();
CocoaGLGraphicsPipe::init_type();
CocoaGLGraphicsStateGuardian::init_type();
CocoaGLGraphicsWindow::init_type();
GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr();
selection->add_pipe_type(CocoaGLGraphicsPipe::get_class_type(),
CocoaGLGraphicsPipe::pipe_constructor);
PandaSystem *ps = PandaSystem::get_global_ptr();
ps->set_system_tag("OpenGL", "window_system", "Cocoa");
}

View File

@ -0,0 +1,5 @@
#include "cocoaGLGraphicsBuffer.mm"
#include "cocoaGLGraphicsPipe.mm"
#include "cocoaGLGraphicsStateGuardian.mm"
#include "cocoaGLGraphicsWindow.mm"
#include "config_cocoagldisplay.mm"

View File

@ -111,6 +111,7 @@
/* BUILDING_PANDAGL for these: */
#ifdef BUILDING_PANDAGL
#define BUILDING_PANDA_COCOADISPLAY
#define BUILDING_PANDA_COCOAGLDISPLAY
#define BUILDING_PANDA_GLGSG
#define BUILDING_PANDA_GLXDISPLAY
#define BUILDING_PANDA_WGLDISPLAY
@ -162,6 +163,14 @@
#define EXPTP_PANDA_COCOADISPLAY IMPORT_TEMPL
#endif
#ifdef BUILDING_PANDA_COCOAGLDISPLAY
#define EXPCL_PANDA_COCOAGLDISPLAY EXPORT_CLASS
#define EXPTP_PANDA_COCOAGLDISPLAY EXPORT_TEMPL
#else
#define EXPCL_PANDA_COCOAGLDISPLAY IMPORT_CLASS
#define EXPTP_PANDA_COCOAGLDISPLAY IMPORT_TEMPL
#endif
#ifdef BUILDING_PANDA_COLLIDE
#define EXPCL_PANDA_COLLIDE EXPORT_CLASS
#define EXPTP_PANDA_COLLIDE EXPORT_TEMPL