diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 2a7a938942..f826530605 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -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) diff --git a/panda/CMakeLists.txt b/panda/CMakeLists.txt index a49a9b664a..72f5628ba2 100644 --- a/panda/CMakeLists.txt +++ b/panda/CMakeLists.txt @@ -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) diff --git a/panda/metalibs/pandagl/CMakeLists.txt b/panda/metalibs/pandagl/CMakeLists.txt index f3bd4e8db9..d138376b37 100644 --- a/panda/metalibs/pandagl/CMakeLists.txt +++ b/panda/metalibs/pandagl/CMakeLists.txt @@ -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 diff --git a/panda/metalibs/pandagl/pandagl.cxx b/panda/metalibs/pandagl/pandagl.cxx index f4bbee47fa..dfed9f2ba2 100644 --- a/panda/metalibs/pandagl/pandagl.cxx +++ b/panda/metalibs/pandagl/pandagl.cxx @@ -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 diff --git a/panda/src/cocoadisplay/CMakeLists.txt b/panda/src/cocoadisplay/CMakeLists.txt index 92565f273d..9f1d23dc53 100644 --- a/panda/src/cocoadisplay/CMakeLists.txt +++ b/panda/src/cocoadisplay/CMakeLists.txt @@ -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() diff --git a/panda/src/cocoadisplay/cocoaGraphicsPipe.h b/panda/src/cocoadisplay/cocoaGraphicsPipe.h index 902d673047..420d2e6a01 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsPipe.h +++ b/panda/src/cocoadisplay/cocoaGraphicsPipe.h @@ -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 -#else -struct NSScreen; -#endif #include -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; diff --git a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm index 80a960938c..87044c2739 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm @@ -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 @@ -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); -} diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.h b/panda/src/cocoadisplay/cocoaGraphicsWindow.h index 13aee0e5b0..19b9b6004a 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.h +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.h @@ -19,11 +19,21 @@ #include "cocoaGraphicsPipe.h" #include "graphicsWindow.h" +#ifdef __OBJC__ #import #import #import - #import +#else +#include +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; diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index 00a625f29f..0a5bde1f1d 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -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 #import #import -#import #import 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 diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm.rej b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm.rej new file mode 100644 index 0000000000..ae6fcbf2a4 --- /dev/null +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm.rej @@ -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 diff --git a/panda/src/cocoadisplay/cocoaPandaView.h b/panda/src/cocoadisplay/cocoaPandaView.h index 819b088ff7..af87ad1274 100644 --- a/panda/src/cocoadisplay/cocoaPandaView.h +++ b/panda/src/cocoadisplay/cocoaPandaView.h @@ -14,18 +14,15 @@ #include "graphicsWindow.h" #import -#import 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; diff --git a/panda/src/cocoadisplay/cocoaPandaView.mm b/panda/src/cocoadisplay/cocoaPandaView.mm index f501592aa2..f86f4f93b5 100644 --- a/panda/src/cocoadisplay/cocoaPandaView.mm +++ b/panda/src/cocoadisplay/cocoaPandaView.mm @@ -18,10 +18,9 @@ #include @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 diff --git a/panda/src/cocoadisplay/config_cocoadisplay.mm b/panda/src/cocoadisplay/config_cocoadisplay.mm index a79144769b..17688586c2 100644 --- a/panda/src/cocoadisplay/config_cocoadisplay.mm +++ b/panda/src/cocoadisplay/config_cocoadisplay.mm @@ -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"); } diff --git a/panda/src/cocoadisplay/p3cocoadisplay_composite1.mm b/panda/src/cocoadisplay/p3cocoadisplay_composite1.mm index 335443fab1..8aabfe5c70 100644 --- a/panda/src/cocoadisplay/p3cocoadisplay_composite1.mm +++ b/panda/src/cocoadisplay/p3cocoadisplay_composite1.mm @@ -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" diff --git a/panda/src/cocoagldisplay/CMakeLists.txt b/panda/src/cocoagldisplay/CMakeLists.txt new file mode 100644 index 0000000000..b928eb52f3 --- /dev/null +++ b/panda/src/cocoagldisplay/CMakeLists.txt @@ -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() diff --git a/panda/src/cocoadisplay/cocoaGraphicsBuffer.I b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.I similarity index 90% rename from panda/src/cocoadisplay/cocoaGraphicsBuffer.I rename to panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.I index 1611af94d1..3b9e7686b3 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsBuffer.I +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.I @@ -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 */ diff --git a/panda/src/cocoadisplay/cocoaGraphicsBuffer.h b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.h similarity index 67% rename from panda/src/cocoadisplay/cocoaGraphicsBuffer.h rename to panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.h index 8485540fdc..ea3a63eb3a 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsBuffer.h +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.h @@ -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 diff --git a/panda/src/cocoadisplay/cocoaGraphicsBuffer.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm similarity index 85% rename from panda/src/cocoadisplay/cocoaGraphicsBuffer.mm rename to panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm index f45837ed87..3632becb0b 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsBuffer.mm +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm @@ -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 -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(); diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.I b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.I new file mode 100644 index 0000000000..b5d68b63b8 --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.I @@ -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 + */ diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.h b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.h new file mode 100644 index 0000000000..fb15557cf9 --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.h @@ -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 diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm new file mode 100644 index 0000000000..7ad1317b0b --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm @@ -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); +} diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.I b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.I similarity index 79% rename from panda/src/cocoadisplay/cocoaGraphicsStateGuardian.I rename to panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.I index 586df26850..22d98c9320 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.I +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.I @@ -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]); diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.h b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.h similarity index 78% rename from panda/src/cocoadisplay/cocoaGraphicsStateGuardian.h rename to panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.h index 0463372b8e..4527648c7c 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.h +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.h @@ -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 diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.mm similarity index 94% rename from panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm rename to panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.mm index 7ffdc23729..9f8de82705 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsStateGuardian.mm @@ -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); diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.I b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.I new file mode 100644 index 0000000000..227f8d774b --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.I @@ -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 + */ diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.h b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.h new file mode 100644 index 0000000000..85d0416c94 --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.h @@ -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 diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm new file mode 100644 index 0000000000..c1e1821226 --- /dev/null +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm @@ -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 + +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(); + } +} diff --git a/panda/src/cocoagldisplay/config_cocoagldisplay.h b/panda/src/cocoagldisplay/config_cocoagldisplay.h new file mode 100644 index 0000000000..1edc192ca4 --- /dev/null +++ b/panda/src/cocoagldisplay/config_cocoagldisplay.h @@ -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 diff --git a/panda/src/cocoagldisplay/config_cocoagldisplay.mm b/panda/src/cocoagldisplay/config_cocoagldisplay.mm new file mode 100644 index 0000000000..c2cadb9916 --- /dev/null +++ b/panda/src/cocoagldisplay/config_cocoagldisplay.mm @@ -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"); +} diff --git a/panda/src/cocoagldisplay/p3cocoagldisplay_composite1.mm b/panda/src/cocoagldisplay/p3cocoagldisplay_composite1.mm new file mode 100644 index 0000000000..138abdc4c0 --- /dev/null +++ b/panda/src/cocoagldisplay/p3cocoagldisplay_composite1.mm @@ -0,0 +1,5 @@ +#include "cocoaGLGraphicsBuffer.mm" +#include "cocoaGLGraphicsPipe.mm" +#include "cocoaGLGraphicsStateGuardian.mm" +#include "cocoaGLGraphicsWindow.mm" +#include "config_cocoagldisplay.mm" diff --git a/panda/src/pandabase/pandasymbols.h b/panda/src/pandabase/pandasymbols.h index edd5e40fda..ee061bda9a 100644 --- a/panda/src/pandabase/pandasymbols.h +++ b/panda/src/pandabase/pandasymbols.h @@ -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