Skip to content

Commit

Permalink
Add Free-Threaded resource upload to Android OpenGL Backend
Browse files Browse the repository at this point in the history
  • Loading branch information
alasram committed Aug 29, 2024
1 parent 290bf92 commit aa00054
Show file tree
Hide file tree
Showing 44 changed files with 1,055 additions and 156 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,8 @@ if(MLN_WITH_OPENGL)
SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/gl/attribute.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/attribute.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/buffer_resource.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/buffer_resource.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/command_encoder.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/command_encoder.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/context.cpp
Expand Down Expand Up @@ -1094,6 +1096,8 @@ if(MLN_WITH_OPENGL)
${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderbuffer_resource.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderbuffer_resource.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderer_backend.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/resource_upload_thread_pool.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/resource_upload_thread_pool.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/state.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture.hpp
Expand Down
4 changes: 4 additions & 0 deletions bazel/core.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,8 @@ MLN_CORE_HEADERS = [
MLN_OPENGL_SOURCE = [
"src/mbgl/gl/attribute.cpp",
"src/mbgl/gl/attribute.hpp",
"src/mbgl/gl/buffer_resource.cpp",
"src/mbgl/gl/buffer_resource.hpp",
"src/mbgl/gl/command_encoder.cpp",
"src/mbgl/gl/command_encoder.hpp",
"src/mbgl/gl/context.cpp",
Expand All @@ -886,6 +888,8 @@ MLN_OPENGL_SOURCE = [
"src/mbgl/gl/renderbuffer_resource.cpp",
"src/mbgl/gl/renderbuffer_resource.hpp",
"src/mbgl/gl/renderer_backend.cpp",
"src/mbgl/gl/resource_upload_thread_pool.cpp",
"src/mbgl/gl/resource_upload_thread_pool.hpp",
"src/mbgl/gl/state.hpp",
"src/mbgl/gl/texture.cpp",
"src/mbgl/gl/texture.hpp",
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/gl/drawable_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class DrawableGL : public gfx::Drawable {

void setVertexAttrId(const size_t id);

void upload(gfx::UploadPass&);
void issueUpload(gfx::UploadPass&);

protected:
class Impl;
Expand Down
4 changes: 2 additions & 2 deletions include/mbgl/gl/layer_group_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class TileLayerGroupGL : public TileLayerGroup {
TileLayerGroupGL(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~TileLayerGroupGL() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand All @@ -39,7 +39,7 @@ class LayerGroupGL : public LayerGroup {
LayerGroupGL(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~LayerGroupGL() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand Down
19 changes: 19 additions & 0 deletions include/mbgl/gl/renderer_backend.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/gl/resource_upload_thread_pool.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/util/util.hpp>
Expand All @@ -14,6 +15,16 @@ namespace gl {
using ProcAddress = void (*)();
using FramebufferID = uint32_t;

class UploadThreadContext {
public:
UploadThreadContext() = default;
virtual ~UploadThreadContext() = default;
virtual void createContext() = 0;
virtual void destroyContext() = 0;
virtual void bindContext() = 0;
virtual void unbindContext() = 0;
};

class RendererBackend : public gfx::RendererBackend {
public:
RendererBackend(gfx::ContextMode);
Expand All @@ -28,6 +39,11 @@ class RendererBackend : public gfx::RendererBackend {
void initShaders(gfx::ShaderRegistry&, const ProgramParameters& programParameters) override;
#endif

virtual bool supportFreeThreadedUpload() const { return false; }
virtual void initFreeThreadedUpload() {}
virtual std::shared_ptr<UploadThreadContext> createUploadThreadContext() { return nullptr; }
gl::ResourceUploadThreadPool& getResourceUploadThreadPool();

protected:
std::unique_ptr<gfx::Context> createContext() override;

Expand Down Expand Up @@ -58,6 +74,9 @@ class RendererBackend : public gfx::RendererBackend {
void setFramebufferBinding(FramebufferID fbo);
void setViewport(int32_t x, int32_t y, const Size&);
void setScissorTest(bool);

private:
std::unique_ptr<gl::ResourceUploadThreadPool> resourceUploadThreadPool;
};

} // namespace gl
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/mtl/layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class LayerGroup : public mbgl::LayerGroup {
LayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~LayerGroup() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/mtl/tile_layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class TileLayerGroup : public mbgl::TileLayerGroup {
TileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~TileLayerGroup() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/renderer/layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class LayerGroupBase : public util::SimpleIdentifiable {
/// Called before starting each frame
virtual void preRender(RenderOrchestrator&, PaintParameters&) {}
/// Called during the upload pass
virtual void upload(gfx::UploadPass&) {}
virtual void issueUpload(gfx::UploadPass&) {}
/// Called during each render pass
virtual void render(RenderOrchestrator&, PaintParameters&) {}
/// Called at the end of each frame
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/renderer/render_target.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class RenderTarget {
}

/// Upload the layer groups
void upload(gfx::UploadPass& uploadPass);
void issueUpload(gfx::UploadPass& uploadPass);

/// Render the layer groups
void render(RenderOrchestrator&, const RenderTree&, PaintParameters&);
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/util/instrumentation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ constexpr const char* tracyConstMemoryLabel = "Constant Buffer Memory";
#define MLN_TRACE_GL_CONTEXT() ((void)0)
#define MLN_TRACE_GL_ZONE(label) ((void)0)
#define MLN_TRACE_FUNC_GL() ((void)0)
#define MLN_END_FRAME() FrameMark;
#define MLN_END_FRAME() FrameMark

#endif // MLN_RENDER_BACKEND_OPENGL

Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/vulkan/layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class LayerGroup : public mbgl::LayerGroup {
LayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~LayerGroup() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/vulkan/tile_layer_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TileLayerGroup : public mbgl::TileLayerGroup {
TileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name);
~TileLayerGroup() override {}

void upload(gfx::UploadPass&) override;
void issueUpload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;

const gfx::UniformBufferArray& getUniformBuffers() const override { return uniformBuffers; };
Expand Down
196 changes: 194 additions & 2 deletions platform/android/MapLibreAndroid/src/cpp/android_renderer_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
#include <mbgl/gfx/backend_scope.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/renderable_resource.hpp>

#include <EGL/egl.h>
#include <mbgl/util/instrumentation.hpp>
#include <mbgl/util/logging.hpp>

#include <cassert>
#include <mutex>
#include <stdexcept>

namespace mbgl {
namespace android {
namespace {

std::mutex& getEglMutex() {
static std::mutex eglMutex;
return eglMutex;
}

} // namespace

class AndroidGLRenderableResource final : public mbgl::gl::RenderableResource {
public:
Expand Down Expand Up @@ -74,5 +84,187 @@ void AndroidRendererBackend::swap() {
}
}

std::shared_ptr<gl::UploadThreadContext> AndroidRendererBackend::createUploadThreadContext() {
MLN_TRACE_FUNC();

assert(eglMainCtx != EGL_NO_CONTEXT);
return std::make_shared<AndroidUploadThreadContext>(*this, eglDsply, eglConfig, eglMainCtx);
}

void AndroidRendererBackend::initFreeThreadedUpload() {
MLN_TRACE_FUNC();

if (eglMainCtx != EGL_NO_CONTEXT) {
// Already initialized
return;
}
assert(eglDsply == EGL_NO_DISPLAY);
assert(eglSurf == EGL_NO_SURFACE);
assert(eglGetError() == EGL_SUCCESS);

eglMainCtx = eglGetCurrentContext();
if (eglMainCtx == EGL_NO_CONTEXT) {
constexpr const char* err = "eglGetCurrentContext returned EGL_NO_CONTEXT";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

eglDsply = eglGetCurrentDisplay();
if (eglDsply == EGL_NO_DISPLAY) {
constexpr const char* err = "eglGetCurrentDisplay returned EGL_NO_DISPLAY";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

eglSurf = eglGetCurrentSurface(EGL_READ);
if (eglSurf == EGL_NO_SURFACE) {
constexpr const char* err = "eglGetCurrentSurface returned eglGetCurrentSurface";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

EGLSurface writeSurf = eglGetCurrentSurface(EGL_DRAW);
if (eglSurf != writeSurf) {
constexpr const char* err = "EGL_READ and EGL_DRAW surfaces are different";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

int config_id = 0;
if (eglQueryContext(eglDsply, eglMainCtx, EGL_CONFIG_ID, &config_id) == EGL_FALSE) {
auto err = "eglQueryContext for EGL_CONFIG_ID failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

int config_count = 0;
const EGLint attribs[] = {EGL_CONFIG_ID, config_id, EGL_NONE};
if (eglChooseConfig(eglDsply, attribs, nullptr, 0, &config_count) == EGL_FALSE) {
auto err = "eglChooseConfig failed to query config_count. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
if (config_count != 1) {
auto err = "eglChooseConfig returned multiple configs: " + std::to_string(config_count);
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

if (eglChooseConfig(eglDsply, attribs, &eglConfig, 1, &config_count) == EGL_FALSE) {
auto err = "eglChooseConfig failed to query config. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
}

AndroidUploadThreadContext::AndroidUploadThreadContext(AndroidRendererBackend& backend_,
EGLDisplay display_,
EGLConfig config_,
EGLContext mainContext_)
: backend(backend_),
display(display_),
config(config_),
mainContext(mainContext_) {}

AndroidUploadThreadContext::~AndroidUploadThreadContext() {
MLN_TRACE_FUNC();

auto ctx = eglGetCurrentContext();
if (ctx == EGL_NO_CONTEXT) {
return; // Upload thread clean from any EGL context
}

if (ctx == sharedContext) {
mbgl::Log::Error(mbgl::Event::OpenGL, "AndroidUploadThreadContext::destroyContext() must be explicitly called");
} else {
mbgl::Log::Error(mbgl::Event::OpenGL, "Unexpected context bound to an Upload thread");
}
assert(ctx == EGL_NO_CONTEXT);
}

void AndroidUploadThreadContext::createContext() {
MLN_TRACE_FUNC();

const std::lock_guard<std::mutex> lock(getEglMutex());

assert(display != EGL_NO_DISPLAY);
assert(mainContext != EGL_NO_CONTEXT);
assert(sharedContext == EGL_NO_CONTEXT);
assert(surface == EGL_NO_SURFACE);

sharedContext = eglCreateContext(display, config, mainContext, nullptr);
if (sharedContext == EGL_NO_CONTEXT) {
constexpr const char* err = "eglGetCurrentContext returned EGL_NO_CONTEXT";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

surface = eglCreatePbufferSurface(display, config, nullptr);
if (surface == EGL_NO_SURFACE) {
auto err = "eglCreatePbufferSurface failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

if (eglMakeCurrent(display, surface, surface, sharedContext) == EGL_FALSE) {
auto err = "eglMakeCurrent for shared context failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
MLN_TRACE_GL_CONTEXT();
}

void AndroidUploadThreadContext::destroyContext() {
MLN_TRACE_FUNC();

const std::lock_guard<std::mutex> lock(getEglMutex());

auto ctx = eglGetCurrentContext();
if (ctx == EGL_NO_CONTEXT) {
constexpr const char* err =
"AndroidUploadThreadContext::destroyContext() expects a persistently bound EGL shared context";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
} else if (ctx != sharedContext) {
constexpr const char* err =
"AndroidUploadThreadContext::destroyContext(): expects a single EGL context to be used in each Upload "
"thread";
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
assert(ctx == sharedContext);

if (eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) {
auto err = "eglMakeCurrent with EGL_NO_CONTEXT failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
if (eglDestroyContext(display, sharedContext) == EGL_FALSE) {
auto err = "eglDestroyContext failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}
if (eglDestroySurface(display, surface) == EGL_FALSE) {
auto err = "eglDestroySurface failed. Error code" + std::to_string(eglGetError());
mbgl::Log::Error(mbgl::Event::OpenGL, err);
throw std::runtime_error(err);
}

display = EGL_NO_DISPLAY;
mainContext = EGL_NO_CONTEXT;
sharedContext = EGL_NO_CONTEXT;
surface = EGL_NO_SURFACE;
}

void AndroidUploadThreadContext::bindContext() {
// Expect a persistently bound EGL shared context
assert(eglGetCurrentContext() == sharedContext && sharedContext != EGL_NO_CONTEXT);
}

void AndroidUploadThreadContext::unbindContext() {
// Expect a persistently bound EGL shared context
assert(eglGetCurrentContext() == sharedContext && sharedContext != EGL_NO_CONTEXT);
}

} // namespace android
} // namespace mbgl
Loading

0 comments on commit aa00054

Please sign in to comment.