Multiple GLFW windows with single context

I have program that has 4 viewports.

1 of main GLFW window to deal with GUI and 4 of sub GLFW windows to render scenes.
Scene will be loaded up while sub GLFW window is being created then initialize Shaders/FBOs/SSBOs/Frame Buffers.

At this point I have a issue that I have to load up scene 4 times otherwise scenes cannot be rendered on each views.

I think scenes can be shared among views, so reducing it will improve the overall performance.
However when I try that, nothing is rendered on views.

So I would like to get some help from here to see what is the problem with my source codes.

GL_Window / GL_Viewport…

struct GL_Viewport {
	HWND						winHandle;
	GLFWwindow*					glfwHandle;
	char						name[256];
	int							x, y, width, height;
	RECT						area;
	Camera*						camera;
};

struct GL_Window {
	HWND						winHandle;
	GLFWwindow*					glfwHandle;
	char						name[256];
	int							x, y, width, height;
	GL_Viewport*				glViews;
	int							size;

	bool AddViewport(int viewIndex = 0, int _x = 0, int _y = 0, int _width = 0, int _height = 0) {
		if (viewIndex == 0)
			glViews = (GL_Viewport*)malloc((viewIndex + 1) * sizeof(GL_Viewport));

		else
			glViews = (GL_Viewport*)realloc(glViews, (viewIndex + 1) * sizeof(GL_Viewport));

		GL_Viewport	dummyView;

		glViews[viewIndex] = dummyView;

		glViews[viewIndex].x = _x;
		glViews[viewIndex].y = _y;
		glViews[viewIndex].width = _width;
		glViews[viewIndex].height = _height;

		sprintf(glViews[viewIndex].name, "View-%d", viewIndex);

		if (!glfwInit()) {
			printf("Failed to initialize GLFW\n");
			return false;
		}

		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
		glfwWindowHint(GLFW_SAMPLES, 4);

		glfwWindowHint(GLFW_DECORATED, GL_FALSE);

		// Create viewport
		glViews[viewIndex].glfwHandle = glfwCreateWindow(glViews[viewIndex].width, glViews[viewIndex].height, glViews[viewIndex].name, NULL, glfwHandle);

		if (glViews[viewIndex].glfwHandle == NULL) {
			printf("Failed to create viewport(s)\n");
			return false;
		}

		// Switch to current viewport
		glfwMakeContextCurrent(glViews[viewIndex].glfwHandle);

		// Initialize GLAD
		if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
			printf("Failed to initialize GLAD\n");
			glfwTerminate();
			return false;
		}

		// Get window handle
		glViews[viewIndex].winHandle = glfwGetWin32Window(glViews[viewIndex].glfwHandle);

		// Set parent
		SetParent(glViews[viewIndex].winHandle, winHandle);

		return true;
	}
};

Main…

    // Create main GLFW window
    if (!gDisplayManager.startUp()) {
        printf("Failed to initialize window display manager.\n");
        return false;
    }

    // Create 4 viewports
    for (int i = 0; i < gDisplayManager.glWindow.size; i++) {
        // Create viewport
        gDisplayManager.glWindow.AddViewport(i, 0, 0, gDisplayManager.ViewWidth, gDisplayManager.ViewHeight);

        // Initialize viewports
        gDisplayManager.InitViewports(i);

        // Load scene(s)
        if (!gSceneManager.startUp(gDisplayManager.glWindow.glViews[i])) {
            printf("Failed to initialize scene manager.\n");
            return false;
        }

        // Initializes rendering manager, which is in charge of high level
        // rendering tasks (render queue, locating render scene etc)
        // It gets passed references to the other major subsystems for use later
        if (!gRenderManager.startUp(gSceneManager.getCurrentScene(), gDisplayManager.glWindow.glViews[i])) {
            printf("Failed to initialize Render manager for view [%d].\n", i);
            return false;
        }

        // Initializing input manager that manages all mouse, keyboard and
        // mousewheel input.
        if (!gInputManager.startUp(gDisplayManager.glWindow.glViews[i])) {
            printf("Failed to initialize input manager for view [%d].\n", i);
            return false;
        }
    }

    while (!gDisplayManager.ShouldClose()) {
        // Update all models in the current scene
        gSceneManager.update(deltaT);

        // Scan through all available viewports
        for (int i = 0; i < gDisplayManager.glWindow.size; i++) {
            glfwMakeContextCurrent(gDisplayManager.glWindow.glViews[i].glfwHandle);

            // Update camera
            gDisplayManager.glWindow.glViews[i].camera->update(NULL, 0, 0);

            // User input
            gInputManager.processInput(deltaTime, gDisplayManager.glWindow.glViews[i]);

            // Render scene
            gRenderManager.render(start, gDisplayManager.glWindow.glViews[i]);

            // Swap screen buffer
            gDisplayManager.Swap(i);

            // Processes all pending events
            glfwPollEvents();
        }
    }

SceneManager…

bool SceneManager::startUp(GL_Viewport& glView) {
    currentSceneID = "sponza";
    if (!loadScene(currentSceneID, glView)) {
        printf("Could not load scene. No models successfully loaded!\n");
        return false;
    }

    return true;
}

void SceneManager::update(unsigned int deltaT) {
    currentScene->update(deltaT);
}

Scene* SceneManager::getCurrentScene() {
    return currentScene;
}

// Loads the scene with the given ID
bool SceneManager::loadScene(std::string sceneID, GL_Viewport& glView) {
    currentScene = new Scene(sceneID, glView);

    return !currentScene->loadingError;
}

Scene…

Scene::Scene(const std::string& sceneName, GL_Viewport& glView) {
    models.folderPath = "assets/scenes/";
    models.fileExtension = ".json";
    models.sceneID = sceneName;
    loadingError = !loadContent(glView);
}

bool Scene::loadContent(GL_Viewport& glView) {
    // Parsing into Json file readable format
    models.sceneConfigFilePath = models.folderPath + models.sceneID + models.fileExtension;
    std::ifstream file(models.sceneConfigFilePath.c_str());
    json configJson;
    file >> configJson;

    loadSceneModels(configJson);

    loadCamera(configJson, glView);

    CubeMap::cubeMapCube.setup();
    loadSkyBox(configJson);

    loadLights(configJson);

    generateEnvironmentMaps();

    return !models.modelsInScene.empty();
}

RenderManager…

bool RenderManager::startUp(Scene* scene, GL_Viewport& glView) {
    currentScene = scene;

    if (!loadShaders()) {
        printf("Shaders failed to be initialized correctly.\n");
        return false;
    }

    if (!initFBOs(glView)) {
        printf("FBO's failed to be initialized correctly.\n");
        return false;
    }

    if (!initSSBOs(glView)) {
        printf("SSBO's failed to be initialized correctly.\n");
        return false;
    }

    if (!preProcess(glView)) {
        printf("Pre-processing failed.\n");
        return false;
    }

    return true;
}

void RenderManager::render(const unsigned int start, GL_Viewport& glView) {
    // Making sure depth testing is enabled 
    glEnable(GL_DEPTH_TEST);
    glDepthMask(true);

    // Directional shadows
    dirShadowFBO.bind();
    dirShadowFBO.clear(GL_DEPTH_BUFFER_BIT, glm::vec3(1.0f));
    currentScene->drawDirLightShadows(dirShadowShader, dirShadowFBO.depthBuffer, withDirectionalLightShadow);

    // Multisampled Depth pre-pass
    multiSampledFBO.bind();
    multiSampledFBO.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, glm::vec3(0.0f));
    currentScene->drawDepthPass(depthPrePassShader, glView);

    // Light assignment
    cullLightsCompShader.use();
    cullLightsCompShader.setMat4("viewMatrix", glView.camera->viewMatrix);
    cullLightsCompShader.dispatch(1, 1, 6);

    // Forward render the scene in the multisampled FBO using the z buffer to discard early
    glDepthFunc(GL_LEQUAL);
    glDepthMask(false);
    currentScene->drawScene(PBRClusteredShader, glView, withLight, withTexture);
    currentScene->drawSkyBox(skyboxShader, glView, withSkyBox);

    // Resolve the from multisampled to normal resolution for postProcessing
    multiSampledFBO.blitTo(simpleFBO, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Post processing, includes bloom, exposure mapping
    postProcess(start, glView);
}

Since the same scene has been loaded 4 times, it occupies system resources too much, I want to minimize it.


You’re passing a variable glfwHandle but there’s no declaration, initialisation or assignment of this variable in the code you posted. The value of that variable should be null for the first call to glfwCreateWindow and the handle (GLFWwindow*) of an existing window for subsequent calls.

Contexts which share data will share buffers, textures, renderbuffers, shaders and programs (which includes the contents of the default uniform block), but not container objects (program pipelines, VAOs, FBOs, and transform feedback objects) nor query objects. Context state is not shared so any state-setting commands have to be repeated for each context.

E.g. when you create a texture, the texture will exist and have the same contents in all contexts which share data, but the binding of textures to texture units has to be performed separately for each context. Likewise for buffers; you only need to create and populate the buffer once, but the glVertexAttribPointer calls need to be performed for each context. If you’re using a VAO to hold the attribute array state, each context needs to create and initialise its own VAO.

Similarly, each context needs its own FBO, but they can all use the same texture(s).

Thanks! I missed the part for main window creation here but I did what you have mentioned.
I will check those VAOs, FBOs as you recommended :slight_smile: thanks!

// Create main GLFW window
bool CreateGLWindow() {
		if (!glfwInit()) {
			printf("Failed to initialize GLFW\n");
			return false;
		}

		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
#ifdef UHD4600
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#else
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
#endif
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
		glfwWindowHint(GLFW_SAMPLES, 4);

		// Create main window
		glfwHandle = glfwCreateWindow(width, height, name, NULL, NULL);

		// Get the window handle
		winHandle = glfwGetWin32Window(glfwHandle);

		glfwMakeContextCurrent(glfwHandle);

		printf("Initializing GLFW window...\n");
		if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
			printf("Failed to initialize GLAD\n");
			glfwTerminate();

			return false;
		}

		// Enable vsync
	//	glfwSwapInterval(1);

		// Printing some vendor Information
		printf("Vendor:   %s\n", glGetString(GL_VENDOR));
		printf("Renderer: %s\n", glGetString(GL_RENDERER));
		printf("Version:  %s\n", glGetString(GL_VERSION));

		return true;
	}

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.