Merge branch 'master' into shader-performance

This commit is contained in:
John Firebaugh
2015-01-07 15:15:11 -08:00
31 changed files with 598 additions and 434 deletions

View File

@@ -33,7 +33,7 @@
#include <uv.h>
// Check libuv library version.
const static bool uv_version_check = []() {
const static bool uvVersionCheck = []() {
const unsigned int version = uv_version();
const unsigned int major = (version >> 16) & 0xFF;
const unsigned int minor = (version >> 8) & 0xFF;
@@ -55,7 +55,7 @@ const static bool uv_version_check = []() {
#include <zlib.h>
// Check zlib library version.
const static bool zlib_version_check = []() {
const static bool zlibVersionCheck = []() {
const char *const version = zlibVersion();
if (version[0] != ZLIB_VERSION[0]) {
throw std::runtime_error(mbgl::util::sprintf<96>(
@@ -68,7 +68,7 @@ const static bool zlib_version_check = []() {
#include <sqlite3.h>
// Check sqlite3 library version.
const static bool sqlite_version_check = []() {
const static bool sqliteVersionCheck = []() {
if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) {
throw std::runtime_error(mbgl::util::sprintf<96>(
"sqlite3 libversion mismatch: headers report %d, but library reports %d",
@@ -91,6 +91,7 @@ Map::Map(View& view_, FileSource& fileSource_)
view(view_),
#ifndef NDEBUG
mainThread(std::this_thread::get_id()),
mapThread(mainThread),
#endif
transform(view_),
fileSource(fileSource_),
@@ -108,7 +109,7 @@ Map::Map(View& view_, FileSource& fileSource_)
}
Map::~Map() {
if (async) {
if (mode == Mode::Continuous) {
stop();
}
@@ -132,11 +133,11 @@ uv::worker &Map::getWorker() {
void Map::start() {
assert(std::this_thread::get_id() == mainThread);
assert(!async);
assert(mode == Mode::None);
// When starting map rendering in another thread, we perform async/continuously
// updated rendering. Only in these cases, we attach the async handlers.
async = true;
mode = Mode::Continuous;
// Reset the flag.
isStopped = false;
@@ -200,7 +201,7 @@ void Map::start() {
void Map::stop(std::function<void ()> callback) {
assert(std::this_thread::get_id() == mainThread);
assert(mainThread != mapThread);
assert(async);
assert(mode == Mode::Continuous);
asyncTerminate->send();
@@ -220,15 +221,16 @@ void Map::stop(std::function<void ()> callback) {
// already finished executing.
thread.join();
async = false;
mode = Mode::None;
}
void Map::run() {
if (mode == Mode::None) {
#ifndef NDEBUG
if (!async) {
mapThread = mainThread;
}
#endif
mode = Mode::Static;
}
assert(std::this_thread::get_id() == mapThread);
setup();
@@ -240,18 +242,23 @@ void Map::run() {
// If the map rendering wasn't started asynchronously, we perform one render
// *after* all events have been processed.
if (!async) {
if (mode == Mode::Static) {
render();
#ifndef NDEBUG
mapThread = std::thread::id();
#endif
mode = Mode::None;
fileSource.clearLoop();
}
}
void Map::rerender() {
// We only send render events if we want to continuously update the map
// (== async rendering).
if (async) {
if (mode == Mode::Static) {
prepare();
} else if (mode == Mode::Continuous) {
// We only send render events if we want to continuously update the map
// (== async rendering).
assert(asyncRender);
asyncRender->send();
}
}
@@ -280,9 +287,9 @@ void Map::terminate() {
void Map::setup() {
assert(std::this_thread::get_id() == mapThread);
assert(painter);
view.make_active();
view.activate();
painter->setup();
view.make_inactive();
view.deactivate();
}
void Map::setStyleURL(const std::string &url) {
@@ -606,7 +613,7 @@ void Map::prepare() {
}
void Map::render() {
view.make_active();
view.activate();
assert(painter);
painter->render(*style, activeSources,
@@ -616,5 +623,5 @@ void Map::render() {
update();
}
view.make_inactive();
view.deactivate();
}

View File

@@ -29,7 +29,7 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio,
if (final.width != w || final.height != h || final.pixelRatio != ratio ||
final.framebuffer[0] != fb_w || final.framebuffer[1] != fb_h) {
view.notify_map_change(MapChangeRegionWillChange);
view.notifyMapChange(MapChangeRegionWillChange);
current.width = final.width = w;
current.height = final.height = h;
@@ -38,7 +38,7 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio,
current.framebuffer[1] = final.framebuffer[1] = fb_h;
constrain(current.scale, current.y);
view.notify_map_change(MapChangeRegionDidChange);
view.notifyMapChange(MapChangeRegionDidChange);
return true;
} else {
@@ -57,7 +57,7 @@ void Transform::moveBy(const double dx, const double dy, const timestamp duratio
void Transform::_moveBy(const double dx, const double dy, const timestamp duration) {
// This is only called internally, so we don't need a lock here.
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionWillChangeAnimated :
MapChangeRegionWillChange);
@@ -78,7 +78,7 @@ void Transform::_moveBy(const double dx, const double dy, const timestamp durati
std::make_shared<util::ease_transition<double>>(current.y, final.y, current.y, start, duration));
}
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionDidChangeAnimated :
MapChangeRegionDidChange,
duration);
@@ -268,7 +268,7 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
const timestamp duration) {
// This is only called internally, so we don't need a lock here.
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionWillChangeAnimated :
MapChangeRegionWillChange);
@@ -297,7 +297,7 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
Bc = s / 360;
Cc = s / (2 * M_PI);
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionDidChangeAnimated :
MapChangeRegionDidChange,
duration);
@@ -376,7 +376,7 @@ void Transform::setAngle(const double new_angle, const double cx, const double c
void Transform::_setAngle(double new_angle, const timestamp duration) {
// This is only called internally, so we don't need a lock here.
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionWillChangeAnimated :
MapChangeRegionWillChange);
@@ -395,7 +395,7 @@ void Transform::_setAngle(double new_angle, const timestamp duration) {
current.angle, final.angle, current.angle, start, duration));
}
view.notify_map_change(duration ?
view.notifyMapChange(duration ?
MapChangeRegionDidChangeAnimated :
MapChangeRegionDidChange,
duration);

View File

@@ -5,8 +5,9 @@
#include <mbgl/platform/platform.hpp>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <fstream>
using namespace mbgl;
@@ -25,35 +26,26 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
// Load binary shader if it exists
bool skipCompile = false;
if (!binaryFileName.empty() && (gl::ProgramBinary != nullptr)) {
FILE *binaryFile = fopen(binaryFileName.c_str(), "rb");
if (binaryFile != nullptr) {
GLsizei binaryLength;
GLenum binaryFormat;
bool lengthOk = fread(&binaryLength, sizeof(binaryLength), 1, binaryFile) == 1;
bool formatOk = fread(&binaryFormat, sizeof(binaryFormat), 1, binaryFile) == 1;
std::ifstream binaryFile(binaryFileName, std::ios::in | std::ios::binary);
if (lengthOk && formatOk && binaryLength > 0) {
std::unique_ptr<char[]> binary = mbgl::util::make_unique<char[]>(binaryLength);
GLsizei binaryLength;
GLenum binaryFormat;
binaryFile.read(reinterpret_cast<char *>(&binaryLength), sizeof(binaryLength));
binaryFile.read(reinterpret_cast<char *>(&binaryFormat), sizeof(binaryFormat));
if (binary != nullptr) {
bool binaryOk = fread(binary.get(), binaryLength, 1, binaryFile) == 1;
std::unique_ptr<char[]> binary = mbgl::util::make_unique<char[]>(binaryLength);
binaryFile.read(binary.get(), binaryLength);
if (binaryOk) {
MBGL_CHECK_ERROR(gl::ProgramBinary(program, binaryFormat, binary.get(), binaryLength));
MBGL_CHECK_ERROR(gl::ProgramBinary(program, binaryFormat, binary.get(), binaryLength));
// Check if the binary was valid
GLint status;
MBGL_CHECK_ERROR(glGetProgramiv(program, GL_LINK_STATUS, &status));
if (status == GL_TRUE) {
skipCompile = true;
}
}
}
}
fclose(binaryFile);
binaryFile = nullptr;
// Check if the binary was valid
GLint status;
MBGL_CHECK_ERROR(glGetProgramiv(program, GL_LINK_STATUS, &status));
if (status == GL_TRUE) {
skipCompile = true;
}
binaryFile.close();
}
GLuint vertShader = 0;
@@ -150,7 +142,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
*shader = MBGL_CHECK_ERROR(glCreateShader(type));
const GLchar *strings[] = { source };
const GLsizei lengths[] = { (GLsizei)strlen(source) };
const GLsizei lengths[] = { (GLsizei)std::strlen(source) };
MBGL_CHECK_ERROR(glShaderSource(*shader, 1, strings, lengths));
MBGL_CHECK_ERROR(glCompileShader(*shader));
@@ -189,19 +181,14 @@ Shader::~Shader() {
MBGL_CHECK_ERROR(glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength));
if (binaryLength > 0) {
std::unique_ptr<char[]> binary = mbgl::util::make_unique<char[]>(binaryLength);
if (binary != nullptr) {
MBGL_CHECK_ERROR(gl::GetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary.get()));
MBGL_CHECK_ERROR(gl::GetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary.get()));
// Write the binary to a file
FILE *binaryFile = fopen(binaryFileName.c_str(), "wb");
if (binaryFile != nullptr) {
fwrite(&binaryLength, sizeof(binaryLength), 1, binaryFile);
fwrite(&binaryFormat, sizeof(binaryFormat), 1, binaryFile);
fwrite(binary.get(), binaryLength, 1, binaryFile);
fclose(binaryFile);
binaryFile = nullptr;
}
}
// Write the binary to a file
std::ofstream binaryFile(binaryFileName, std::ios::out | std::ios::trunc | std::ios::binary);
binaryFile.write(reinterpret_cast<char *>(&binaryLength), sizeof(binaryLength));
binaryFile.write(reinterpret_cast<char *>(&binaryFormat), sizeof(binaryFormat));
binaryFile.write(binary.get(), binaryLength);
binaryFile.close();
}
}

View File

@@ -1,5 +1,5 @@
#include <mbgl/storage/caching_http_file_source.hpp>
#include <mbgl/storage/file_request.hpp>
#include <mbgl/storage/asset_request.hpp>
#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/sqlite_store.hpp>
#include <mbgl/util/uv-messenger.h>
@@ -17,6 +17,8 @@ CachingHTTPFileSource::~CachingHTTPFileSource() {
}
void CachingHTTPFileSource::setLoop(uv_loop_t* loop_) {
assert(!loop);
thread_id = std::this_thread::get_id();
store = !path.empty() ? util::ptr<SQLiteStore>(new SQLiteStore(loop_, path)) : nullptr;
loop = loop_;
@@ -51,6 +53,8 @@ void CachingHTTPFileSource::clearLoop() {
}
store.reset();
loop = nullptr;
}
void CachingHTTPFileSource::setBase(std::string value) {
@@ -91,8 +95,8 @@ std::unique_ptr<Request> CachingHTTPFileSource::request(ResourceType type, const
}
if (!req) {
if (url.substr(0, 7) == "file://") {
req = std::make_shared<FileRequest>(url.substr(7), loop);
if (url.substr(0, 8) == "asset://") {
req = std::make_shared<AssetRequest>(url.substr(8), loop);
} else {
req = std::make_shared<HTTPRequest>(type, url, loop, store);
}

View File

@@ -1,37 +0,0 @@
#include <mbgl/storage/file_request.hpp>
#include <mbgl/storage/file_request_baton.hpp>
#include <mbgl/storage/response.hpp>
#include <uv.h>
#include <cassert>
#include <unistd.h>
namespace mbgl {
FileRequest::FileRequest(const std::string &path_, uv_loop_t *loop)
: BaseRequest(path_), ptr(new FileRequestBaton(this, path, loop)) {
}
void FileRequest::cancel() {
assert(thread_id == std::this_thread::get_id());
if (ptr) {
ptr->cancel();
// When deleting a FileRequest object with a uv_fs_* call is in progress, we are making sure
// that the callback doesn't accidentally reference this object again.
ptr->request = nullptr;
ptr = nullptr;
}
notify();
}
FileRequest::~FileRequest() {
assert(thread_id == std::this_thread::get_id());
cancel();
}
}

View File

@@ -1,27 +0,0 @@
#ifndef MBGL_STORAGE_FILE_REQUEST
#define MBGL_STORAGE_FILE_REQUEST
#include <mbgl/storage/base_request.hpp>
namespace mbgl {
typedef struct uv_loop_s uv_loop_t;
struct FileRequestBaton;
class FileRequest : public BaseRequest {
public:
FileRequest(const std::string &path, uv_loop_t *loop);
~FileRequest();
void cancel();
private:
FileRequestBaton *ptr = nullptr;
friend struct FileRequestBaton;
};
}
#endif

View File

@@ -1,160 +0,0 @@
#include <mbgl/storage/file_request_baton.hpp>
#include <mbgl/storage/file_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/std.hpp>
#include <limits>
namespace mbgl {
FileRequestBaton::FileRequestBaton(FileRequest *request_, const std::string &path, uv_loop_t *loop)
: thread_id(std::this_thread::get_id()), request(request_) {
req.data = this;
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, file_opened);
}
FileRequestBaton::~FileRequestBaton() {
}
void FileRequestBaton::cancel() {
canceled = true;
// uv_cancel fails frequently when the request has already been started.
// In that case, we have to let it complete and check the canceled bool
// instead.
uv_cancel((uv_req_t *)&req);
}
void FileRequestBaton::notify_error(uv_fs_t *req) {
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
assert(ptr->thread_id == std::this_thread::get_id());
if (ptr->request && req->result < 0 && !ptr->canceled && req->result != UV_ECANCELED) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = req->result == UV_ENOENT ? 404 : 500;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
ptr->request->response->message = uv_strerror(uv_last_error(req->loop));
#else
ptr->request->response->message = uv_strerror(int(req->result));
#endif
ptr->request->notify();
}
}
void FileRequestBaton::file_opened(uv_fs_t *req) {
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
assert(ptr->thread_id == std::this_thread::get_id());
if (req->result < 0) {
// Opening failed or was canceled. There isn't much left we can do.
notify_error(req);
cleanup(req);
} else {
const uv_file fd = uv_file(req->result);
// We're going to reuse this handle, so we need to cleanup first.
uv_fs_req_cleanup(req);
if (ptr->canceled || !ptr->request) {
// Either the FileRequest object has been destructed, or the
// request was canceled.
uv_fs_close(req->loop, req, fd, file_closed);
} else {
ptr->fd = fd;
uv_fs_fstat(req->loop, req, fd, file_stated);
}
}
}
void FileRequestBaton::file_stated(uv_fs_t *req) {
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
assert(ptr->thread_id == std::this_thread::get_id());
if (req->result != 0 || ptr->canceled || !ptr->request) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notify_error(req);
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, file_closed);
} else {
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
const uv_statbuf_t *stat = static_cast<const uv_statbuf_t *>(req->ptr);
#else
const uv_stat_t *stat = static_cast<const uv_stat_t *>(req->ptr);
#endif
if (stat->st_size > std::numeric_limits<int>::max()) {
// File is too large for us to open this way because uv_buf's only support unsigned
// ints as maximum size.
if (ptr->request) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = UV_EFBIG;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
ptr->request->response->message = uv_strerror(uv_err_t {UV_EFBIG, 0});
#else
ptr->request->response->message = uv_strerror(UV_EFBIG);
#endif
ptr->request->notify();
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, file_closed);
} else {
const unsigned int size = (unsigned int)(stat->st_size);
ptr->body.resize(size);
ptr->buffer = uv_buf_init(const_cast<char *>(ptr->body.data()), size);
uv_fs_req_cleanup(req);
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
uv_fs_read(req->loop, req, ptr->fd, ptr->buffer.base, ptr->buffer.len, -1, file_read);
#else
uv_fs_read(req->loop, req, ptr->fd, &ptr->buffer, 1, 0, file_read);
#endif
}
}
}
void FileRequestBaton::file_read(uv_fs_t *req) {
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
assert(ptr->thread_id == std::this_thread::get_id());
if (req->result < 0 || ptr->canceled || !ptr->request) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notify_error(req);
} else {
// File was successfully read.
if (ptr->request) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = 200;
ptr->request->response->data = std::move(ptr->body);
ptr->request->notify();
}
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, file_closed);
}
void FileRequestBaton::file_closed(uv_fs_t *req) {
assert(((FileRequestBaton *)req->data)->thread_id == std::this_thread::get_id());
if (req->result < 0) {
// Closing the file failed. But there isn't anything we can do.
}
cleanup(req);
}
void FileRequestBaton::cleanup(uv_fs_t *req) {
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
assert(ptr->thread_id == std::this_thread::get_id());
if (ptr->request) {
ptr->request->ptr = nullptr;
}
uv_fs_req_cleanup(req);
delete ptr;
}
}

View File

@@ -1,36 +0,0 @@
#ifndef MBGL_STORAGE_FILE_REQUEST_BATON
#define MBGL_STORAGE_FILE_REQUEST_BATON
#include <mbgl/storage/file_request.hpp>
#include <thread>
#include <uv.h>
namespace mbgl {
struct FileRequestBaton {
FileRequestBaton(FileRequest *request_, const std::string &path, uv_loop_t *loop);
~FileRequestBaton();
void cancel();
static void file_opened(uv_fs_t *req);
static void file_stated(uv_fs_t *req);
static void file_read(uv_fs_t *req);
static void file_closed(uv_fs_t *req);
static void notify_error(uv_fs_t *req);
static void cleanup(uv_fs_t *req);
const std::thread::id thread_id;
FileRequest *request = nullptr;
uv_fs_t req;
uv_file fd = -1;
bool canceled = false;
std::string body;
uv_buf_t buffer;
};
}
#endif