summaryrefslogtreecommitdiff
path: root/platform/default/src/mbgl/gl/headless_backend.cpp
blob: 697c560f76aa783b56f4cabee20c4f704374d619 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/renderable_resource.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gfx/backend_scope.hpp>

#include <cassert>
#include <stdexcept>
#include <type_traits>

namespace mbgl {
namespace gl {

class HeadlessRenderableResource final : public gl::RenderableResource {
public:
    HeadlessRenderableResource(HeadlessBackend& backend_, gl::Context& context_, Size size_)
        : backend(backend_),
          context(context_),
          color(context.createRenderbuffer<gfx::RenderbufferPixelType::RGBA>(size_)),
          depthStencil(context.createRenderbuffer<gfx::RenderbufferPixelType::DepthStencil>(size_)),
          framebuffer(context.createFramebuffer(color, depthStencil)) {}

    void bind() override {
        context.bindFramebuffer = framebuffer.framebuffer;
        context.scissorTest = false;
        context.viewport = { 0, 0, framebuffer.size };
    }

    void swap() override { backend.swap(); }

    HeadlessBackend& backend;
    gl::Context& context;
    gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA> color;
    gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil> depthStencil;
    gl::Framebuffer framebuffer;
};

HeadlessBackend::HeadlessBackend(const Size size_,
                                 gfx::HeadlessBackend::SwapBehaviour swapBehaviour_,
                                 const gfx::ContextMode contextMode_)
    : mbgl::gl::RendererBackend(contextMode_), mbgl::gfx::HeadlessBackend(size_), swapBehaviour(swapBehaviour_) {}

HeadlessBackend::~HeadlessBackend() {
    gfx::BackendScope guard{*this};
    resource.reset();
    // Explicitly reset the context so that it is destructed and cleaned up before we destruct
    // the impl object.
    context.reset();
}

gl::ProcAddress HeadlessBackend::getExtensionFunctionPointer(const char* name) {
    assert(impl);
    return impl->getExtensionFunctionPointer(name);
}

void HeadlessBackend::activate() {
    active = true;

    if (!impl) {
        createImpl();
    }

    assert(impl);
    impl->activateContext();
}

void HeadlessBackend::deactivate() {
    assert(impl);
    impl->deactivateContext();
    active = false;
}

gfx::Renderable& HeadlessBackend::getDefaultRenderable() {
    if (!resource) {
        resource = std::make_unique<HeadlessRenderableResource>(*this, static_cast<gl::Context&>(getContext()), size);
    }
    return *this;
}

void HeadlessBackend::swap() {
    if (swapBehaviour == SwapBehaviour::Flush) static_cast<gl::Context&>(getContext()).finish();
}

void HeadlessBackend::updateAssumedState() {
    // no-op
}

PremultipliedImage HeadlessBackend::readStillImage() {
    return static_cast<gl::Context&>(getContext()).readFramebuffer<PremultipliedImage>(size);
}

RendererBackend* HeadlessBackend::getRendererBackend() {
    return this;
}

} // namespace gl

namespace gfx {

template <>
std::unique_ptr<gfx::HeadlessBackend> Backend::Create<gfx::Backend::Type::OpenGL>(
    const Size size, gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode) {
    return std::make_unique<gl::HeadlessBackend>(size, swapBehavior, contextMode);
}

} // namespace gfx
} // namespace mbgl