summaryrefslogtreecommitdiff
path: root/platform/macos/src/MGLMapView+OpenGL.mm
blob: f6168a4b8037978ad40c884ae9a3ce751a001334 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#import "MGLMapView+OpenGL.h"
#import "MGLOpenGLLayer.h"

#include <mbgl/gl/renderable_resource.hpp>

#import <OpenGL/gl.h>

class MGLMapViewOpenGLRenderableResource final : public mbgl::gl::RenderableResource {
public:
    MGLMapViewOpenGLRenderableResource(MGLMapViewOpenGLImpl& backend_) : backend(backend_) {
    }

    void bind() override {
        backend.restoreFramebufferBinding();
    }

private:
    MGLMapViewOpenGLImpl& backend;

public:
    // The current framebuffer of the NSOpenGLLayer we are painting to.
    GLint fbo = 0;

    // The reference counted count of activation calls
    NSUInteger activationCount = 0;
};

MGLMapViewOpenGLImpl::MGLMapViewOpenGLImpl(MGLMapView* nativeView_)
    : MGLMapViewImpl(nativeView_),
      mbgl::gl::RendererBackend(mbgl::gfx::ContextMode::Unique),
      mbgl::gfx::Renderable(mapView.framebufferSize,
                            std::make_unique<MGLMapViewOpenGLRenderableResource>(*this)) {

    // Install the OpenGL layer. Interface Builder’s synchronous drawing means
    // we can’t display a map, so don’t even bother to have a map layer.
    mapView.layer =
        mapView.isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
}

mbgl::gl::ProcAddress MGLMapViewOpenGLImpl::getExtensionFunctionPointer(const char* name) {
    static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
    if (!framework) {
        throw std::runtime_error("Failed to load OpenGL framework.");
    }

    return reinterpret_cast<mbgl::gl::ProcAddress>(CFBundleGetFunctionPointerForName(
        framework, (__bridge CFStringRef)[NSString stringWithUTF8String:name]));
}

void MGLMapViewOpenGLImpl::activate() {
    auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
    if (resource.activationCount++) {
        return;
    }

    MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
    [layer.openGLContext makeCurrentContext];
}

void MGLMapViewOpenGLImpl::deactivate() {
    auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
    if (--resource.activationCount) {
        return;
    }

    [NSOpenGLContext clearCurrentContext];
}

void MGLMapViewOpenGLImpl::updateAssumedState() {
    auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &resource.fbo);
    assumeFramebufferBinding(resource.fbo);
    assumeViewport(0, 0, mapView.framebufferSize);
}

void MGLMapViewOpenGLImpl::restoreFramebufferBinding() {
    auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
    setFramebufferBinding(resource.fbo);
    setViewport(0, 0, mapView.framebufferSize);
}

mbgl::PremultipliedImage MGLMapViewOpenGLImpl::readStillImage() {
    return readFramebuffer(mapView.framebufferSize);
}

CGLContextObj MGLMapViewOpenGLImpl::getCGLContextObj() {
    MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
    return layer.openGLContext.CGLContextObj;
}