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') CopyAllHeaders('panda/src/wgldisplay')
elif GetTarget() == 'darwin': elif GetTarget() == 'darwin':
CopyAllHeaders('panda/src/cocoadisplay') CopyAllHeaders('panda/src/cocoadisplay')
if not PkgSkip('GL'):
CopyAllHeaders('panda/src/cocoagldisplay')
elif GetTarget() == 'android': elif GetTarget() == 'android':
CopyAllHeaders('panda/src/android') CopyAllHeaders('panda/src/android')
CopyAllHeaders('panda/src/androiddisplay') 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/ # DIRECTORY: panda/src/cocoadisplay/
# #
if GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and not PkgSkip("GL"): if GetTarget() == 'darwin' and not PkgSkip("COCOA"):
OPTS=['DIR:panda/src/cocoadisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] OPTS=['DIR:panda/src/cocoadisplay', 'BUILDING:PANDAGL', 'COCOA']
TargetAdd('p3cocoadisplay_composite1.obj', opts=OPTS, input='p3cocoadisplay_composite1.mm') 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'] OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL']
TargetAdd('pandagl_pandagl.obj', opts=OPTS, input='pandagl.cxx') TargetAdd('pandagl_pandagl.obj', opts=OPTS, input='pandagl.cxx')
TargetAdd('libpandagl.dll', input='pandagl_pandagl.obj') TargetAdd('libpandagl.dll', input='pandagl_pandagl.obj')
TargetAdd('libpandagl.dll', input='p3glgsg_config_glgsg.obj') TargetAdd('libpandagl.dll', input='p3glgsg_config_glgsg.obj')
TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj') TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj')
TargetAdd('libpandagl.dll', input='p3cocoadisplay_composite1.obj') TargetAdd('libpandagl.dll', input='p3cocoadisplay_composite1.obj')
TargetAdd('libpandagl.dll', input='p3cocoagldisplay_composite1.obj')
if not PkgSkip('PANDAFX'): if not PkgSkip('PANDAFX'):
TargetAdd('libpandagl.dll', input='libpandafx.dll') TargetAdd('libpandagl.dll', input='libpandafx.dll')
TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS) TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)

View File

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

View File

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

View File

@ -13,9 +13,9 @@
#include "wglGraphicsPipe.h" #include "wglGraphicsPipe.h"
#endif #endif
#if defined(HAVE_COCOA) #ifdef HAVE_COCOA
#include "config_cocoadisplay.h" #include "config_cocoagldisplay.h"
#include "cocoaGraphicsPipe.h" #include "cocoaGLGraphicsPipe.h"
#endif #endif
#ifdef HAVE_GLX #ifdef HAVE_GLX
@ -46,8 +46,8 @@ init_libpandagl() {
init_libwgldisplay(); init_libwgldisplay();
#endif // HAVE_GL #endif // HAVE_GL
#if defined(HAVE_COCOA) #ifdef HAVE_COCOA
init_libcocoadisplay(); init_libcocoagldisplay();
#endif #endif
#ifdef HAVE_GLX #ifdef HAVE_GLX
@ -69,8 +69,8 @@ get_pipe_type_pandagl() {
return wglGraphicsPipe::get_class_type().get_index(); return wglGraphicsPipe::get_class_type().get_index();
#endif #endif
#if defined(HAVE_COCOA) #ifdef HAVE_COCOA
return CocoaGraphicsPipe::get_class_type().get_index(); return CocoaGLGraphicsPipe::get_class_type().get_index();
#endif #endif
#ifdef HAVE_GLX #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() return()
endif() endif()
set(P3COCOADISPLAY_HEADERS set(P3COCOADISPLAY_HEADERS
config_cocoadisplay.h config_cocoadisplay.h
cocoaGraphicsBuffer.h cocoaGraphicsBuffer.I
cocoaGraphicsPipe.h cocoaGraphicsPipe.I cocoaGraphicsPipe.h cocoaGraphicsPipe.I
cocoaGraphicsWindow.h cocoaGraphicsWindow.I cocoaGraphicsWindow.h cocoaGraphicsWindow.I
cocoaGraphicsStateGuardian.h cocoaGraphicsStateGuardian.I
cocoaPandaApp.h cocoaPandaApp.h
cocoaPandaView.h cocoaPandaView.h
cocoaPandaWindow.h cocoaPandaWindow.h
@ -17,9 +15,7 @@ set(P3COCOADISPLAY_HEADERS
set(P3COCOADISPLAY_SOURCES set(P3COCOADISPLAY_SOURCES
config_cocoadisplay.mm config_cocoadisplay.mm
cocoaGraphicsBuffer.mm
cocoaGraphicsPipe.mm cocoaGraphicsPipe.mm
cocoaGraphicsStateGuardian.mm
cocoaGraphicsWindow.mm cocoaGraphicsWindow.mm
cocoaPandaApp.mm cocoaPandaApp.mm
cocoaPandaView.mm cocoaPandaView.mm
@ -31,7 +27,7 @@ set(P3COCOADISPLAY_SOURCES
composite_sources(p3cocoadisplay P3COCOADISPLAY_SOURCES) composite_sources(p3cocoadisplay P3COCOADISPLAY_SOURCES)
add_component_library(p3cocoadisplay SYMBOL BUILDING_PANDA_COCOADISPLAY add_component_library(p3cocoadisplay SYMBOL BUILDING_PANDA_COCOADISPLAY
${P3COCOADISPLAY_HEADERS} ${P3COCOADISPLAY_SOURCES}) ${P3COCOADISPLAY_HEADERS} ${P3COCOADISPLAY_SOURCES})
target_link_libraries(p3cocoadisplay p3glgsg panda) target_link_libraries(p3cocoadisplay panda)
# Frameworks: # Frameworks:
find_library(APPLICATIONSERVICES_LIBRARY ApplicationServices) find_library(APPLICATIONSERVICES_LIBRARY ApplicationServices)
@ -46,5 +42,5 @@ mark_as_advanced(
APPLICATIONSERVICES_LIBRARY APPKIT_LIBRARY CARBON_LIBRARY CORE_VIDEO_LIBRARY) APPLICATIONSERVICES_LIBRARY APPKIT_LIBRARY CARBON_LIBRARY CORE_VIDEO_LIBRARY)
if(NOT BUILD_METALIBS) 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() endif()

View File

@ -15,22 +15,12 @@
#define COCOAGRAPHICSPIPE_H #define COCOAGRAPHICSPIPE_H
#include "pandabase.h" #include "pandabase.h"
#include "graphicsWindow.h"
#include "graphicsPipe.h" #include "graphicsPipe.h"
#include "lightMutex.h"
#include "lightReMutex.h"
#ifdef __OBJC__
#import <AppKit/NSScreen.h>
#else
struct NSScreen;
#endif
#include <ApplicationServices/ApplicationServices.h> #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. * windows on a Cocoa-based (e.g. Mac OS X) client.
*/ */
class EXPCL_PANDA_COCOADISPLAY CocoaGraphicsPipe : public GraphicsPipe { class EXPCL_PANDA_COCOADISPLAY CocoaGraphicsPipe : public GraphicsPipe {
@ -40,32 +30,15 @@ public:
INLINE CGDirectDisplayID get_display_id() const; INLINE CGDirectDisplayID get_display_id() const;
virtual std::string get_interface_name() const;
static PT(GraphicsPipe) pipe_constructor();
public: public:
virtual PreferredWindowThread get_preferred_window_thread() const; 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: private:
void load_display_information(); void load_display_information();
// This is the Quartz display identifier. // This is the Quartz display identifier.
CGDirectDisplayID _display; CGDirectDisplayID _display;
friend class CocoaGraphicsWindow;
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {
return _type_handle; return _type_handle;

View File

@ -12,11 +12,7 @@
*/ */
#include "cocoaGraphicsPipe.h" #include "cocoaGraphicsPipe.h"
#include "cocoaGraphicsBuffer.h"
#include "cocoaGraphicsWindow.h"
#include "cocoaGraphicsStateGuardian.h"
#include "config_cocoadisplay.h" #include "config_cocoadisplay.h"
#include "frameBufferProperties.h"
#include "displayInformation.h" #include "displayInformation.h"
#import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSAutoreleasePool.h>
@ -32,9 +28,6 @@ TypeHandle CocoaGraphicsPipe::_type_handle;
*/ */
CocoaGraphicsPipe:: CocoaGraphicsPipe::
CocoaGraphicsPipe(CGDirectDisplayID display) : _display(display) { CocoaGraphicsPipe(CGDirectDisplayID display) : _display(display) {
_supported_types = OT_window | OT_buffer | OT_texture_buffer;
_is_valid = true;
[[NSAutoreleasePool alloc] init]; [[NSAutoreleasePool alloc] init];
// Put Cocoa into thread-safe mode by spawning a thread which immediately // Put Cocoa into thread-safe mode by spawning a thread which immediately
@ -110,7 +103,7 @@ load_display_information() {
} }
CFRelease(encoding); CFRelease(encoding);
} }
if (modes != NULL) { if (modes != nullptr) {
CFRelease(modes); CFRelease(modes);
} }
@ -135,26 +128,6 @@ CocoaGraphicsPipe::
~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 * Returns an indication of the thread in which this GraphicsPipe requires its
* window processing to be performed: typically either the app thread (e.g. * 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! // only be called from the main thread!
return PWT_app; 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 "cocoaGraphicsPipe.h"
#include "graphicsWindow.h" #include "graphicsWindow.h"
#ifdef __OBJC__
#import <AppKit/NSEvent.h> #import <AppKit/NSEvent.h>
#import <AppKit/NSView.h> #import <AppKit/NSView.h>
#import <AppKit/NSWindow.h> #import <AppKit/NSWindow.h>
#import <CoreVideo/CoreVideo.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 * An interface to the Cocoa system for managing OpenGL windows under Mac OS
@ -41,13 +51,13 @@ public:
virtual ~CocoaGraphicsWindow(); virtual ~CocoaGraphicsWindow();
virtual bool move_pointer(int device, int x, int y); 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 process_events();
virtual void set_properties_now(WindowProperties &properties); virtual void set_properties_now(WindowProperties &properties);
virtual void update_context();
virtual void unbind_context();
void handle_move_event(); void handle_move_event();
void handle_resize_event(); void handle_resize_event();
void handle_minimize_event(bool minimized); void handle_minimize_event(bool minimized);
@ -81,7 +91,7 @@ private:
ButtonHandle map_key(unsigned short c) const; ButtonHandle map_key(unsigned short c) const;
ButtonHandle map_raw_key(unsigned short keycode) const; ButtonHandle map_raw_key(unsigned short keycode) const;
private: protected:
NSWindow *_window; NSWindow *_window;
NSView *_view; NSView *_view;
NSUInteger _modifier_keys; NSUInteger _modifier_keys;
@ -90,7 +100,6 @@ private:
PT(GraphicsWindowInputDevice) _input; PT(GraphicsWindowInputDevice) _input;
bool _mouse_hidden; bool _mouse_hidden;
bool _context_needs_update; bool _context_needs_update;
bool _vsync_enabled = false;
CGDisplayModeRef _fullscreen_mode; CGDisplayModeRef _fullscreen_mode;
CGDisplayModeRef _windowed_mode; CGDisplayModeRef _windowed_mode;

View File

@ -12,7 +12,6 @@
*/ */
#include "cocoaGraphicsWindow.h" #include "cocoaGraphicsWindow.h"
#include "cocoaGraphicsStateGuardian.h"
#include "config_cocoadisplay.h" #include "config_cocoadisplay.h"
#include "cocoaGraphicsPipe.h" #include "cocoaGraphicsPipe.h"
#include "cocoaPandaApp.h" #include "cocoaPandaApp.h"
@ -40,7 +39,6 @@
#import <AppKit/NSImage.h> #import <AppKit/NSImage.h>
#import <AppKit/NSScreen.h> #import <AppKit/NSScreen.h>
#import <AppKit/NSText.h> #import <AppKit/NSText.h>
#import <OpenGL/OpenGL.h>
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
TypeHandle CocoaGraphicsWindow::_type_handle; TypeHandle CocoaGraphicsWindow::_type_handle;
@ -108,7 +106,7 @@ CocoaGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
CocoaGraphicsPipe *cocoa_pipe; CocoaGraphicsPipe *cocoa_pipe;
DCAST_INTO_V(cocoa_pipe, _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; 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 * Do whatever processing is necessary to ensure that the window responds to
* user events. Also, honor any requests recently made via * user events. Also, honor any requests recently made via
@ -351,15 +208,7 @@ process_events() {
[pool release]; [pool release];
if (_context_needs_update && _gsg != nullptr) { if (_context_needs_update && _gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg; update_context();
DCAST_INTO_V(cocoagsg, _gsg);
if (cocoagsg != nullptr && cocoagsg->_context != nil) {
cocoagsg->lock_context();
_context_needs_update = false;
[cocoagsg->_context update];
cocoagsg->unlock_context();
}
} }
} }
@ -369,34 +218,6 @@ process_events() {
*/ */
bool CocoaGraphicsWindow:: bool CocoaGraphicsWindow::
open_window() { 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. // Fill in the blanks.
if (!_properties.has_origin()) { if (!_properties.has_origin()) {
_properties.set_origin(-2, -2); _properties.set_origin(-2, -2);
@ -476,7 +297,7 @@ open_window() {
NSEnumerator *e = [[NSScreen screens] objectEnumerator]; NSEnumerator *e = [[NSScreen screens] objectEnumerator];
while (screen = (NSScreen *) [e nextObject]) { while (screen = (NSScreen *) [e nextObject]) {
NSNumber *num = [[screen deviceDescription] objectForKey: @"NSScreenNumber"]; NSNumber *num = [[screen deviceDescription] objectForKey: @"NSScreenNumber"];
if (cocoa_pipe->_display == (CGDirectDisplayID) [num longValue]) { if (_display == (CGDirectDisplayID) [num longValue]) {
break; 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. // Create the NSView to render to.
NSRect rect = NSMakeRect(0, 0, _properties.get_x_size(), _properties.get_y_size()); NSRect rect = NSMakeRect(0, 0, _properties.get_x_size(), _properties.get_y_size());
_view = [[CocoaPandaView alloc] initWithFrame:rect context:cocoagsg->_context window:this]; _view = [[CocoaPandaView alloc] initWithFrame:rect window:this];
if (_parent_window_handle == (WindowHandle *)NULL) { if (_parent_window_handle == nullptr) {
[_window setContentView:_view]; [_window setContentView:_view];
[_window makeFirstResponder:_view]; [_window makeFirstResponder:_view];
} }
// Check if we have an NSView to attach our NSView to. // Check if we have an NSView to attach our NSView to.
if (parent_nsview != NULL) { if (parent_nsview != nullptr) {
[parent_nsview addSubview:_view]; [parent_nsview addSubview:_view];
} }
@ -566,7 +384,7 @@ open_window() {
_window_handle = NativeWindowHandle::make_int((size_t) _view); _window_handle = NativeWindowHandle::make_int((size_t) _view);
// And tell our parent window that we're now its child. // 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); _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. // Reset dead key state.
_dead_key_state = 0; _dead_key_state = 0;
@ -710,8 +505,6 @@ open_window() {
CGAssociateMouseAndMouseCursorPosition(NO); CGAssociateMouseAndMouseCursorPosition(NO);
} }
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
return true; return true;
} }
@ -730,15 +523,8 @@ close_window() {
_cursor = nil; _cursor = nil;
} }
if (_gsg != (GraphicsStateGuardian *)NULL) { if (_gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg; unbind_context();
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
cocoagsg->lock_context();
[cocoagsg->_context clearDrawable];
cocoagsg->unlock_context();
}
_gsg.clear(); _gsg.clear();
} }
@ -756,8 +542,6 @@ close_window() {
_view = nil; _view = nil;
} }
_vsync_enabled = false;
GraphicsWindow::close_window(); GraphicsWindow::close_window();
} }
@ -1148,16 +932,22 @@ set_properties_now(WindowProperties &properties) {
} }
if (_context_needs_update && _gsg != nullptr) { if (_context_needs_update && _gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg; update_context();
DCAST_INTO_V(cocoagsg, _gsg); }
}
if (cocoagsg != nullptr && cocoagsg->_context != nil) { /**
cocoagsg->lock_context(); *
_context_needs_update = false; */
[cocoagsg->_context update]; void CocoaGraphicsWindow::
cocoagsg->unlock_context(); update_context() {
} }
}
/**
*
*/
void CocoaGraphicsWindow::
unbind_context() {
} }
/** /**
@ -1663,17 +1453,9 @@ handle_close_event() {
_window = nil; _window = nil;
// Get rid of the GSG // Get rid of the GSG
if (_gsg != (GraphicsStateGuardian *)NULL) { if (_gsg != nullptr) {
CocoaGraphicsStateGuardian *cocoagsg; unbind_context();
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
cocoagsg->lock_context();
[cocoagsg->_context clearDrawable];
cocoagsg->unlock_context();
}
_gsg.clear(); _gsg.clear();
_vsync_enabled = false;
} }
// Dump the view, too // 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" #include "graphicsWindow.h"
#import <AppKit/NSView.h> #import <AppKit/NSView.h>
#import <AppKit/NSOpenGL.h>
class CocoaGraphicsWindow; class CocoaGraphicsWindow;
@interface CocoaPandaView : NSView { @interface CocoaPandaView : NSView {
@private @private
NSOpenGLContext *_context;
CocoaGraphicsWindow *_graphicsWindow; CocoaGraphicsWindow *_graphicsWindow;
} }
- (id) initWithFrame:(NSRect)frameRect context:(NSOpenGLContext*)context window:(CocoaGraphicsWindow*)window; - (id) initWithFrame:(NSRect)frameRect window:(CocoaGraphicsWindow*)window;
- (NSOpenGLContext*) openGLContext;
- (GraphicsWindow*) graphicsWindow; - (GraphicsWindow*) graphicsWindow;
- (void) drawRect:(NSRect)dirtyRect; - (void) drawRect:(NSRect)dirtyRect;

View File

@ -18,10 +18,9 @@
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
@implementation CocoaPandaView @implementation CocoaPandaView
- (id) initWithFrame:(NSRect)frameRect context:(NSOpenGLContext*)context window:(CocoaGraphicsWindow*)window { - (id) initWithFrame:(NSRect)frameRect window:(CocoaGraphicsWindow*)window {
self = [super initWithFrame: frameRect]; self = [super initWithFrame: frameRect];
_context = context;
[self setCanDrawConcurrently:YES]; [self setCanDrawConcurrently:YES];
// If a layer ends up becoming attached to the view, tell AppKit we'll manage // If a layer ends up becoming attached to the view, tell AppKit we'll manage
@ -37,10 +36,6 @@
return self; return self;
} }
- (NSOpenGLContext*) openGLContext {
return _context;
}
- (GraphicsWindow*) graphicsWindow { - (GraphicsWindow*) graphicsWindow {
return _graphicsWindow; return _graphicsWindow;
} }
@ -170,14 +165,9 @@
return YES; return YES;
} }
-(void)setLayer:(CALayer*)layer -(void)setLayer:(CALayer*)layer {
{
[super setLayer:layer]; [super setLayer:layer];
// Starting in macOS 10.14, a CALayer will still be attached to a view even _graphicsWindow->update_context();
// 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];
} }
@end @end

View File

@ -12,11 +12,8 @@
*/ */
#include "config_cocoadisplay.h" #include "config_cocoadisplay.h"
#include "cocoaGraphicsBuffer.h"
#include "cocoaGraphicsPipe.h" #include "cocoaGraphicsPipe.h"
#include "cocoaGraphicsStateGuardian.h"
#include "cocoaGraphicsWindow.h" #include "cocoaGraphicsWindow.h"
#include "graphicsPipeSelection.h"
#include "dconfig.h" #include "dconfig.h"
#include "pandaSystem.h" #include "pandaSystem.h"
@ -50,15 +47,6 @@ init_libcocoadisplay() {
} }
initialized = true; initialized = true;
CocoaGraphicsBuffer::init_type();
CocoaGraphicsPipe::init_type(); CocoaGraphicsPipe::init_type();
CocoaGraphicsStateGuardian::init_type();
CocoaGraphicsWindow::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 "cocoaGraphicsPipe.mm"
#include "cocoaGraphicsStateGuardian.mm"
#include "cocoaGraphicsWindow.mm" #include "cocoaGraphicsWindow.mm"
#include "cocoaPandaApp.mm" #include "cocoaPandaApp.mm"
#include "cocoaPandaView.mm" #include "cocoaPandaView.mm"
#include "cocoaPandaWindow.mm" #include "cocoaPandaWindow.mm"
#include "cocoaPandaWindowDelegate.mm" #include "cocoaPandaWindowDelegate.mm"
#include "cocoaPandaAppDelegate.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 * license. You should have received a copy of this license along
* with this source code in a file named "LICENSE." * with this source code in a file named "LICENSE."
* *
* @file cocoaGraphicsBuffer.I * @file cocoaGLGraphicsBuffer.I
* @author rdb * @author rdb
* @date 2017-12-19 * @date 2017-12-19
*/ */

View File

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

View File

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

View File

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

View File

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