From df5a39570819abc6e083bee8bc1fc9da8d92b68c Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Sat, 18 Jun 2016 19:11:30 +0300 Subject: [PATCH] [core] Refactor wireframe to match JS overdraw mode --- src/mbgl/map/map.cpp | 2 +- src/mbgl/renderer/painter.cpp | 13 +++-- src/mbgl/renderer/painter.hpp | 2 + src/mbgl/renderer/painter_background.cpp | 16 ++----- src/mbgl/renderer/painter_circle.cpp | 2 +- src/mbgl/renderer/painter_fill.cpp | 22 +++------ src/mbgl/renderer/painter_line.cpp | 17 ++----- src/mbgl/renderer/painter_raster.cpp | 2 +- src/mbgl/renderer/painter_symbol.cpp | 4 +- src/mbgl/shader/shader.cpp | 61 ++++++++++++++++-------- src/mbgl/shader/shader.hpp | 11 ++++- src/mbgl/style/style.cpp | 7 ++- src/mbgl/style/style.hpp | 2 +- 13 files changed, 91 insertions(+), 70 deletions(-) diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 11bc89a1a..f4cca3b2b 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -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) diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index ca536f667..fae5c74d7 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -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& order = renderData.order; const std::set& 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 { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 4c51543bd..d2d722ef7 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -156,6 +156,8 @@ private: void setDepthSublayer(int n); + bool isWireframe() const { return frame.debugOptions & MapDebugOptions::Wireframe; } + mat4 projMatrix; mat4 nativeMatrix; diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp index 022d3dd7a..f9a67ee59 100644 --- a/src/mbgl/renderer/painter_background.cpp +++ b/src/mbgl/renderer/painter_background.cpp @@ -21,9 +21,6 @@ void Painter::renderBackground(const BackgroundLayer& layer) { optional imagePosA; optional 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); } diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp index 24cc9806e..d92ca1ae9 100644 --- a/src/mbgl/renderer/painter_circle.cpp +++ b/src/mbgl/renderer/painter_circle.cpp @@ -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; diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 710fa444e..62e808614 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -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; diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index bb759abc5..447e3f740 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -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; diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp index f3a0b720e..6394d61dc 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painter_raster.cpp @@ -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; diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index b65ae34a1..374500986 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -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 }}; diff --git a/src/mbgl/shader/shader.cpp b/src/mbgl/shader/shader.cpp index e2c7776e4..80c4c33ef 100644 --- a/src/mbgl/shader/shader.cpp +++ b/src/mbgl/shader/shader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -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(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(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(std::strlen(*source)); - MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, source, &lengths)); + const GLsizei lengths = static_cast(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 diff --git a/src/mbgl/shader/shader.hpp b/src/mbgl/shader/shader.hpp index 3ba1e044c..4289b83a7 100644 --- a/src/mbgl/shader/shader.hpp +++ b/src/mbgl/shader/shader.hpp @@ -3,6 +3,7 @@ #include #include #include +#include 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 programOverdraw; + mbgl::optional overdrawShader; }; } // namespace mbgl diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index cfeff6d40..c3bc5d73a 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -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()) { + 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(). diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 1a41c4ce4..35369ffca 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -74,7 +74,7 @@ public: void setClasses(const std::vector&, const TransitionOptions& = {}); std::vector getClasses() const; - RenderData getRenderData() const; + RenderData getRenderData(MapDebugOptions) const; std::vector queryRenderedFeatures(const QueryParameters&) const;