Skip to content

Commit

Permalink
Merge pull request #1194 from tangrams/reduce-font-data-copies
Browse files Browse the repository at this point in the history
More font loading speedups
  • Loading branch information
hjanetzek authored Jan 10, 2017
2 parents db73248 + 269b567 commit d93cf4f
Show file tree
Hide file tree
Showing 19 changed files with 232 additions and 196 deletions.
20 changes: 10 additions & 10 deletions android/tangram/src/main/cpp/platform_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,14 @@ std::vector<FontSourceHandle> systemFontFallbacksHandle() {
return handles;
}

unsigned char* systemFont(const std::string& _name, const std::string& _weight, const std::string& _face, size_t* _size) {
std::vector<char> systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) {
std::string path = fontPath(_name, _weight, _face);

if (path.empty()) { return nullptr; }
if (path.empty()) { return {}; }

return bytesFromFile(path.c_str(), *_size);
auto data = bytesFromFile(path.c_str());

return data;
}

void setContinuousRendering(bool _isContinuous) {
Expand Down Expand Up @@ -293,22 +295,20 @@ std::string stringFromFile(const char* _path) {
return data;
}

unsigned char* bytesFromFile(const char* _path, size_t& _size) {

_size = 0;
unsigned char* data = nullptr;
std::vector<char> bytesFromFile(const char* _path) {
std::vector<char> data;

auto allocator = [&](size_t size) {
_size = size;
data = (unsigned char*) malloc(sizeof(char) * size);
return reinterpret_cast<char*>(data);
data.resize(size);
return data.data();
};

if (strncmp(_path, aaPrefix, aaPrefixLen) == 0) {
bytesFromAssetManager(_path + aaPrefixLen, allocator);
} else {
bytesFromFileSystem(_path, allocator);
}

return data;
}

Expand Down
10 changes: 4 additions & 6 deletions core/src/data/rasterSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,16 @@ RasterSource::RasterSource(const std::string& _name, const std::string& _urlTemp
TextureOptions _options, bool _genMipmap)
: DataSource(_name, _urlTemplate, _minDisplayZoom, _maxDisplayZoom, _maxZoom), m_texOptions(_options), m_genMipmap(_genMipmap) {

m_emptyTexture = std::make_shared<Texture>(nullptr, 0, m_texOptions, m_genMipmap);
std::vector<char> data = {};
m_emptyTexture = std::make_shared<Texture>(data, m_texOptions, m_genMipmap);
}

std::shared_ptr<Texture> RasterSource::createTexture(const std::vector<char>& _rawTileData) {
auto udata = reinterpret_cast<const unsigned char*>(_rawTileData.data());
size_t dataSize = _rawTileData.size();

if (dataSize == 0) {
if (_rawTileData.size() == 0) {
return m_emptyTexture;
}

auto texture = std::make_shared<Texture>(udata, dataSize, m_texOptions, m_genMipmap);
auto texture = std::make_shared<Texture>(_rawTileData, m_texOptions, m_genMipmap);

return texture;
}
Expand Down
4 changes: 3 additions & 1 deletion core/src/gl/renderState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,9 @@ void RenderState::deleteDefaultPointTexture() {

void RenderState::generateDefaultPointTexture() {
TextureOptions options = { GL_RGBA, GL_RGBA, { GL_LINEAR, GL_LINEAR }, { GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE } };
m_defaultPointTexture = new Texture(default_point_texture_data, default_point_texture_size, options, true);
std::vector<char> defaultPoint;
defaultPoint.insert(defaultPoint.begin(), default_point_texture_data, default_point_texture_data + default_point_texture_size);
m_defaultPointTexture = new Texture(defaultPoint, options, true);
}

bool RenderState::framebuffer(GLuint handle) {
Expand Down
10 changes: 5 additions & 5 deletions core/src/gl/texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ Texture::Texture(unsigned int _width, unsigned int _height, TextureOptions _opti
resize(_width, _height);
}

Texture::Texture(const unsigned char* data, size_t dataSize, TextureOptions options, bool generateMipmaps)
Texture::Texture(const std::vector<char>& _data, TextureOptions options, bool generateMipmaps)
: Texture(0u, 0u, options, generateMipmaps) {

loadImageFromMemory(data, dataSize);
loadImageFromMemory(_data);
}

Texture::~Texture() {
Expand All @@ -54,12 +54,12 @@ Texture::~Texture() {
});
}

bool Texture::loadImageFromMemory(const unsigned char* blob, unsigned int size) {
bool Texture::loadImageFromMemory(const std::vector<char>& _data) {
unsigned char* pixels = nullptr;
int width, height, comp;

if (blob != nullptr && size != 0) {
pixels = stbi_load_from_memory(blob, size, &width, &height, &comp, STBI_rgb_alpha);
if (_data.size() != 0) {
pixels = stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(_data.data()), _data.size(), &width, &height, &comp, STBI_rgb_alpha);
}

if (pixels) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/gl/texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Texture {
TextureOptions _options = DEFAULT_TEXTURE_OPTION,
bool _generateMipmaps = false);

Texture(const unsigned char* data, size_t dataSize,
Texture(const std::vector<char>& _data,
TextureOptions _options = DEFAULT_TEXTURE_OPTION,
bool _generateMipmaps = false);

Expand Down Expand Up @@ -87,7 +87,7 @@ class Texture {

static bool isRepeatWrapping(TextureWrapping _wrapping);

bool loadImageFromMemory(const unsigned char* blob, unsigned int size);
bool loadImageFromMemory(const std::vector<char>& _data);

static void flipImageData(unsigned char *result, int w, int h, int depth);
static void flipImageData(GLuint *result, int w, int h);
Expand Down
13 changes: 4 additions & 9 deletions core/src/gl/textureCube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,23 @@
namespace Tangram {

TextureCube::TextureCube(std::string _file, TextureOptions _options)
: Texture(0u, 0u, _options) {
: Texture(0, 0, _options) {

m_target = GL_TEXTURE_CUBE_MAP;
load(_file);
}

void TextureCube::load(const std::string& _file) {
size_t size;
unsigned char* data = bytesFromFile(_file.c_str(), size);
auto data = bytesFromFile(_file.c_str());
unsigned char* pixels;
int width, height, comp;

if (data == nullptr || size == 0) {
if (data.size() == 0) {
LOGE("Texture not found! '%s'", _file.c_str());
free(data);
return;
}

pixels = stbi_load_from_memory(data, size, &width, &height, &comp, STBI_rgb_alpha);

size = width * height;
pixels = stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(data.data()), data.size(), &width, &height, &comp, STBI_rgb_alpha);

m_width = width / 4;
m_height = height / 3;
Expand Down Expand Up @@ -63,7 +59,6 @@ void TextureCube::load(const std::string& _file) {
}
}

free(data);
stbi_image_free(pixels);

}
Expand Down
4 changes: 2 additions & 2 deletions core/src/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ std::string stringFromFile(const char* _path);
* containing the contents of the file. The size of the memory in bytes is written to _size.
* If the file cannot be read, nothing is allocated and nullptr is returned.
*/
unsigned char* bytesFromFile(const char* _path, size_t& _size);
std::vector<char> bytesFromFile(const char* _path);

/* Function type for receiving data from a successful network request */
using UrlCallback = std::function<void(std::vector<char>&&)>;
Expand All @@ -63,7 +63,7 @@ void cancelUrlRequest(const std::string& _url);
*/
void setCurrentThreadPriority(int priority);

unsigned char* systemFont(const std::string& _name, const std::string& _weight, const std::string& _face, size_t* _size);
std::vector<char> systemFont(const std::string& _name, const std::string& _weight, const std::string& _face);

struct FontSourceHandle {
FontSourceHandle(std::string _path) : path(_path) {}
Expand Down
34 changes: 16 additions & 18 deletions core/src/scene/sceneLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,12 +552,10 @@ std::shared_ptr<Texture> SceneLoader::fetchTexture(const std::string& name, cons
if (std::regex_search(url, match, r)) {
scene->pendingTextures++;
startUrlRequest(url, [=](std::vector<char>&& rawData) {
auto ptr = (unsigned char*)(rawData.data());
size_t dataSize = rawData.size();
std::lock_guard<std::mutex> lock(m_textureMutex);
auto texture = scene->getTexture(name);
if (texture) {
if (!texture->loadImageFromMemory(ptr, dataSize)) {
if (!texture->loadImageFromMemory(rawData)) {
LOGE("Invalid texture data '%s'", url.c_str());
}

Expand All @@ -568,7 +566,8 @@ std::shared_ptr<Texture> SceneLoader::fetchTexture(const std::string& name, cons
}
}
});
texture = std::make_shared<Texture>(nullptr, 0, options, generateMipmaps);
std::vector<char> textureData = {};
texture = std::make_shared<Texture>(textureData, options, generateMipmaps);
} else {

if (url.substr(0, 22) == "data:image/png;base64,") {
Expand All @@ -589,24 +588,25 @@ std::shared_ptr<Texture> SceneLoader::fetchTexture(const std::string& name, cons
}
texture = std::make_shared<Texture>(0, 0, options, generateMipmaps);

if (!texture->loadImageFromMemory(blob.data(), blob.size())) {
std::vector<char> textureData;
auto cdata = reinterpret_cast<char*>(blob.data());
textureData.insert(textureData.begin(), cdata, cdata + blob.size());
if (!texture->loadImageFromMemory(textureData)) {
LOGE("Invalid Base64 texture");
}

} else {
size_t size = 0;
unsigned char* blob = bytesFromFile(url.c_str(), size);
auto data = bytesFromFile(url.c_str());

if (!blob) {
if (data.size() == 0) {
LOGE("Can't load texture resource at url '%s'", url.c_str());
return nullptr;
}
texture = std::make_shared<Texture>(0, 0, options, generateMipmaps);

if (!texture->loadImageFromMemory(blob, size)) {
texture = std::make_shared<Texture>(0, 0, options, generateMipmaps);
if (!texture->loadImageFromMemory(data)) {
LOGE("Invalid texture data '%s'", url.c_str());
}
free(blob);
}
}

Expand Down Expand Up @@ -725,15 +725,13 @@ void loadFontDescription(const Node& node, const std::string& family, const std:
scene->pendingFonts--;
});
} else {
// Load from local storage
size_t dataSize = 0;

if (unsigned char* data = bytesFromFile(_ft.uri.c_str(), dataSize)) {
auto data = bytesFromFile(_ft.uri.c_str());

LOGN("Add local font %s (%s)", _ft.uri.c_str(), _ft.bundleAlias.c_str());
scene->fontContext()->addFont(_ft, alfons::InputSource(reinterpret_cast<char*>(data), dataSize));
} else {
if (data.size() == 0) {
LOGW("Local font at path %s can't be found (%s)", _ft.uri.c_str(), _ft.bundleAlias.c_str());
} else {
LOGN("Adding local font %s (%s)", _ft.uri.c_str(), _ft.bundleAlias.c_str());
scene->fontContext()->addFont(_ft, alfons::InputSource(std::move(data)));
}
}
}
Expand Down
20 changes: 7 additions & 13 deletions core/src/text/fontContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,34 +284,28 @@ std::shared_ptr<alfons::Font> FontContext::getFont(const std::string& _family, c
auto font = m_alfons.getFont(FontDescription::Alias(_family, _style, _weight), fontSize);
if (font->hasFaces()) { return font; }

unsigned char* data = nullptr;
size_t dataSize = 0;

// 1. Bundle
// Assuming bundled ttf file follows this convention
std::string bundleFontPath = m_sceneResourceRoot + "fonts/" +
FontDescription::BundleAlias(_family, _style, _weight);

data = bytesFromFile(bundleFontPath.c_str(), dataSize);
std::vector<char> fontData = bytesFromFile(bundleFontPath.c_str());

// 2. System font
if (!data) {
data = systemFont(_family, _weight, _style, &dataSize);
if (fontData.size() == 0) {
fontData = systemFont(_family, _weight, _style);
}

if (data) {
font->addFace(m_alfons.addFontFace(alfons::InputSource(reinterpret_cast<char*>(data), dataSize), fontSize));
free(data);
if (fontData.size() == 0) {
LOGN("Could not load font file %s", FontDescription::BundleAlias(_family, _style, _weight).c_str());

// add fallbacks from default font
// 3. Add fallbacks from default font
if (m_font[sizeIndex]) {
font->addFaces(*m_font[sizeIndex]);
}

} else {
LOGN("Could not load font file %s", FontDescription::BundleAlias(_family, _style, _weight).c_str());
font->addFace(m_alfons.addFontFace(alfons::InputSource(std::move(fontData)), fontSize));

// add fallbacks from default font
if (m_font[sizeIndex]) {
font->addFaces(*m_font[sizeIndex]);
}
Expand Down
2 changes: 1 addition & 1 deletion external/alfons
4 changes: 3 additions & 1 deletion ios/src/TGFontConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>

#import <vector>

@interface TGFontConverter : NSObject

+ (unsigned char *)fontDataForCGFont:(CGFontRef)cgFont size:(size_t *)size;
+ (std::vector<char>)fontDataForCGFont:(CGFontRef)cgFont;

@end

Expand Down
Loading

0 comments on commit d93cf4f

Please sign in to comment.