Openframeworks in a dll issues with ofShader


#1

Hello everyone,

I’m building OF as dll and everything works great until I use a shader. I could use ofFBO and send images from the host application to the dll which creates a window and displays it. Everything is good until I try to load a shader.
The same code running in a single executable works well. Therefore there must be some problem either in my dll main, which handles the window creation, loop and glRenderer, etc, or some settings in GLEW or GLFW must be changed in order to make things work.

To me it seems that GLEW is not initialized, but I can see OF going through the ofAppGLFWWindow::setup() call and loading GLEW as usual.

Any idea what I could be missing?
Here are some details on the modifications I have gone through to reach the current point and the crash.

//------------------------------------

ofShader.h requires a modification in order to point at the current rendrer (similar to ofFBO):

public:
	void setRenderer(std::shared_ptr<ofBaseGLRenderer> GLrenderer) {
		gl = GLrenderer;
	}
private:
	std::shared_ptr<ofBaseGLRenderer> gl;

then before loading any shader I pass the renderer used:

blendShader.setRenderer(gl);

then I get a crash when loading the shader like:

blendShader.setupShaderFromSource(GL_FRAGMENT_SHADER, myshader);

crashes at: ofShader.cpp

//--------------------------------------------------------------
void ofShader::checkAndCreateProgram() {
#ifndef TARGET_OPENGLES
	if(GL_ARB_shader_objects) {
#else
	if(ofIsGLProgrammableRenderer()){
#endif
		if(program == 0) {
			ofLogVerbose("ofShader") << "checkAndCreateProgram(): creating GLSL program";
-->			program = glCreateProgram();
			retainProgram(program);
		}
	} else {
		ofLogError("ofShader") << "sorry, it looks like you can't run 'ARB_shader_objects'";
		ofLogError("ofShader") << "please check the capabilites of your graphics card: http://www.ozone3d.net/gpu_caps_viewer";
	}
}

Exception thrown at 0x0000000000000000 in explicitRendererExample_mine_debug.exe: 0xC0000005: Access violation executing location 0x0000000000000000.

//------------------------------------

Things I’ve tried:

use ofGLProgrammableRenderer by setting:

ofGLFWWindowSettings settings;
settings.setGLVersion(3, 2);

then changing ofAppGLFWWindow.cpp:

		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

by

		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

as suggested in:

in ofConstants change:

#define GLEW_STATIC

by

#define GLEW_BUILD

as suggested in :

Followed this thread to expose C calls from the dll:

I’m using the explicit renderer described in:

My dll main.cpp:

#define DLLEXPORT __declspec(dllexport)
extern "C"
{
	DLLEXPORT void createWindow(std::shared_ptr<ofMainLoop>& mainLoop, std::shared_ptr<GuiApp>& mainApp)
	{
		ofSetLogLevel(OF_LOG_VERBOSE);
		ofLogToConsole();

		std::cout << "Creating output window" << std::endl;

//		ofInit();
		// create output window	
		ofGLFWWindowSettings settings;
		settings.setSize(screenW*2, screenH);
		settings.setPosition(ofVec2f(1920, 0));
		settings.resizable = false;
		settings.decorated = false;
		settings.windowMode = OF_WINDOW;
//		settings.setGLVersion(3, 2); // set programmable renderer

		mainLoop = make_shared<ofMainLoop>();
		auto& mainWindow = mainLoop->createWindow(settings);
//		auto& mainWindow = ofCreateWindow(settings);

		// create output app
		mainApp = make_shared<GuiApp>();
		mainApp->window = mainWindow;
		mainApp->gl = static_pointer_cast<ofBaseGLRenderer>(mainWindow->renderer());
		mainLoop->run(mainWindow, mainApp);

		std::cout << "Output window created" << std::endl;
	}

	DLLEXPORT void loop(std::shared_ptr<ofMainLoop>& mainLoop)
	{
//		mainLoop->loopOnce();
 		mainLoop->getCurrentWindow()->makeCurrent();
 		mainLoop->getCurrentWindow()->update();
 		mainLoop->getCurrentWindow()->draw();
		ofAppGLFWWindow::pollEvents();
	}

}

#2

So I found the solution but I don’t know why this fix is needed.

The problem is that GLEW was not inited when loading the shader. So I placed the initialization in my app::setup() :

#ifndef TARGET_OPENGLES
	static bool inited = false;
	if (!inited) {
		glewExperimental = GL_TRUE;
		GLenum err = glewInit();
		if (GLEW_OK != err)
		{
			/* Problem: glewInit failed, something is seriously wrong. */
			ofLogError("ofAppRunner") << "couldn't init GLEW: " << glewGetErrorString(err);
			return;
		}
		inited = true;
	}
#endif

My question is:
The GLEW initialization is done during the creation of the window, specifically at:
auto&amp; mainWindow = mainLoop-&gt;createWindow(settings);

Why when using a dll is this initialization required also at the setup of my application?

So why do I have to run it twice? where is the initialization being reset (or lost)?


#3

Finally I got to understand the source of the issue:
“So GLFW doesn’t support multiple copies of itself in the same process”

So the solution is to load GLFW as dll in all projects where it is used. Use GLFW_DLL preprocessor definition and add the paths to lib and header files.