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

[core] GL performance fixes #9255

Merged
merged 9 commits into from
Jun 14, 2017
1 change: 1 addition & 0 deletions cmake/core-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ set(MBGL_CORE_FILES
src/mbgl/programs/line_program.cpp
src/mbgl/programs/line_program.hpp
src/mbgl/programs/program.hpp
src/mbgl/programs/program_parameters.cpp
src/mbgl/programs/program_parameters.hpp
src/mbgl/programs/programs.hpp
src/mbgl/programs/raster_program.cpp
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Map : private util::noncopyable {
GLContextMode contextMode = GLContextMode::Unique,
ConstrainMode constrainMode = ConstrainMode::HeightOnly,
ViewportMode viewportMode = ViewportMode::Default,
const std::string& programCacheDir = "");
const optional<std::string>& programCacheDir = {});
~Map();

// Register a callback that will get called (on the render thread) when all resources have
Expand Down
96 changes: 58 additions & 38 deletions scripts/generate-shaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,42 +61,62 @@ ${fragmentPrelude}
'symbol_icon',
'symbol_sdf'
].forEach(function (shaderName) {
function applyPragmas(source, pragmas) {
return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => {
const a_type = type === "float" ? "vec2" : "vec4";
return pragmas[operation]
.join("\n")
.replace(/\{type\}/g, type)
.replace(/\{a_type}/g, a_type)
.replace(/\{precision\}/g, precision)
.replace(/\{name\}/g, name);
});
}

function vertexSource() {
const source = fs.readFileSync(path.join(inputPath, shaderName + '.vertex.glsl'), 'utf8');
return applyPragmas(source, {
define: [
"uniform lowp float a_{name}_t;",
"attribute {precision} {a_type} a_{name};",
"varying {precision} {type} {name};"
],
initialize: [
"{name} = unpack_mix_{a_type}(a_{name}, a_{name}_t);"
]
});
}

function fragmentSource() {
const source = fs.readFileSync(path.join(inputPath, shaderName + '.fragment.glsl'), 'utf8');
return applyPragmas(source, {
define: [
"varying {precision} {type} {name};"
],
initialize: [
]
});
}
const re = /#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g;
const fragmentPragmas = new Set();

let fragmentSource = fs.readFileSync(path.join(inputPath, shaderName + '.fragment.glsl'), 'utf8');
let vertexSource = fs.readFileSync(path.join(inputPath, shaderName + '.vertex.glsl'), 'utf8');

fragmentSource = fragmentSource.replace(re, (match, operation, precision, type, name) => {
fragmentPragmas.add(name);
return operation === "define" ? `
#ifndef HAS_UNIFORM_u_${name}
varying ${precision} ${type} ${name};
#else
uniform ${precision} ${type} u_${name};
#endif
` : `
#ifdef HAS_UNIFORM_u_${name}
${precision} ${type} ${name} = u_${name};
#endif
`;
});

vertexSource = vertexSource.replace(re, (match, operation, precision, type, name) => {
const a_type = type === "float" ? "vec2" : "vec4";
if (fragmentPragmas.has(name)) {
return operation === "define" ? `
#ifdef HAS_UNIFORM_u_${name}
uniform lowp float a_${name}_t;
attribute ${precision} ${a_type} a_${name};
varying ${precision} ${type} ${name};
#else
uniform ${precision} ${type} u_${name};
#endif
` : `
#ifndef HAS_UNIFORM_u_${name}
${name} = unpack_mix_${a_type}(a_${name}, a_${name}_t);
#else
${precision} ${type} ${name} = u_${name};
#endif
`;
} else {
return operation === "define" ? `
#ifdef HAS_UNIFORM_u_${name}
uniform lowp float a_${name}_t;
attribute ${precision} ${a_type} a_${name};
#else
uniform ${precision} ${type} u_${name};
#endif
` : `
#ifndef HAS_UNIFORM_u_${name}
${precision} ${type} ${name} = unpack_mix_${a_type}(a_${name}, a_${name}_t);
#else
${precision} ${type} ${name} = u_${name};
#endif
`;
}
});

writeIfModified(path.join(outputPath, `${shaderName}.hpp`), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.

Expand Down Expand Up @@ -125,10 +145,10 @@ namespace shaders {

const char* ${shaderName}::name = "${shaderName}";
const char* ${shaderName}::vertexSource = R"MBGL_SHADER(
${vertexSource()}
${vertexSource}
)MBGL_SHADER";
const char* ${shaderName}::fragmentSource = R"MBGL_SHADER(
${fragmentSource()}
${fragmentSource}
)MBGL_SHADER";

} // namespace shaders
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/gl/attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void VariableAttributeBinding<T, N>::bind(Context& context,
}
context.vertexBuffer = vertexBuffer;
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
oldBinding = *this;
MBGL_CHECK_ERROR(glVertexAttribPointer(
location,
static_cast<GLint>(attributeSize),
Expand Down
11 changes: 5 additions & 6 deletions src/mbgl/gl/program.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,17 @@ class Program {
const char* vertexSource_,
const char* fragmentSource_) {
#if MBGL_HAS_BINARY_PROGRAMS
if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) {
optional<std::string> cachePath = programParameters.cachePath(name);
if (cachePath && context.supportsProgramBinaries()) {
const std::string vertexSource =
shaders::vertexSource(programParameters, vertexSource_);
const std::string fragmentSource =
shaders::fragmentSource(programParameters, fragmentSource_);
const std::string cachePath =
shaders::programCachePath(programParameters, name);
const std::string identifier =
shaders::programIdentifier(vertexSource, fragmentSource_);

try {
if (auto cachedBinaryProgram = util::readFile(cachePath)) {
if (auto cachedBinaryProgram = util::readFile(*cachePath)) {
const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
if (binaryProgram.identifier() == identifier) {
return Program { context, binaryProgram };
Expand All @@ -82,8 +81,8 @@ class Program {
try {
if (const auto binaryProgram =
result.template get<BinaryProgram>(context, identifier)) {
util::write_file(cachePath, binaryProgram->serialize());
Log::Warning(Event::OpenGL, "Caching program in: %s", cachePath.c_str());
util::write_file(*cachePath, binaryProgram->serialize());
Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str());
}
} catch (std::runtime_error& error) {
Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what());
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/gl/uniform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Uniform {
class State {
public:
void operator=(const Value& value) {
if (!current || *current != value.t) {
if (location >= 0 && (!current || *current != value.t)) {
current = value.t;
bindUniform(location, value.t);
}
Expand Down
8 changes: 4 additions & 4 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Map::Impl : public style::Observer {
GLContextMode,
ConstrainMode,
ViewportMode,
const std::string& programCacheDir);
optional<std::string> programCacheDir);

void onSourceChanged(style::Source&) override;
void onUpdate(Update) override;
Expand All @@ -83,7 +83,7 @@ class Map::Impl : public style::Observer {
const MapMode mode;
const GLContextMode contextMode;
const float pixelRatio;
const std::string programCacheDir;
const optional<std::string> programCacheDir;

MapDebugOptions debugOptions { MapDebugOptions::NoDebug };

Expand Down Expand Up @@ -116,7 +116,7 @@ Map::Map(Backend& backend,
GLContextMode contextMode,
ConstrainMode constrainMode,
ViewportMode viewportMode,
const std::string& programCacheDir)
const optional<std::string>& programCacheDir)
: impl(std::make_unique<Impl>(*this,
backend,
pixelRatio,
Expand All @@ -139,7 +139,7 @@ Map::Impl::Impl(Map& map_,
GLContextMode contextMode_,
ConstrainMode constrainMode_,
ViewportMode viewportMode_,
const std::string& programCacheDir_)
optional<std::string> programCacheDir_)
: map(map_),
observer(backend_),
backend(backend_),
Expand Down
37 changes: 35 additions & 2 deletions src/mbgl/programs/program.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
#include <mbgl/shaders/shaders.hpp>
#include <mbgl/util/io.hpp>

#include <unordered_map>

namespace mbgl {

template <class Shaders,
class Primitive,
class LayoutAttrs,
class Uniforms,
class PaintProperties>
class PaintProps>
class Program {
public:
using LayoutAttributes = LayoutAttrs;
using LayoutVertex = typename LayoutAttributes::Vertex;

using PaintProperties = PaintProps;
using PaintPropertyBinders = typename PaintProperties::Binders;
using PaintAttributes = typename PaintPropertyBinders::Attributes;
using Attributes = gl::ConcatenateAttributes<LayoutAttributes, PaintAttributes>;
Expand Down Expand Up @@ -62,7 +65,7 @@ class Program {
std::move(stencilMode),
std::move(colorMode),
uniformValues
.concat(paintPropertyBinders.uniformValues(currentZoom)),
.concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)),
LayoutAttributes::allVariableBindings(layoutVertexBuffer)
.concat(paintPropertyBinders.attributeBindings(currentProperties)),
indexBuffer,
Expand All @@ -71,4 +74,34 @@ class Program {
}
};

template <class Program>
class ProgramMap {
public:
using PaintProperties = typename Program::PaintProperties;
using PaintPropertyBinders = typename Program::PaintPropertyBinders;
using Bitset = typename PaintPropertyBinders::Bitset;

ProgramMap(gl::Context& context_, ProgramParameters parameters_)
: context(context_),
parameters(std::move(parameters_)) {
}

Program& get(const typename PaintProperties::Evaluated& currentProperties) {
Bitset bits = PaintPropertyBinders::constants(currentProperties);
auto it = programs.find(bits);
if (it != programs.end()) {
return it->second;
}
return programs.emplace(std::piecewise_construct,
std::forward_as_tuple(bits),
std::forward_as_tuple(context,
parameters.withAdditionalDefines(PaintPropertyBinders::defines(currentProperties)))).first->second;
}

private:
gl::Context& context;
ProgramParameters parameters;
std::unordered_map<Bitset, Program> programs;
};

} // namespace mbgl
48 changes: 48 additions & 0 deletions src/mbgl/programs/program_parameters.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <mbgl/programs/program_parameters.hpp>

#include <iomanip>
#include <sstream>

namespace mbgl {

ProgramParameters::ProgramParameters(const float pixelRatio,
const bool overdraw,
optional<std::string> cacheDir_)
: defines([&] {
std::ostringstream ss;
ss.imbue(std::locale("C"));
ss.setf(std::ios_base::showpoint);
ss << "#define DEVICE_PIXEL_RATIO " << pixelRatio << std::endl;
if (overdraw) {
ss << "#define OVERDRAW_INSPECTOR" << std::endl;
}
return ss.str();
}()),
cacheDir(std::move(cacheDir_)) {
}

const std::string& ProgramParameters::getDefines() const {
return defines;
}

optional<std::string> ProgramParameters::cachePath(const char* name) const {
if (!cacheDir) {
return {};
} else {
std::ostringstream ss;
ss << *cacheDir << "/com.mapbox.gl.shader." << name << "." << std::setfill('0')
<< std::setw(sizeof(size_t) * 2) << std::hex << std::hash<std::string>()(defines) << ".pbf";
return ss.str();
}
}

ProgramParameters ProgramParameters::withAdditionalDefines(const std::vector<std::string>& additionalDefines) const {
ProgramParameters result(*this);
for (const auto& define : additionalDefines) {
result.defines += define;
result.defines += "\n";
}
return result;
}

} // namespace mbgl
23 changes: 13 additions & 10 deletions src/mbgl/programs/program_parameters.hpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
#pragma once

#include <mbgl/util/optional.hpp>

#include <string>
#include <vector>

namespace mbgl {

class ProgramParameters {
public:
ProgramParameters(float pixelRatio_ = 1.0,
bool overdraw_ = false,
const std::string& cacheDir_ = "")
: pixelRatio(pixelRatio_), overdraw(overdraw_), cacheDir(cacheDir_) {
}

const float pixelRatio;
const bool overdraw;
const std::string cacheDir;
ProgramParameters(float pixelRatio, bool overdraw, optional<std::string> cacheDir);

const std::string& getDefines() const;
optional<std::string> cachePath(const char* name) const;

ProgramParameters withAdditionalDefines(const std::vector<std::string>& defines) const;

private:
std::string defines;
optional<std::string> cacheDir;
};

} // namespace mbgl

Loading