Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Refactor GL context creation and headless rendering #6596

Merged
merged 2 commits into from
Oct 25, 2016

Conversation

kkaefer
Copy link
Contributor

@kkaefer kkaefer commented Oct 7, 2016

We currently have a View object, which is a weird mix of GL context creating, framebuffer management, as well as size + pixel ratio management. Instead, I propose refactoring this as follows:

  • Backend creates/destroys an OpenGL context (if needed). Contains the gl::Context object. Must be used to initialize Map and Canvas objects. A Backend can support multiple Map objects.
  • Map objects are initialized with a fixed pixel ratio; we don't support changing pixel ratio on-the-fly anyway because it is tied to what resources are being loaded.
  • Map objects can be resized, in logical units (unrelated to the pixel ratio). This affects what tiles are being loaded. It is not tied to a framebuffer or View object.
  • Map objects can take a lambda/std::function that is called when the map should be redrawn
  • View: abstract class that represents something that we can draw upon. Every render/renderStill call gets passed a View object. The Map and View objects must be initialized with the same Backend object.
    • A default is present on platform bindings like iOS and macOS, this encapsulates the default framebuffer provided by the system
    • OffscreenView is an implementation that draws to the framebuffer. Supports methods for obtaining the image rendered.
    • OffscreenTexture is similar to OffscreenView, except that it draws to a texture which can then be used for rendering to other views.

Open questions:

  • Continuously rendering map objects need a way to "invalidate" the map, i.e. tell the rendering driver to request a new frame
  • Multiple headless maps should be able to run on the same thread, and when calling renderStillImage, it doesn't need to block as long as the event loop continues to run. We should only issue GL calls when we are finally drawing the image

/cc @mikemorris @jfirebaugh

@kkaefer
Copy link
Contributor Author

kkaefer commented Oct 5, 2016

The main issue I'm currently seeing is the coupling between an OpenGL context and an object we can render to. It's currently one object, represented by the View object. This duality mirrors the GLFW API, but it's not actually how headless rendering works, and even when we have one main object, we could still have other Canvas objects that we render to.

@mikemorris
Copy link
Contributor

mikemorris commented Oct 5, 2016

A few tasks that I've previously started that I think would be related to this work:

@mention-bot
Copy link

@kkaefer, thanks for your PR! By analyzing the history of the files in this pull request, we identified @jfirebaugh, @mikemorris and @tmpsantos to be potential reviewers.

@kkaefer kkaefer force-pushed the 6596-refactor-gl-context-creation branch 9 times, most recently from 789daa1 to e307fdf Compare October 13, 2016 11:31
@kkaefer
Copy link
Contributor Author

kkaefer commented Oct 13, 2016

@jfirebaugh @tmpsantos @brunoabinader @mikemorris This is finally in a good shape and ready for review. I implemented pretty much exactly what is described above.

In particular, the only remaining (new) method of a View object is bind(). It is called whenever the Map needs to bind that view because it wants to draw on it. When the system provides a default framebuffer (i.e. all UI platforms), we are changing the gl::Context's state to reflect the framebuffer and viewport binding. In particular, the bindFramebuffer and viewport state values in gl::Context have a special treatment because they are always used in conjunction in our code. We previously didn't have a way to explicitly bind the default view because we never bound other framebuffers so far, but we are going to in the future.

This pull request unlocks a few other tasks that aren't part of this PR yet:

  • Remove activate()/deactivate() from the Backend object(?)
  • Share Backend objects across multiple Map/View objects to prevent excessive context switching in the Node.js use case (where every Map object currently has its own GL context)
  • Move invalidate() and notifyMapChange elsewhere; they shouldn't be part of Backend.

@kkaefer kkaefer force-pushed the 6596-refactor-gl-context-creation branch from e307fdf to 02e6151 Compare October 13, 2016 12:17
@jfirebaugh
Copy link
Contributor

  • Move invalidate() and notifyMapChange elsewhere; they shouldn't be part of Backend.

Refs #6383

Copy link
Contributor

@jfirebaugh jfirebaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos, this looks like a great refactor. I like the fact that neither View nor Backend have a dependency on Map, as View did before. This eliminates a troublesome circular dependency.

Just some small nits and one TODO to finish up.

#include <mbgl/platform/default/headless_display.hpp>
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/platform/default/headless_backend.hpp>
#include <mbgl/platform/default/offscreen_view.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense as a followup to rename Headless ⇢ Offscreen for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't rename this to have a difference in naming: Offscreen rendering doesn't necessarily imply headless rendering (and vice versa): We can use Offscreen views/texturs in regular rendering as well.

@@ -26,7 +26,8 @@ namespace android {
void CustomLayer::update(jni::JNIEnv&) {
Log::Debug(mbgl::Event::JNI, "Updating map");
if (map) {
map->update(mbgl::Update::Repaint);
// TODO: trigger a rerender
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need this implemented before merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implemented


class Framebuffer {
public:
// Framebuffer(std::array<uint16_t, 2> size_, gl::UniqueFramebuffer framebuffer_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete?


namespace mbgl {

class Map;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused.

#include <mbgl/util/image.hpp>

#include <array>
#include <functional>
#include <memory>

namespace mbgl {

class Map;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused.

@@ -1,63 +1,22 @@
#pragma once

#include <mbgl/map/change.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/image.hpp>

#include <array>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused.

@@ -1,63 +1,22 @@
#pragma once

#include <mbgl/map/change.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/image.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused.

@kkaefer kkaefer force-pushed the 6596-refactor-gl-context-creation branch from 02e6151 to 6a555ce Compare October 25, 2016 00:13
@kkaefer
Copy link
Contributor Author

kkaefer commented Oct 25, 2016

@jfirebaugh please review again

@kkaefer kkaefer merged commit a4d259c into master Oct 25, 2016
@kkaefer kkaefer deleted the 6596-refactor-gl-context-creation branch October 25, 2016 20:52
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants