Skip to content
Snippets Groups Projects
Commit 04ea26f7 authored by Oliver Behnke's avatar Oliver Behnke
Browse files

Merge branch 'mac-iosurface'

parents a3ff8e11 9007986f
Branches
No related tags found
No related merge requests found
......@@ -442,6 +442,9 @@ build_boinc()
cd $ROOT/3rdparty/boinc/mac_build || failure
xcodebuild -project boinc.xcodeproj -target gfx2libboinc -configuration Deployment build >> $LOGFILE 2>&1 || failure
cp $ROOT/3rdparty/boinc/mac_build/build/boinc.build/Deployment/gfx2libboinc.build/DerivedSources/x86_64/*.h $ROOT/build/boinc >> $LOGFILE 2>&1 || failure
echo "Patching BOINC..." | tee -a $LOGFILE
cd $ROOT/3rdparty/boinc/api || failure
patch Makefile.am < $ROOT/patches/boinc_mac_iosurface.patch >> $LOGFILE 2>&1 || failure
cd $ROOT/build/boinc || failure
export CPPFLAGS="-I/sw/include -I/opt/local/include $CPPFLAGS"
$ROOT/3rdparty/boinc/configure --prefix=$ROOT/install --enable-shared=no --enable-static=yes --disable-server --disable-client --with-apple-opengl-framework --enable-install-headers --enable-libraries --disable-manager --disable-fcgi >> $LOGFILE 2>&1 || failure
......@@ -454,6 +457,7 @@ build_boinc()
echo "Fixing up BOINC's incomplete out-of-tree build..." | tee -a $LOGFILE
mkdir -p $ROOT/install/include/boinc >> $LOGFILE 2>&1 || failure
cp $ROOT/build/boinc/config.h $ROOT/install/include/boinc >> $LOGFILE 2>&1 || failure
cp $ROOT/build/boinc/MultiGPUMig*.h $ROOT/install/include/boinc >> $LOGFILE 2>&1 || failure
cp $ROOT/3rdparty/boinc/project_specific_defines.h $ROOT/install/include/boinc >> $LOGFILE 2>&1 || failure
echo "Building BOINC (this may take a while)..." | tee -a $LOGFILE
make >> $LOGFILE 2>&1 || failure
......
diff --git a/api/Makefile.am b/api/Makefile.am
index 383c2afbdf..49b9a03b64 100644
--- a/api/Makefile.am
+++ b/api/Makefile.am
@@ -29,6 +29,8 @@ endif
if OS_DARWIN
graphics2_files += mac_icon.cpp
graphics2_files += macglutfix.m
+ graphics2_files += MultiGPUMigServer.c
+ graphics2_files += MultiGPUMigUser.c
endif
# library for OpenCL apps
#ifndef MAC_IOSURFACE_MANAGER
#define MAC_IOSURFACE_MANAGER
#endif
#ifdef __cplusplus
extern "C" {
#endif
void initMacIOSurface();
void renderMacIOSurfacePre();
bool renderMacIOSurfacePost();
#ifdef __cplusplus
}
#endif
#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
#include <Cocoa/Cocoa.h>
#import <GLKit/GLKit.h>
#include <servers/bootstrap.h>
#import "MultiGPUMig.h"
#import "MultiGPUMigServer.h"
#include "MacIOSurfaceManager.h"
// On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
// display the graphics output of our child graphics apps in our window.
// Code adapted from Apple Developer Tech Support Sample Code MutiGPUIOSurface:
// <https://developer.apple.com/library/content/samplecode/MultiGPUIOSurface>
#define NUM_IOSURFACE_BUFFERS 2
@interface MachServerController : NSObject <NSMachPortDelegate>
{
NSMachPort *serverPort;
NSMachPort *localPort;
uint32_t serverPortName;
uint32_t localPortName;
NSMachPort *clientPort[16];
uint32_t clientPortNames[16];
uint32_t clientPortCount;
}
- (MachServerController *)init;
- (kern_return_t)checkInClient:(mach_port_t)client_port index:(int32_t *)client_index;
- (void)portDied:(NSNotification *)notification;
- (void)sendIOSurfaceMachPortToClients: (uint32_t)index withMachPort:(mach_port_t) iosurface_port;
- (bool)activeClients;
@end
static MachServerController *myserverController;
static uint32_t currentFrameIndex;
static GLsizei w, h;
static IOSurfaceRef ioSurfaceBuffers[NUM_IOSURFACE_BUFFERS];
static mach_port_t ioSurfaceMachPorts[NUM_IOSURFACE_BUFFERS];
static GLuint textureNames[NUM_IOSURFACE_BUFFERS];
static GLuint fboNames[NUM_IOSURFACE_BUFFERS];
static GLuint depthBufferName;
@implementation MachServerController
- (MachServerController *)init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification object:nil];
mach_port_t servicePortNum = MACH_PORT_NULL;
kern_return_t machErr;
char *portName = "edu.berkeley.boincsaver";
machErr = bootstrap_check_in(bootstrap_port, portName, &servicePortNum);
if (machErr != KERN_SUCCESS) {
[NSApp terminate:self];
}
serverPort = (NSMachPort*)[NSMachPort portWithMachPort:servicePortNum];
// Create a local dummy reply port to use with the mig reply stuff
localPort = [[NSMachPort alloc] init];
// Retrieve raw mach port names.
serverPortName = [serverPort machPort];
localPortName = [localPort machPort];
[serverPort setDelegate:self];
[serverPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
return self;
}
- (void)portDied:(NSNotification *)notification
{
NSPort *port = [notification object];
if(port == serverPort)
{
[NSApp terminate:self];
}
else
{
int i;
for(i = 0; i < clientPortCount+1; i++)
{
if([clientPort[i] isEqual:port])
{
[clientPort[i] release];
clientPort[i] = nil;
clientPortNames[i] = 0;
}
}
}
}
- (void)handleMachMessage:(void *)msg
{
union __ReplyUnion___MGCMGSServer_subsystem reply;
mach_msg_header_t *reply_header = (void *)&reply;
kern_return_t kr;
if(MGSServer_server(msg, reply_header) && reply_header->msgh_remote_port != MACH_PORT_NULL)
{
kr = mach_msg(reply_header, MACH_SEND_MSG, reply_header->msgh_size, 0, MACH_PORT_NULL,
0, MACH_PORT_NULL);
if(kr != 0)
[NSApp terminate:nil];
}
}
- (kern_return_t)checkInClient:(mach_port_t)client_port index:(int32_t *)client_index
{
clientPortCount++; // clients always start at index 1
clientPortNames[clientPortCount] = client_port;
clientPort[clientPortCount] = [[NSMachPort alloc] initWithMachPort:client_port];
*client_index = clientPortCount;
return 0;
}
kern_return_t _MGSCheckinClient(mach_port_t server_port, mach_port_t client_port,
int32_t *client_index)
{
return [myserverController checkInClient:client_port index:client_index];
}
// For the MachO server, this is a no-op
kern_return_t _MGSDisplayFrame(mach_port_t server_port, int32_t frame_index, uint32_t iosurface_port)
{
return 0;
}
- (void)sendIOSurfaceMachPortToClients:(uint32_t)index withMachPort:(mach_port_t)iosurface_port
{
int i;
for(i = 0; i < clientPortCount+1; i++)
{
if(clientPortNames[i])
{
_MGCDisplayFrame(clientPortNames[i], index, iosurface_port);
}
}
}
- (bool)activeClients
{
return clientPortCount > 0 ? true : false;
}
@end
void initMacIOSurface() {
int viewportRect[4];
glGetIntegerv(GL_VIEWPORT, (GLint*)viewportRect);
w = viewportRect[2];
h = viewportRect[3];
if (!myserverController) {
myserverController = [[[MachServerController alloc] init] retain];
}
if (!ioSurfaceBuffers[0]) {
// Set up all of our iosurface buffers
for(int i = 0; i < NUM_IOSURFACE_BUFFERS; i++) {
ioSurfaceBuffers[i] = IOSurfaceCreate((CFDictionaryRef) @{
(id)kIOSurfaceWidth: [NSNumber numberWithInt: w],
(id)kIOSurfaceHeight: [NSNumber numberWithInt: h],
(id)kIOSurfaceBytesPerElement: @4
});
ioSurfaceMachPorts[i] = IOSurfaceCreateMachPort(ioSurfaceBuffers[i]);
}
}
}
void renderMacIOSurfacePre() {
GLuint name, namef;
if(!myserverController || ![myserverController activeClients]) {
return;
}
if(!textureNames[currentFrameIndex]) {
NSOpenGLContext * myContext = [ NSOpenGLContext currentContext ];
CGLContextObj cgl_ctx = (CGLContextObj)[myContext CGLContextObj];
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_RECTANGLE, name);
// At the moment, CGLTexImageIOSurface2D requires the GL_TEXTURE_RECTANGLE target
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RGBA, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
ioSurfaceBuffers[currentFrameIndex], 0);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate an FBO and bind the texture to it as a render target.
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glGenFramebuffers(1, &namef);
glBindFramebuffer(GL_FRAMEBUFFER, namef);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, name, 0);
if(!depthBufferName) {
glGenRenderbuffers(1, &depthBufferName);
glRenderbufferStorage(GL_TEXTURE_RECTANGLE, GL_DEPTH, w, h);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, depthBufferName);
fboNames[currentFrameIndex] = namef;
textureNames[currentFrameIndex] = name;
}
glBindFramebuffer(GL_FRAMEBUFFER, fboNames[currentFrameIndex]);
}
bool renderMacIOSurfacePost() {
if(!myserverController || ![myserverController activeClients]) {
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glFlush();
[myserverController sendIOSurfaceMachPortToClients: currentFrameIndex
withMachPort:ioSurfaceMachPorts[currentFrameIndex]];
currentFrameIndex = (currentFrameIndex + 1) % NUM_IOSURFACE_BUFFERS;
return true;
}
......@@ -23,6 +23,7 @@ FRAMEWORK_SRC?=$(PWD)
FRAMEWORK_INSTALL?=$(PWD)
# config values
OS = $(shell uname -s)
CXX?=g++
# variables
......@@ -34,6 +35,9 @@ CPPFLAGS += -I$(FRAMEWORK_INSTALL)/include/boinc -I/usr/include
DEPS = Makefile
OBJS = AbstractGraphicsEngine.o GraphicsEngineFactory.o WindowManager.o Resource.o ResourceFactory.o BOINCClientAdapter.o Libxml2Adapter.o
ifeq ($(OS), Darwin)
OBJS += MacIOSurfaceManager.o
endif
# TODO: GraphicsEngineFactory obviously depends on the actual implementations (here starsphere)! need to change the structure! what about plugins?
CPPFLAGS += -I$(FRAMEWORK_SRC) -I$(FRAMEWORK_SRC)/../starsphere
......@@ -62,6 +66,11 @@ GraphicsEngineFactory.o: $(DEPS) $(FRAMEWORK_SRC)/GraphicsEngineFactory.cpp $(FR
WindowManager.o: $(DEPS) $(FRAMEWORK_SRC)/WindowManager.cpp $(FRAMEWORK_SRC)/WindowManager.h
$(CXX) -g ${CPPFLAGS} -c $(FRAMEWORK_SRC)/WindowManager.cpp
ifeq ($(OS), Darwin)
MacIOSurfaceManager.o: $(DEPS) $(FRAMEWORK_SRC)/MacIOSurfaceManager.m $(FRAMEWORK_SRC)/MacIOSurfaceManager.h
$(CXX) -g ${CPPFLAGS} -c $(FRAMEWORK_SRC)/MacIOSurfaceManager.m
endif
BOINCClientAdapter.o: $(DEPS) $(FRAMEWORK_SRC)/BOINCClientAdapter.cpp $(FRAMEWORK_SRC)/BOINCClientAdapter.h
$(CXX) -g ${CPPFLAGS} -c $(FRAMEWORK_SRC)/BOINCClientAdapter.cpp
......
......@@ -20,6 +20,10 @@
#include "WindowManager.h"
#ifdef __APPLE__
#include "MacIOSurfaceManager.h"
#endif
WindowManager::WindowManager()
{
m_ScreensaverMode = false;
......@@ -232,8 +236,24 @@ void WindowManager::eventLoop()
i++;
#endif
// notify our observers (currently exactly one, hence front())
#ifdef __APPLE__
if(!m_ScreensaverMode) {
eventObservers.front()->render(dtime());
SDL_GL_SwapWindow(m_Window);
}
else {
// render to IOSurface and pass it to BOINC via Mach RPC
renderMacIOSurfacePre();
eventObservers.front()->render(dtime());
if(renderMacIOSurfacePost() == false) {
// there isn't a Mach client attached, render normally
SDL_GL_SwapWindow(m_Window);
}
}
#else
eventObservers.front()->render(dtime());
SDL_GL_SwapWindow(m_Window);
#endif
#ifdef DEBUG_VALGRIND
}
......@@ -256,11 +276,14 @@ void WindowManager::eventLoop()
(event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEBUTTONDOWN ||
event.type == SDL_KEYDOWN)) {
// don't handle events prematurely
if((SDL_GetWindowFlags(m_Window) & SDL_WINDOW_SHOWN)) {
// we're in screensaver mode so exit on user input
SDL_GL_DeleteContext(m_GLContext);
SDL_DestroyWindow(m_Window);
SDL_Quit();
}
}
else if (event.motion.state & (SDL_BUTTON(1) | SDL_BUTTON(3)) &&
event.type == SDL_MOUSEMOTION) {
......@@ -287,6 +310,13 @@ void WindowManager::eventLoop()
// (windoze needs to be reinitialized instead of just resized, oh well)
/// \todo Can we determine the host OS? On X11 a resize() is sufficient!
eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, getDisplayScalingFactor(), 0, true);
#ifdef __APPLE__
// initialize IOSurface and Mach RPC server
if(m_ScreensaverMode) {
initMacIOSurface();
}
#endif
}
else if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
m_WindowedWidth = event.window.data1;
......@@ -471,6 +501,21 @@ void WindowManager::toggleFullscreen()
m_VideoModeFlags |= SDL_WINDOW_FULLSCREEN;
}
#ifdef __APPLE__
// force window resize or BOINC's macOS screensaver host won't get the memo
if(m_ScreensaverMode) {
SDL_Rect rect;
int displayIndex = SDL_GetWindowDisplayIndex(m_Window);
if(displayIndex >= 0 && SDL_GetDisplayBounds(displayIndex, &rect) == 0) {
SDL_SetWindowSize(m_Window, rect.w, rect.h);
SDL_GL_GetDrawableSize(m_Window, &m_CurrentWidth, &m_CurrentHeight);
}
else {
cerr << "Could not force window resize: " << SDL_GetError() << endl;
}
}
#endif
// notify our observers (currently exactly one, hence front())
// (windoze needs to be reinitialized instead of just resized, oh well)
/// \todo Can we determine the host OS? On X11 a resize() is sufficient!
......
......@@ -31,7 +31,7 @@ LIBS += $(shell $(STARSPHERE_INSTALL)/bin/freetype-config --libs)
LIBS += $(shell $(STARSPHERE_INSTALL)/bin/xml2-config --libs)
LIBS += -lboinc_graphics2 -lboinc_api -lboinc -L$(STARSPHERE_INSTALL)/lib
LIBS += $(shell $(STARSPHERE_INSTALL)/bin/sdl2-config --static-libs)
LIBS += -Wl,-framework,OpenGL
LIBS += -Wl,-framework,IOSurface -Wl,-framework,OpenGL
LIBS += -lpthread -lm -lc
CPPFLAGS += -I$(STARSPHERE_INSTALL)/include
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment