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

Commit

Permalink
Merge pull request #1272 from mapbox/1272-render-still-images-on-thread
Browse files Browse the repository at this point in the history
Render still/static images on a separate thread as well, aligning it with the way continuous render mode works
  • Loading branch information
kkaefer committed Apr 17, 2015
2 parents cd49664 + 9072df7 commit 7827d49
Show file tree
Hide file tree
Showing 25 changed files with 446 additions and 158 deletions.
10 changes: 1 addition & 9 deletions android/cpp/jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,6 @@ void JNICALL nativeResume(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
nativeMapView->resume();
}

void JNICALL nativeRun(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRun");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().run();
}

void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate");
assert(nativeMapViewPtr != 0);
Expand Down Expand Up @@ -936,7 +929,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {

// NOTE: if you get java.lang.UnsatisfiedLinkError you likely forgot to set the size of the
// array correctly (too large)
std::array<JNINativeMethod, 63> methods = {{ // Can remove the extra brace in C++14
std::array<JNINativeMethod, 62> methods = {{ // Can remove the extra brace in C++14
{"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
reinterpret_cast<void *>(&nativeCreate)},
{"nativeDestroy", "(J)V", reinterpret_cast<void *>(&nativeDestroy)},
Expand All @@ -951,7 +944,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeStop", "(J)V", reinterpret_cast<void *>(&nativeStop)},
{"nativePause", "(J)V", reinterpret_cast<void *>(&nativePause)},
{"nativeResume", "(J)V", reinterpret_cast<void *>(&nativeResume)},
{"nativeRun", "(J)V", reinterpret_cast<void *>(&nativeRun)},
{"nativeUpdate", "(J)V", reinterpret_cast<void *>(&nativeUpdate)},
{"nativeTerminate", "(J)V", reinterpret_cast<void *>(&nativeTerminate)},
{"nativeResize", "(JIIFII)V",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ public void resume() {
nativeResume(mNativeMapViewPtr);
}

public void run() {
nativeRun(mNativeMapViewPtr);
}

public void update() {
nativeUpdate(mNativeMapViewPtr);
}
Expand Down Expand Up @@ -398,8 +394,6 @@ private native void nativeCreateSurface(long nativeMapViewPtr,

private native void nativeResume(long nativeMapViewPtr);

private native void nativeRun(long nativeMapViewPtr);

private native void nativeUpdate(long nativeMapViewPtr);

private native void nativeTerminate(long nativeMapViewPtr);
Expand Down
34 changes: 24 additions & 10 deletions bin/render.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/still_image.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/io.hpp>
Expand All @@ -19,12 +20,13 @@

namespace po = boost::program_options;

#include <uv.h>

#include <cassert>
#include <cstdlib>
#include <iostream>

int main(int argc, char *argv[]) {

std::string style_path;
double lat = 0, lon = 0;
double zoom = 0;
Expand All @@ -33,7 +35,7 @@ int main(int argc, char *argv[]) {
int width = 512;
int height = 512;
double pixelRatio = 1.0;
std::string output = "out.png";
static std::string output = "out.png";
std::string cache_file = "cache.sqlite";
std::vector<std::string> classes;
std::string token;
Expand Down Expand Up @@ -81,6 +83,8 @@ int main(int argc, char *argv[]) {
HeadlessView view;
Map map(view, fileSource);

map.start(Map::Mode::Static);

// Set access token if present
if (token.size()) {
map.setAccessToken(std::string(token));
Expand All @@ -93,14 +97,24 @@ int main(int argc, char *argv[]) {
map.setLatLngZoom({ lat, lon }, zoom);
map.setBearing(bearing);

// Run the loop. It will terminate when we don't have any further listeners.
map.run();
uv_async_t *async = new uv_async_t;
uv_async_init(uv_default_loop(), async, [](uv_async_t *as, int) {
std::unique_ptr<const StillImage> image(reinterpret_cast<const StillImage *>(as->data));
uv_close(reinterpret_cast<uv_handle_t *>(as), [](uv_handle_t *handle) {
delete reinterpret_cast<uv_async_t *>(handle);
});

const std::string png = util::compress_png(image->width, image->height, image->pixels.get());
util::write_file(output, png);
});

map.renderStill([async](std::unique_ptr<const StillImage> image) {
async->data = const_cast<StillImage *>(image.release());
uv_async_send(async);
});

// Get the data from the GPU.
auto pixels = view.readPixels();
// This loop will terminate once the async was fired.
uv_run(uv_default_loop(), UV_RUN_DEFAULT);

const unsigned int w = width * pixelRatio;
const unsigned int h = height * pixelRatio;
const std::string image = util::compress_png(w, h, pixels.get());
util::write_file(output, image);
map.stop();
}
3 changes: 3 additions & 0 deletions bin/render.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@
'variables' : {
'cflags_cc': [
'<@(glfw3_cflags)',
'<@(uv_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(glfw3_ldflags)',
'<@(uv_ldflags)',
'<@(boost_ldflags)',
'-lboost_program_options'
],
'libraries': [
'<@(glfw3_static_libs)',
'<@(uv_static_libs)',
],
},

Expand Down
28 changes: 17 additions & 11 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,24 @@ class EnvironmentScope;
class AnnotationManager;
class MapData;
class Worker;
class StillImage;

class Map : private util::noncopyable {
friend class View;

public:
enum class Mode : uint8_t {
None, // we're not doing any processing
Continuous, // continually updating map
Static, // a once-off static image.
};

explicit Map(View&, FileSource&);
~Map();

// Start the map render thread. It is asynchronous.
void start(bool startPaused = false);
void start(bool startPaused = false, Mode mode = Mode::Continuous);
inline void start(Mode renderMode) { start(false, renderMode); }

// Stop the map render thread. This call will block until the map rendering thread stopped.
// The optional callback function will be invoked repeatedly until the map thread is stopped.
Expand All @@ -65,10 +73,8 @@ class Map : private util::noncopyable {
// Resumes a paused render thread
void resume();

// Runs the map event loop. ONLY run this function when you want to get render a single frame
// with this map object. It will *not* spawn a separate thread and instead block until the
// frame is completely rendered.
void run();
using StillImageCallback = std::function<void(std::unique_ptr<const StillImage>)>;
void renderStill(StillImageCallback callback);

// Triggers a synchronous or asynchronous render.
void renderSync();
Expand Down Expand Up @@ -167,6 +173,11 @@ class Map : private util::noncopyable {
inline AnnotationManager& getAnnotationManager() const { return *annotationManager; }

private:
// Runs the map event loop. ONLY run this function when you want to get render a single frame
// with this map object. It will *not* spawn a separate thread and instead block until the
// frame is completely rendered.
void run();

// This may only be called by the View object.
void resize(uint16_t width, uint16_t height, float ratio = 1);
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight);
Expand Down Expand Up @@ -203,12 +214,6 @@ class Map : private util::noncopyable {

size_t sourceCacheSize;

enum class Mode : uint8_t {
None, // we're not doing any processing
Continuous, // continually updating map
Static, // a once-off static image.
};

Mode mode = Mode::None;

const std::unique_ptr<Environment> env;
Expand Down Expand Up @@ -260,6 +265,7 @@ class Map : private util::noncopyable {

std::mutex mutexTask;
std::queue<std::function<void()>> tasks;
StillImageCallback callback;
};

}
Expand Down
21 changes: 21 additions & 0 deletions include/mbgl/map/still_image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef MBGL_MAP_STILL_IMAGE
#define MBGL_MAP_STILL_IMAGE

#include <mbgl/util/noncopyable.hpp>

#include <string>
#include <cstdint>

namespace mbgl {

class StillImage : util::noncopyable {
public:
uint16_t width = 0;
uint16_t height = 0;
using Pixel = uint32_t;
std::unique_ptr<Pixel[]> pixels;
};

}

#endif
3 changes: 3 additions & 0 deletions include/mbgl/map/update.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef MBGL_MAP_UPDATE
#define MBGL_MAP_UPDATE

#include <cstdint>

namespace mbgl {

using UpdateType = uint32_t;
Expand All @@ -12,6 +14,7 @@ enum class Update : UpdateType {
DefaultTransitionDuration = 1 << 2,
Classes = 1 << 3,
Zoom = 1 << 4,
RenderStill = 1 << 5,
};

}
Expand Down
11 changes: 11 additions & 0 deletions include/mbgl/map/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

#include <mbgl/util/chrono.hpp>

#include <memory>

namespace mbgl {

class Map;
class StillImage;

enum MapChange : uint8_t {
MapChangeRegionWillChange = 0,
Expand Down Expand Up @@ -40,6 +43,14 @@ class View {
// (i.e. map->renderSync() or map->renderAsync() must be called as a result of this)
virtual void invalidate() = 0;

// Called from the render (=GL) thread. Signals that the contents of the contents
// may be discarded. The default is a no-op.
virtual void discard();

// Reads the pixel data from the current framebuffer. If your View implementation
// doesn't support reading from the framebuffer, return a null pointer.
virtual std::unique_ptr<StillImage> readStillImage();

// Notifies a watcher of map x/y/scale/rotation changes.
// Must only be called from the same thread that caused the change.
// Must not be called from the render thread.
Expand Down
39 changes: 28 additions & 11 deletions include/mbgl/platform/default/headless_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,47 @@ class HeadlessDisplay;

class HeadlessView : public View {
public:
HeadlessView();
HeadlessView(std::shared_ptr<HeadlessDisplay> display);
HeadlessView(uint16_t width = 256, uint16_t height = 256, float pixelRatio = 1);
HeadlessView(std::shared_ptr<HeadlessDisplay> display, uint16_t width = 256, uint16_t height = 256, float pixelRatio = 1);
~HeadlessView();

void createContext();
void loadExtensions();

void resize(uint16_t width, uint16_t height, float pixelRatio);
std::unique_ptr<uint32_t[]> readPixels();

void activate() override;
void deactivate() override;
void notify() override;
void invalidate() override;
void discard() override;
std::unique_ptr<StillImage> readStillImage() override;

private:
void createContext();
void loadExtensions();
void clearBuffers();
bool isActive();

private:
std::shared_ptr<HeadlessDisplay> display_;
uint16_t width_;
uint16_t height_;
float pixelRatio_;
std::shared_ptr<HeadlessDisplay> display;

struct Dimensions {
inline Dimensions(uint16_t width = 0, uint16_t height = 0, float pixelRatio = 0);
inline uint16_t pixelWidth() const { return width * pixelRatio; }
inline uint16_t pixelHeight() const { return height * pixelRatio; }

uint16_t width = 0;
uint16_t height = 0;
float pixelRatio = 0;
};

// These are the values that represent the state of the current framebuffer.
Dimensions current;

// These are the values that will be used after the next discard() event.
std::mutex prospectiveMutex;
Dimensions prospective;

#if MBGL_USE_CGL
CGLContextObj glContext;
CGLContextObj glContext = nullptr;
#endif

#if MBGL_USE_GLX
Expand All @@ -64,6 +79,8 @@ class HeadlessView : public View {
GLuint fbo = 0;
GLuint fboDepthStencil = 0;
GLuint fboColor = 0;

std::thread::id thread;
};

}
Expand Down
File renamed without changes.
Loading

0 comments on commit 7827d49

Please sign in to comment.