[core] Refactor wireframe to match JS overdraw mode

This commit is contained in:
Bruno de Oliveira Abinader
2016-06-18 19:11:30 +03:00
parent 7e549b9020
commit df5a395708
13 changed files with 91 additions and 70 deletions

View File

@@ -794,7 +794,7 @@ void Map::cycleDebugOptions() {
impl->debugOptions = MapDebugOptions::NoDebug;
#endif // GL_ES_VERSION_2_0
else if (impl->debugOptions & MapDebugOptions::Collision)
impl->debugOptions = MapDebugOptions::Collision | MapDebugOptions::Wireframe;
impl->debugOptions = MapDebugOptions::Wireframe;
else if (impl->debugOptions & MapDebugOptions::Timestamps)
impl->debugOptions = impl->debugOptions | MapDebugOptions::Collision;
else if (impl->debugOptions & MapDebugOptions::ParseStatus)

View File

@@ -92,7 +92,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
spriteAtlas = style.spriteAtlas.get();
lineAtlas = style.lineAtlas.get();
RenderData renderData = style.getRenderData();
RenderData renderData = style.getRenderData(frame.debugOptions);
const std::vector<RenderItem>& order = renderData.order;
const std::set<Source*>& sources = renderData.sources;
const Color& background = renderData.backgroundColor;
@@ -144,7 +144,12 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
config.depthTest = GL_FALSE;
config.depthMask = GL_TRUE;
config.colorMask = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
if (frame.debugOptions & MapDebugOptions::Wireframe) {
if (isWireframe()) {
config.blend = GL_TRUE;
config.blendFunc = { GL_CONSTANT_COLOR, GL_ONE };
const float overdraw = 1.0f / 8.0f;
config.blendColor = { overdraw, overdraw, overdraw, 0.0f };
config.clearColor = Color::black();
} else {
config.clearColor = background;
@@ -243,7 +248,9 @@ void Painter::renderPass(RenderPass pass_,
if (!layer.baseImpl->hasRenderPass(pass))
continue;
if (pass == RenderPass::Translucent) {
if (isWireframe()) {
config.blend = GL_TRUE;
} else if (pass == RenderPass::Translucent) {
config.blendFunc.reset();
config.blend = GL_TRUE;
} else {

View File

@@ -156,6 +156,8 @@ private:
void setDepthSublayer(int n);
bool isWireframe() const { return frame.debugOptions & MapDebugOptions::Wireframe; }
mat4 projMatrix;
mat4 nativeMatrix;

View File

@@ -21,9 +21,6 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
optional<SpriteAtlasPosition> imagePosA;
optional<SpriteAtlasPosition> imagePosB;
bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
isPatterned &= !wireframe;
if (isPatterned) {
imagePosA = spriteAtlas->getPosition(properties.backgroundPattern.value.from, true);
imagePosB = spriteAtlas->getPosition(properties.backgroundPattern.value.to, true);
@@ -31,7 +28,7 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
if (!imagePosA || !imagePosB)
return;
config.program = patternShader->getID();
config.program = isWireframe() ? patternShader->getOverdrawID() : patternShader->getID();
patternShader->u_matrix = identityMatrix;
patternShader->u_pattern_tl_a = imagePosA->tl;
patternShader->u_pattern_br_a = imagePosA->br;
@@ -44,15 +41,10 @@ void Painter::renderBackground(const BackgroundLayer& layer) {
backgroundPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
} else {
if (wireframe) {
plainShader->u_color = Color::black();
plainShader->u_opacity = 1.0f;
} else {
plainShader->u_color = properties.backgroundColor;
plainShader->u_opacity = properties.backgroundOpacity;
}
plainShader->u_color = properties.backgroundColor;
plainShader->u_opacity = properties.backgroundOpacity;
config.program = plainShader->getID();
config.program = isWireframe() ? plainShader->getOverdrawID() : plainShader->getID();
backgroundArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0), store);
}

View File

@@ -27,7 +27,7 @@ void Painter::renderCircle(CircleBucket& bucket,
mat4 vtxMatrix = translatedMatrix(matrix, properties.circleTranslate, tileID,
properties.circleTranslateAnchor);
config.program = circleShader->getID();
config.program = isWireframe() ? circleShader->getOverdrawID() : circleShader->getID();
circleShader->u_matrix = vtxMatrix;
circleShader->u_extrude_scale = extrudeScale;

View File

@@ -36,16 +36,6 @@ void Painter::renderFill(FillBucket& bucket,
bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined;
bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
if (wireframe) {
fillColor = Color::white();
strokeColor = Color::white();
opacity = 1.0f;
pattern = false;
outline = true;
fringeline = true;
}
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
config.depthFunc.reset();
@@ -56,7 +46,7 @@ void Painter::renderFill(FillBucket& bucket,
// Because we're drawing top-to-bottom, and we update the stencil mask
// befrom, we have to draw the outline first (!)
if (outline && pass == RenderPass::Translucent) {
config.program = outlineShader->getID();
config.program = isWireframe() ? outlineShader->getOverdrawID() : outlineShader->getID();
outlineShader->u_matrix = vertexMatrix;
outlineShader->u_outline_color = strokeColor;
@@ -86,7 +76,7 @@ void Painter::renderFill(FillBucket& bucket,
// Image fill.
if (pass == RenderPass::Translucent && imagePosA && imagePosB) {
config.program = patternShader->getID();
config.program = isWireframe() ? patternShader->getOverdrawID() : patternShader->getID();
patternShader->u_matrix = vertexMatrix;
patternShader->u_pattern_tl_a = imagePosA->tl;
patternShader->u_pattern_br_a = imagePosA->br;
@@ -115,7 +105,7 @@ void Painter::renderFill(FillBucket& bucket,
bucket.drawElements(*patternShader, store);
if (properties.fillAntialias && !isOutlineColorDefined) {
config.program = outlinePatternShader->getID();
config.program = isWireframe() ? outlinePatternShader->getOverdrawID() : outlinePatternShader->getID();
outlinePatternShader->u_matrix = vertexMatrix;
// Draw the entire line
@@ -143,14 +133,14 @@ void Painter::renderFill(FillBucket& bucket,
bucket.drawVertices(*outlinePatternShader, store);
}
}
} else if (!wireframe) {
} else {
// No image fill.
if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
// Only draw the fill when it's either opaque and we're drawing opaque
// fragments or when it's translucent and we're drawing translucent
// fragments
// Draw filling rectangle.
config.program = plainShader->getID();
config.program = isWireframe() ? plainShader->getOverdrawID() : plainShader->getID();
plainShader->u_matrix = vertexMatrix;
plainShader->u_color = fillColor;
plainShader->u_opacity = opacity;
@@ -164,7 +154,7 @@ void Painter::renderFill(FillBucket& bucket,
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
if (fringeline && pass == RenderPass::Translucent) {
config.program = outlineShader->getID();
config.program = isWireframe() ? outlineShader->getOverdrawID() : outlineShader->getID();
outlineShader->u_matrix = vertexMatrix;
outlineShader->u_outline_color = fillColor;

View File

@@ -33,17 +33,10 @@ void Painter::renderLine(LineBucket& bucket,
// Retina devices need a smaller distance to avoid aliasing.
float antialiasing = 1.0 / frame.pixelRatio;
bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
float blur = properties.lineBlur + antialiasing;
Color color = Color::white();
float opacity = 1.0f;
if (!wireframe) {
color = properties.lineColor;
opacity = properties.lineOpacity;
}
const Color color = properties.lineColor;
const float opacity = properties.lineOpacity;
const float ratio = 1.0 / tileID.pixelsToTileUnits(1.0, state.getZoom());
mat2 antialiasingMatrix;
@@ -64,7 +57,7 @@ void Painter::renderLine(LineBucket& bucket,
if (!properties.lineDasharray.value.from.empty()) {
config.program = linesdfShader->getID();
config.program = isWireframe() ? linesdfShader->getOverdrawID() : linesdfShader->getID();
linesdfShader->u_matrix = vtxMatrix;
linesdfShader->u_linewidth = properties.lineWidth / 2;
@@ -109,7 +102,7 @@ void Painter::renderLine(LineBucket& bucket,
if (!imagePosA || !imagePosB)
return;
config.program = linepatternShader->getID();
config.program = isWireframe() ? linepatternShader->getOverdrawID() : linepatternShader->getID();
linepatternShader->u_matrix = vtxMatrix;
linepatternShader->u_linewidth = properties.lineWidth / 2;
@@ -145,7 +138,7 @@ void Painter::renderLine(LineBucket& bucket,
bucket.drawLinePatterns(*linepatternShader, store);
} else {
config.program = lineShader->getID();
config.program = isWireframe() ? lineShader->getOverdrawID() : lineShader->getID();
lineShader->u_matrix = vtxMatrix;
lineShader->u_linewidth = properties.lineWidth / 2;

View File

@@ -18,7 +18,7 @@ void Painter::renderRaster(RasterBucket& bucket,
const RasterPaintProperties& properties = layer.impl->paint;
if (bucket.hasData()) {
config.program = rasterShader->getID();
config.program = isWireframe() ? rasterShader->getOverdrawID() : rasterShader->getID();
rasterShader->u_matrix = matrix;
rasterShader->u_buffer = 0;
rasterShader->u_opacity = properties.rasterOpacity;

View File

@@ -58,7 +58,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
exScale = {{ exScale[0] * scale, exScale[1] * scale }};
}
config.program = sdfShader.getID();
config.program = isWireframe() ? sdfShader.getOverdrawID() : sdfShader.getID();
sdfShader.u_matrix = vtxMatrix;
sdfShader.u_extrude_scale = exScale;
sdfShader.u_texsize = texsize;
@@ -199,7 +199,7 @@ void Painter::renderSymbol(SymbolBucket& bucket,
exScale = {{ exScale[0] * scale, exScale[1] * scale }};
}
config.program = iconShader->getID();
config.program = isWireframe() ? iconShader->getOverdrawID() : iconShader->getID();
iconShader->u_matrix = vtxMatrix;
iconShader->u_extrude_scale = exScale;
iconShader->u_texsize = {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }};

View File

@@ -8,6 +8,7 @@
#include <cstring>
#include <cassert>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
@@ -21,12 +22,12 @@ Shader::Shader(const char* name_, const char* vertexSource, const char* fragment
{
util::stopwatch stopwatch("shader compilation", Event::Shader);
if (!compileShader(vertexShader, &vertexSource)) {
if (!compileShader(vertexShader, vertexSource)) {
Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource);
throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
}
if (!compileShader(fragmentShader, &fragmentSource)) {
if (!compileShader(fragmentShader, fragmentSource)) {
Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource);
throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
}
@@ -35,32 +36,50 @@ Shader::Shader(const char* name_, const char* vertexSource, const char* fragment
MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get()));
MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get()));
{
// Link program
GLint status;
MBGL_CHECK_ERROR(glLinkProgram(program.get()));
linkProgram(program);
MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
if (status == 0) {
GLint logLength;
MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
const auto log = std::make_unique<GLchar[]>(logLength);
if (logLength > 0) {
MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
}
throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
std::string overdrawSource(fragmentSource);
if (overdrawSource.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos) {
programOverdraw = store.createProgram();
overdrawShader = store.createShader(GL_FRAGMENT_SHADER);
overdrawSource.replace(overdrawSource.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n");
if (!compileShader(*overdrawShader, overdrawSource.c_str())) {
Log::Error(Event::Shader, "Overdraw shader %s failed to compile: %s", name, overdrawSource.c_str());
throw util::ShaderException(std::string { "Overdraw shader " } + name + " failed to compile");
}
MBGL_CHECK_ERROR(glAttachShader(*programOverdraw, vertexShader.get()));
MBGL_CHECK_ERROR(glAttachShader(*programOverdraw, *overdrawShader));
linkProgram(*programOverdraw);
}
a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), "a_pos"));
}
bool Shader::compileShader(gl::UniqueShader& shader, const GLchar *source[]) {
void Shader::linkProgram(gl::UniqueProgram& program_) {
// Link program
GLint status;
MBGL_CHECK_ERROR(glLinkProgram(program_.get()));
MBGL_CHECK_ERROR(glGetProgramiv(program_.get(), GL_LINK_STATUS, &status));
if (status == 0) {
GLint logLength;
MBGL_CHECK_ERROR(glGetProgramiv(program_.get(), GL_INFO_LOG_LENGTH, &logLength));
const auto log = std::make_unique<GLchar[]>(logLength);
if (logLength > 0) {
MBGL_CHECK_ERROR(glGetProgramInfoLog(program_.get(), logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
}
throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
}
}
bool Shader::compileShader(gl::UniqueShader& shader, const GLchar *source) {
GLint status = 0;
const GLsizei lengths = static_cast<GLsizei>(std::strlen(*source));
MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, source, &lengths));
const GLsizei lengths = static_cast<GLsizei>(std::strlen(source));
MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths));
MBGL_CHECK_ERROR(glCompileShader(shader.get()));
@@ -90,6 +109,10 @@ Shader::~Shader() {
MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get()));
MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get()));
}
if (programOverdraw) {
MBGL_CHECK_ERROR(glDetachShader(*programOverdraw, vertexShader.get()));
MBGL_CHECK_ERROR(glDetachShader(*programOverdraw, *overdrawShader));
}
}
} // namespace mbgl

View File

@@ -3,6 +3,7 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/object_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
@@ -15,6 +16,10 @@ public:
return program.get();
}
GLuint getOverdrawID() const {
return programOverdraw ? *programOverdraw : 0;
}
virtual void bind(GLbyte *offset) = 0;
protected:
@@ -22,11 +27,15 @@ protected:
GLint a_pos = -1;
private:
bool compileShader(gl::UniqueShader&, const GLchar *source[]);
bool compileShader(gl::UniqueShader&, const GLchar *source);
void linkProgram(gl::UniqueProgram&);
gl::UniqueProgram program;
gl::UniqueShader vertexShader;
gl::UniqueShader fragmentShader;
mbgl::optional<gl::UniqueProgram> programOverdraw;
mbgl::optional<gl::UniqueShader> overdrawShader;
};
} // namespace mbgl

View File

@@ -258,7 +258,7 @@ bool Style::isLoaded() const {
return true;
}
RenderData Style::getRenderData() const {
RenderData Style::getRenderData(MapDebugOptions debugOptions) const {
RenderData result;
for (const auto& source : sources) {
@@ -272,6 +272,11 @@ RenderData Style::getRenderData() const {
continue;
if (const BackgroundLayer* background = layer->as<BackgroundLayer>()) {
if (debugOptions & MapDebugOptions::Wireframe) {
// We want to skip glClear optimization in wireframe mode.
result.order.emplace_back(*layer);
continue;
}
const BackgroundPaintProperties& paint = background->impl->paint;
if (layer.get() == layers[0].get() && paint.backgroundPattern.value.from.empty()) {
// This is a solid background. We can use glClear().

View File

@@ -74,7 +74,7 @@ public:
void setClasses(const std::vector<std::string>&, const TransitionOptions& = {});
std::vector<std::string> getClasses() const;
RenderData getRenderData() const;
RenderData getRenderData(MapDebugOptions) const;
std::vector<Feature> queryRenderedFeatures(const QueryParameters&) const;