Last active
July 23, 2017 11:28
-
-
Save dbarnes/94ded353e16a579ba3da52d2c6261173 to your computer and use it in GitHub Desktop.
Multi-GPU OpenGL on OSX with GLFW3.3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Post here: | |
// Multi-GPU OpenGL on OSX with GLFW3.3 | |
// https://medium.com/@danbarnes333/multi-gpu-opengl-on-osx-with-glfw3-3-6b0dab55467d | |
// Note: I’ve left in a lot of information gathering about the OpenGL Renderers that I thought | |
// might be helpful to those looking and can be deleted if you want more optimal code. | |
// For example if you dont know the virtual screen no. up front you could cycle through the | |
// renderers to find the desired virtual screen, checking they are: | |
// i) - accelerated (i.e. GPU) | |
// ii) - offline (renderers not connected to a display, i.e. second GPU on Mac Pro) | |
#include <iostream> | |
#include <iomanip> | |
#include <glog/logging.h> | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
#include <OpenGL/OpenGL.h> | |
DEFINE_int32(glfw_context_version_major, 3, "GLFW major context version"); | |
DEFINE_int32(glfw_context_version_minor, 2, "GLFW minor context version"); | |
DEFINE_int32(virtual_screen, -1, | |
"Use a specific virtual screeen which is currently believed to be " | |
"a stable identifier. -1 == default. On Mac Pro: 0 == Secondary " | |
"GPU. 1 == Primary GPU. 2 == Software."); | |
// Struct to hold renderer info | |
struct GLRendererInfo { | |
GLint rendererID; // RendererID number | |
GLint accelerated; // Whether Hardware accelerated | |
GLint online; // Whether renderer (/GPU) is onilne. Second GPU on Mac Pro is offline | |
GLint virtualScreen; // Virtual screen number | |
GLint videoMemoryMB; | |
GLint textureMemoryMB; | |
const GLubyte *vendor; | |
}; | |
GLFWwindow *InitialiseOpenGLContext(const unsigned int &width, | |
const unsigned int &height, | |
const std::string &name) { | |
// Initialise GLFW context | |
glfwSetErrorCallback(glfw::GLFWErrorCallback); | |
LOG_IF(FATAL, !glfwInit()) << "GLFW failed to initialise"; | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, | |
FLAGS_glfw_context_version_major); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, | |
FLAGS_glfw_context_version_minor); | |
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
glfwWindowHint(GLFW_SAMPLES, 0); | |
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); | |
glfwWindowHint(GLFW_REFRESH_RATE, GLFW_DONT_CARE); | |
// This is so all OpenGL Renderers are visible (GPUs / Software) | |
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE); | |
// Initialise GLFW window | |
GLFWwindow *window = glfwCreateWindow(width, height, name.c_str(), NULL, NULL); | |
LOG_IF(FATAL, !window) << "GLFW failed to create window"; | |
glfwMakeContextCurrent(window); | |
// Initialise GLEW | |
glewExperimental = GL_TRUE; | |
LOG_IF(FATAL, glewInit() != GLEW_OK) << "GLEW failed to initialise"; | |
glGetError(); | |
// Code to find and swap the OpenGL context to the desired virtual screen. | |
// We use -1 to use GLFW default | |
if (FLAGS_virtual_screen < 0) { | |
LOG(INFO) << "OpenGL Renderer: Using GLFW default."; | |
} else { | |
LOG(INFO) << "OpenGL Renderer: Using selected virtual screen: " << FLAGS_virtual_screen; | |
// Grab the GLFW context and pixel format for future calls | |
CGLContextObj contextObject = CGLGetCurrentContext(); | |
CGLPixelFormatObj pixel_format = CGLGetPixelFormat(contextObject); | |
// Number of renderers | |
CGLRendererInfoObj rend; | |
GLint nRenderers = 0; | |
CGLQueryRendererInfo(0xffffffff, &rend, &nRenderers); | |
// Number of virtual screens | |
GLint nVirtualScreens = 0; | |
CGLDescribePixelFormat(pixel_format, 0, kCGLPFAVirtualScreenCount, &nVirtualScreens); | |
// Get renderer information | |
std::vector<GLRendererInfo> Renderers(nRenderers); | |
for (GLint i = 0; i < nRenderers; ++i) { | |
CGLDescribeRenderer(rend, i, kCGLRPOnline, &(Renderers[i].online)); | |
CGLDescribeRenderer(rend, i, kCGLRPAcceleratedCompute, &(Renderers[i].accelerated)); | |
CGLDescribeRenderer(rend, i, kCGLRPRendererID, &(Renderers[i].rendererID)); | |
CGLDescribeRenderer(rend, i, kCGLRPVideoMemoryMegabytes, &(Renderers[i].videoMemoryMB)); | |
CGLDescribeRenderer(rend, i, kCGLRPTextureMemoryMegabytes, &(Renderers[i].textureMemoryMB)); | |
} | |
// Get corresponding virtual screen | |
for (GLint i = 0; i != nVirtualScreens; ++i) { | |
CGLSetVirtualScreen(contextObject, i); | |
GLint r; | |
CGLGetParameter(contextObject, kCGLCPCurrentRendererID, &r); | |
for (GLint j = 0; j < nRenderers; ++j) { | |
if (Renderers[j].rendererID == r) { | |
Renderers[j].virtualScreen = i; | |
Renderers[j].vendor = glGetString(GL_VENDOR); | |
} | |
} | |
} | |
// Print out information of renderers | |
VLOG(1) << "No. renderers: " << nRenderers | |
<< " No. virtual screens: " << nVirtualScreens << "\n"; | |
for (GLint i = 0; i < nRenderers; ++i) { | |
VLOG(1) << "Renderer: " << i | |
<< " Virtual Screen: " << Renderers[i].virtualScreen | |
<< " Renderer ID: " << Renderers[i].rendererID | |
<< " Vendor: " << Renderers[i].vendor | |
<< " Accelerated: " << Renderers[i].accelerated | |
<< " Online: " << Renderers[i].online | |
<< " Video Memory MB: " << Renderers[i].videoMemoryMB | |
<< " Texture Memory MB: " << Renderers[i].textureMemoryMB << "\n"; | |
} | |
// Set the context to our desired virtual screen (and therefore OpenGL renderer) | |
bool found = false; | |
for (GLint i = 0; i < nRenderers; ++i) { | |
if (Renderers[i].virtualScreen == FLAGS_virtual_screen) { | |
CGLSetVirtualScreen(contextObject, Renderers[i].virtualScreen); | |
found = true; | |
} | |
} | |
LOG_IF(FATAL, !found) << "Cound not find requested virtual screen: " | |
<< FLAGS_virtual_screen; | |
} | |
// set default color value to zero | |
glClearColor(0, 0, 0, 0); | |
// clear initialisation errors | |
(void)glGetError(); | |
// return pointer to glfw window | |
return window; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment