diff --git a/data/resources-default/smaa-area.png b/data/resources-default/smaa-area.png new file mode 100644 index 0000000000..a11af5907a Binary files /dev/null and b/data/resources-default/smaa-area.png differ diff --git a/data/resources-default/smaa-search.png b/data/resources-default/smaa-search.png new file mode 100644 index 0000000000..25873d346f Binary files /dev/null and b/data/resources-default/smaa-search.png differ diff --git a/drape/drape_global.hpp b/drape/drape_global.hpp index d3933057d0..8511bd8cf4 100644 --- a/drape/drape_global.hpp +++ b/drape/drape_global.hpp @@ -16,6 +16,7 @@ enum TextureFormat { RGBA8, ALPHA, + RED_GREEN, UNSPECIFIED }; @@ -26,6 +27,7 @@ inline uint8_t GetBytesPerPixel(TextureFormat format) { case RGBA8: result = 4; break; case ALPHA: result = 1; break; + case RED_GREEN: result = 2; break; default: ASSERT(false, ()); break; } return result; diff --git a/drape/drape_tests/glfunctions.cpp b/drape/drape_tests/glfunctions.cpp index 0b345dbd34..4143744bf0 100644 --- a/drape/drape_tests/glfunctions.cpp +++ b/drape/drape_tests/glfunctions.cpp @@ -318,6 +318,10 @@ void GLFunctions::glDrawArrays(glConst mode, int32_t first, uint32_t count) {} void GLFunctions::glPixelStore(glConst name, uint32_t value) {} +void GLFunctions::glStencilOpSeparate(glConst face, glConst sfail, glConst dpfail, glConst dppass) {} + +void GLFunctions::glStencilFuncSeparate(glConst face, glConst func, int ref, uint32_t mask) {} + int32_t GLFunctions::glGetBufferParameter(glConst target, glConst name) { return MOCK_CALL(glGetBufferParameter(target, name)); diff --git a/drape/drape_tests/static_texture_tests.cpp b/drape/drape_tests/static_texture_tests.cpp index 6d8c726755..b4bce9fd37 100644 --- a/drape/drape_tests/static_texture_tests.cpp +++ b/drape/drape_tests/static_texture_tests.cpp @@ -1,5 +1,8 @@ #include "testing/testing.hpp" +#include "indexer/map_style.hpp" +#include "indexer/map_style_reader.hpp" + #include "drape/static_texture.hpp" #include @@ -8,9 +11,20 @@ UNIT_TEST(CheckTrafficArrowTextures) { static std::vector skinPaths = {"6plus", "mdpi", "hdpi", "xhdpi", "xxhdpi"}; - for (size_t i = 0; i < skinPaths.size(); ++i) + static std::vector styles = {MapStyle::MapStyleClear, MapStyle::MapStyleDark, + MapStyle::MapStyleVehicleClear, + MapStyle::MapStyleVehicleDark}; + + for (auto const & style : styles) { - dp::StaticTexture texture("traffic-arrow", skinPaths[i], nullptr); - TEST(texture.IsLoadingCorrect(), ()); + GetStyleReader().SetCurrentStyle(style); + for (size_t i = 0; i < skinPaths.size(); ++i) + { + dp::StaticTexture texture("traffic-arrow", skinPaths[i], dp::RGBA8, nullptr); + TEST(texture.IsLoadingCorrect(), ()); + + dp::StaticTexture texture2("area-hatching", skinPaths[i], dp::RGBA8, nullptr); + TEST(texture2.IsLoadingCorrect(), ()); + } } } diff --git a/drape/framebuffer.cpp b/drape/framebuffer.cpp index 73d79173f5..39759deee7 100644 --- a/drape/framebuffer.cpp +++ b/drape/framebuffer.cpp @@ -1,7 +1,5 @@ #include "drape/framebuffer.hpp" - #include "drape/glfunctions.hpp" -#include "drape/oglcontext.hpp" #include "base/assert.hpp" #include "base/logging.hpp" @@ -9,7 +7,82 @@ namespace dp { +Framebuffer::DepthStencil::DepthStencil(bool stencilEnabled) + : m_stencilEnabled(stencilEnabled) +{ + if (m_stencilEnabled) + { + m_layout = gl_const::GLDepthStencil; + m_pixelType = gl_const::GLUnsignedInt24_8Type; + } + else + { + m_layout = gl_const::GLDepthComponent; + m_pixelType = gl_const::GLUnsignedIntType; + } +} + +Framebuffer::DepthStencil::~DepthStencil() +{ + Destroy(); +} + +void Framebuffer::DepthStencil::SetSize(uint32_t width, uint32_t height) +{ + Destroy(); + + m_textureId = GLFunctions::glGenTexture(); + GLFunctions::glBindTexture(m_textureId); + GLFunctions::glTexImage2D(width, height, m_layout, m_pixelType, nullptr); + if (GLFunctions::CurrentApiVersion == dp::ApiVersion::OpenGLES3) + { + GLFunctions::glTexParameter(gl_const::GLMagFilter, gl_const::GLNearest); + GLFunctions::glTexParameter(gl_const::GLMinFilter, gl_const::GLNearest); + GLFunctions::glTexParameter(gl_const::GLWrapT, gl_const::GLClampToEdge); + GLFunctions::glTexParameter(gl_const::GLWrapS, gl_const::GLClampToEdge); + } +} + +void Framebuffer::DepthStencil::Destroy() +{ + if (m_textureId != 0) + { + GLFunctions::glDeleteTexture(m_textureId); + m_textureId = 0; + } +} + +uint32_t Framebuffer::DepthStencil::GetDepthAttachmentId() const +{ + return m_textureId; +} + +uint32_t Framebuffer::DepthStencil::GetStencilAttachmentId() const +{ + return m_stencilEnabled ? m_textureId : 0; +} + +Framebuffer::Framebuffer() + : m_colorFormat(gl_const::GLRGBA) +{ + ApplyOwnDepthStencil(); +} + +Framebuffer::Framebuffer(uint32_t colorFormat) + : m_colorFormat(colorFormat) +{ + ApplyOwnDepthStencil(); +} + +Framebuffer::Framebuffer(uint32_t colorFormat, bool stencilEnabled) + : m_colorFormat(colorFormat) + , m_depthStencil(make_unique_dp(stencilEnabled)) +{ + ApplyOwnDepthStencil(); +} + Framebuffer::~Framebuffer() { Destroy(); } + void Framebuffer::Destroy() { if (m_colorTextureId != 0) @@ -18,11 +91,8 @@ void Framebuffer::Destroy() m_colorTextureId = 0; } - if (m_depthTextureId != 0) - { - GLFunctions::glDeleteTexture(m_depthTextureId); - m_depthTextureId = 0; - } + if (m_depthStencil != nullptr) + m_depthStencil->Destroy(); if (m_framebufferId != 0) { @@ -31,19 +101,21 @@ void Framebuffer::Destroy() } } -void Framebuffer::SetDefaultContext(dp::OGLContext * context) { m_defaultContext = context; } +void Framebuffer::SetFramebufferFallback(FramebufferFallback && fallback) +{ + m_framebufferFallback = std::move(fallback); +} + void Framebuffer::SetSize(uint32_t width, uint32_t height) { - ASSERT(m_defaultContext, ()); - if (!m_isSupported) return; if (m_width == width && m_height == height) return; - m_height = height; m_width = width; + m_height = height; Destroy(); @@ -56,16 +128,14 @@ void Framebuffer::SetSize(uint32_t width, uint32_t height) GLFunctions::glTexParameter(gl_const::GLWrapT, gl_const::GLClampToEdge); GLFunctions::glTexParameter(gl_const::GLWrapS, gl_const::GLClampToEdge); - m_depthTextureId = GLFunctions::glGenTexture(); - GLFunctions::glBindTexture(m_depthTextureId); - GLFunctions::glTexImage2D(m_width, m_height, gl_const::GLDepthComponent, - gl_const::GLUnsignedIntType, nullptr); - if (GLFunctions::CurrentApiVersion == dp::ApiVersion::OpenGLES3) + glConst depthAttachmentId = 0; + glConst stencilAttachmentId = 0; + if (m_depthStencilRef != nullptr) { - GLFunctions::glTexParameter(gl_const::GLMagFilter, gl_const::GLNearest); - GLFunctions::glTexParameter(gl_const::GLMinFilter, gl_const::GLNearest); - GLFunctions::glTexParameter(gl_const::GLWrapT, gl_const::GLClampToEdge); - GLFunctions::glTexParameter(gl_const::GLWrapS, gl_const::GLClampToEdge); + if (m_depthStencilRef == m_depthStencil.get()) + m_depthStencilRef->SetSize(m_width, m_height); + depthAttachmentId = m_depthStencilRef->GetDepthAttachmentId(); + stencilAttachmentId = m_depthStencilRef->GetStencilAttachmentId(); } GLFunctions::glBindTexture(0); @@ -74,8 +144,15 @@ void Framebuffer::SetSize(uint32_t width, uint32_t height) GLFunctions::glBindFramebuffer(m_framebufferId); GLFunctions::glFramebufferTexture2D(gl_const::GLColorAttachment, m_colorTextureId); - GLFunctions::glFramebufferTexture2D(gl_const::GLDepthAttachment, m_depthTextureId); - GLFunctions::glFramebufferTexture2D(gl_const::GLStencilAttachment, 0); + if (depthAttachmentId != stencilAttachmentId) + { + GLFunctions::glFramebufferTexture2D(gl_const::GLDepthAttachment, depthAttachmentId); + GLFunctions::glFramebufferTexture2D(gl_const::GLStencilAttachment, stencilAttachmentId); + } + else + { + GLFunctions::glFramebufferTexture2D(gl_const::GLDepthStencilAttachment, depthAttachmentId); + } uint32_t const status = GLFunctions::glCheckFramebufferStatus(); if (status != gl_const::GLFramebufferComplete) @@ -85,7 +162,18 @@ void Framebuffer::SetSize(uint32_t width, uint32_t height) LOG(LWARNING, ("Framebuffer is unsupported. Framebuffer status =", status)); } - m_defaultContext->setDefaultFramebuffer(); + if (m_framebufferFallback != nullptr) + m_framebufferFallback(); +} + +void Framebuffer::SetDepthStencilRef(ref_ptr depthStencilRef) +{ + m_depthStencilRef = depthStencilRef; +} + +void Framebuffer::ApplyOwnDepthStencil() +{ + m_depthStencilRef = make_ref(m_depthStencil); } void Framebuffer::Enable() @@ -96,10 +184,15 @@ void Framebuffer::Enable() void Framebuffer::Disable() { - ASSERT(m_defaultContext, ()); ASSERT(m_isSupported, ()); - m_defaultContext->setDefaultFramebuffer(); + if (m_framebufferFallback != nullptr) + m_framebufferFallback(); } uint32_t Framebuffer::GetTextureId() const { return m_colorTextureId; } + +ref_ptr Framebuffer::GetDepthStencilRef() const +{ + return m_depthStencilRef; +} } // namespace dp diff --git a/drape/framebuffer.hpp b/drape/framebuffer.hpp index 39de064799..96a95c2dcb 100644 --- a/drape/framebuffer.hpp +++ b/drape/framebuffer.hpp @@ -1,37 +1,61 @@ #pragma once +#include "drape/pointers.hpp" + #include +#include namespace dp { -class OGLContext; +using FramebufferFallback = std::function; class Framebuffer { public: - Framebuffer() = default; + class DepthStencil + { + public: + DepthStencil(bool stencilEnabled); + ~DepthStencil(); + void SetSize(uint32_t width, uint32_t height); + void Destroy(); + uint32_t GetDepthAttachmentId() const; + uint32_t GetStencilAttachmentId() const; + private: + bool const m_stencilEnabled = false; + uint32_t m_layout = 0; + uint32_t m_pixelType = 0; + uint32_t m_textureId = 0; + }; + + Framebuffer(); + Framebuffer(uint32_t colorFormat); + Framebuffer(uint32_t colorFormat, bool stencilEnabled); ~Framebuffer(); - void SetDefaultContext(dp::OGLContext * context); + void SetFramebufferFallback(FramebufferFallback && fallback); void SetSize(uint32_t width, uint32_t height); + void SetDepthStencilRef(ref_ptr depthStencilRef); + void ApplyOwnDepthStencil(); void Enable(); void Disable(); uint32_t GetTextureId() const; + ref_ptr GetDepthStencilRef() const; + bool IsSupported() const { return m_isSupported; } private: void Destroy(); + drape_ptr m_depthStencil; + ref_ptr m_depthStencilRef; uint32_t m_width = 0; uint32_t m_height = 0; - uint32_t m_colorTextureId = 0; - uint32_t m_depthTextureId = 0; uint32_t m_framebufferId = 0; - - dp::OGLContext * m_defaultContext = 0; - + uint32_t m_colorFormat; + FramebufferFallback m_framebufferFallback; bool m_isSupported = true; }; } // namespace dp diff --git a/drape/glconstants.cpp b/drape/glconstants.cpp index 2d4d6a8adc..dfd0c6d2ca 100644 --- a/drape/glconstants.cpp +++ b/drape/glconstants.cpp @@ -104,6 +104,10 @@ const glConst GLRenderer = GL_RENDERER; const glConst GLVendor = GL_VENDOR; const glConst GLVersion = GL_VERSION; +const glConst GLColorBit = GL_COLOR_BUFFER_BIT; +const glConst GLDepthBit = GL_DEPTH_BUFFER_BIT; +const glConst GLStencilBit = GL_STENCIL_BUFFER_BIT; + const glConst GLMaxFragmentTextures = GL_MAX_TEXTURE_IMAGE_UNITS; const glConst GLMaxVertexTextures = GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; const glConst GLMaxTextureSize = GL_MAX_TEXTURE_SIZE; @@ -138,6 +142,7 @@ const glConst GLAlpha = GL_ALPHA; const glConst GLLuminance = GL_LUMINANCE; const glConst GLAlphaLuminance = GL_LUMINANCE_ALPHA; const glConst GLDepthComponent = GL_DEPTH_COMPONENT; +const glConst GLDepthStencil = GL_DEPTH_STENCIL; const glConst GLRGBA8 = GL_RGBA8_OES; const glConst GLRGBA4 = GL_RGBA4_OES; @@ -146,6 +151,7 @@ const glConst GLLuminance8 = GL_LUMINANCE8_OES; const glConst GLAlphaLuminance8 = GL_LUMINANCE8_ALPHA8_OES; const glConst GLAlphaLuminance4 = GL_LUMINANCE8_ALPHA4_OES; const glConst GLRed = GL_RED; +const glConst GLRedGreen = GL_RG; const glConst GL8BitOnChannel = GL_UNSIGNED_BYTE; const glConst GL4BitOnChannel = GL_UNSIGNED_SHORT_4_4_4_4; @@ -173,6 +179,7 @@ const glConst GLUnsignedShortType = GL_UNSIGNED_SHORT; const glConst GLIntType = GL_INT; const glConst GLUnsignedIntType = GL_UNSIGNED_INT; const glConst GLFloatType = GL_FLOAT; +const glConst GLUnsignedInt24_8Type = GL_UNSIGNED_INT_24_8; const glConst GLFloatVec2 = GL_FLOAT_VEC2; const glConst GLFloatVec3 = GL_FLOAT_VEC3; @@ -203,6 +210,7 @@ const glConst GLDepthTest = GL_DEPTH_TEST; const glConst GLBlending = GL_BLEND; const glConst GLCullFace = GL_CULL_FACE; const glConst GLScissorTest = GL_SCISSOR_TEST; +const glConst GLStencilTest = GL_STENCIL_TEST; const glConst GLClockwise = GL_CW; const glConst GLCounterClockwise = GL_CCW; @@ -220,6 +228,14 @@ const glConst GLNotEqual = GL_NOTEQUAL; const glConst GLGreatOrEqual = GL_GEQUAL; const glConst GLAlways = GL_ALWAYS; +const glConst GLKeep = GL_KEEP; +const glConst GLIncr = GL_INCR; +const glConst GLDecr = GL_DECR; +const glConst GLInvert = GL_INVERT; +const glConst GLReplace = GL_REPLACE; +const glConst GLIncrWrap = GL_INCR_WRAP; +const glConst GLDecrWrap = GL_DECR_WRAP; + const glConst GLActiveUniforms = GL_ACTIVE_UNIFORMS; const glConst GLLines = GL_LINES; @@ -230,6 +246,7 @@ const glConst GLTriangleStrip = GL_TRIANGLE_STRIP; const glConst GLColorAttachment = GL_COLOR_ATTACHMENT0; const glConst GLDepthAttachment = GL_DEPTH_ATTACHMENT; const glConst GLStencilAttachment = GL_STENCIL_ATTACHMENT; +const glConst GLDepthStencilAttachment = GL_DEPTH_STENCIL_ATTACHMENT; const glConst GLFramebufferComplete = GL_FRAMEBUFFER_COMPLETE; diff --git a/drape/glconstants.hpp b/drape/glconstants.hpp index c67c181fa9..e44bd5656a 100644 --- a/drape/glconstants.hpp +++ b/drape/glconstants.hpp @@ -12,6 +12,11 @@ extern const glConst GLRenderer; extern const glConst GLVendor; extern const glConst GLVersion; +/// Clear bits +extern const glConst GLColorBit; +extern const glConst GLDepthBit; +extern const glConst GLStencilBit; + /// Hardware specific params extern const glConst GLMaxFragmentTextures; extern const glConst GLMaxVertexTextures; @@ -54,6 +59,7 @@ extern const glConst GLAlpha; extern const glConst GLLuminance; extern const glConst GLAlphaLuminance; extern const glConst GLDepthComponent; +extern const glConst GLDepthStencil; /// Texture layout size extern const glConst GLRGBA8; @@ -63,6 +69,7 @@ extern const glConst GLLuminance8; extern const glConst GLAlphaLuminance8; extern const glConst GLAlphaLuminance4; extern const glConst GLRed; +extern const glConst GLRedGreen; /// Pixel type for texture upload extern const glConst GL8BitOnChannel; @@ -97,6 +104,7 @@ extern const glConst GLUnsignedShortType; extern const glConst GLIntType; extern const glConst GLUnsignedIntType; extern const glConst GLFloatType; +extern const glConst GLUnsignedInt24_8Type; extern const glConst GLFloatVec2; extern const glConst GLFloatVec3; @@ -130,6 +138,7 @@ extern const glConst GLDepthTest; extern const glConst GLBlending; extern const glConst GLCullFace; extern const glConst GLScissorTest; +extern const glConst GLStencilTest; /// Triangle faces order extern const glConst GLClockwise; @@ -150,6 +159,15 @@ extern const glConst GLNotEqual; extern const glConst GLGreatOrEqual; extern const glConst GLAlways; +/// OpenGL stencil functions +extern const glConst GLKeep; +extern const glConst GLIncr; +extern const glConst GLDecr; +extern const glConst GLInvert; +extern const glConst GLReplace; +extern const glConst GLIncrWrap; +extern const glConst GLDecrWrap; + /// Program object parameter names extern const glConst GLActiveUniforms; @@ -163,6 +181,7 @@ extern const glConst GLTriangleStrip; extern const glConst GLColorAttachment; extern const glConst GLDepthAttachment; extern const glConst GLStencilAttachment; +extern const glConst GLDepthStencilAttachment; /// Framebuffer status extern const glConst GLFramebufferComplete; diff --git a/drape/glfunctions.cpp b/drape/glfunctions.cpp index 55c003194a..4cdc153b63 100644 --- a/drape/glfunctions.cpp +++ b/drape/glfunctions.cpp @@ -427,16 +427,10 @@ void GLFunctions::glClearColor(float r, float g, float b, float a) GLCHECK(glClearColorFn(r, g, b, a)); } -void GLFunctions::glClear() +void GLFunctions::glClear(uint32_t clearBits) { ASSERT(glClearFn != nullptr, ()); - GLCHECK(glClearFn(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); -} - -void GLFunctions::glClearDepth() -{ - ASSERT(glClearFn != nullptr, ()); - GLCHECK(glClearFn(GL_DEPTH_BUFFER_BIT)); + GLCHECK(glClearFn(clearBits)); } void GLFunctions::glViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) @@ -458,8 +452,21 @@ void GLFunctions::glFlush() } void GLFunctions::glFinish() { GLCHECK(::glFinish()); } + void GLFunctions::glFrontFace(glConst mode) { GLCHECK(::glFrontFace(mode)); } + void GLFunctions::glCullFace(glConst face) { GLCHECK(::glCullFace(face)); } + +void GLFunctions::glStencilOpSeparate(glConst face, glConst sfail, glConst dpfail, glConst dppass) +{ + GLCHECK(::glStencilOpSeparate(face, sfail, dpfail, dppass)); +} + +void GLFunctions::glStencilFuncSeparate(glConst face, glConst func, int ref, uint32_t mask) +{ + GLCHECK(::glStencilFuncSeparate(face, func, ref, mask)); +} + void GLFunctions::glPixelStore(glConst name, uint32_t value) { GLCHECK(::glPixelStorei(name, value)); @@ -900,8 +907,10 @@ void GLFunctions::glTexImage2D(int width, int height, glConst layout, glConst pi { // In OpenGL ES3: // - we can't create unsized GL_RED texture, so we use GL_R8; + // - we can't create unsized GL_RG texture, so we use GL_RG8; // - we can't create unsized GL_DEPTH_COMPONENT texture, so we use GL_DEPTH_COMPONENT16 - // or GL_DEPTH_COMPONENT24 or GL_DEPTH_COMPONENT32F. + // or GL_DEPTH_COMPONENT24 or GL_DEPTH_COMPONENT32F; + // - we can't create unsized GL_DEPTH_STENCIL texture, so we use GL_DEPTH24_STENCIL8. glConst internalFormat = layout; if (CurrentApiVersion == dp::ApiVersion::OpenGLES3) { @@ -909,6 +918,10 @@ void GLFunctions::glTexImage2D(int width, int height, glConst layout, glConst pi { internalFormat = GL_R8; } + else if (layout == gl_const::GLRedGreen) + { + internalFormat = GL_RG8; + } else if (layout == gl_const::GLDepthComponent) { internalFormat = GL_DEPTH_COMPONENT16; @@ -917,10 +930,14 @@ void GLFunctions::glTexImage2D(int width, int height, glConst layout, glConst pi else if (pixelType == gl_const::GLFloatType) internalFormat = GL_DEPTH_COMPONENT32F; } + else if (layout == gl_const::GLDepthStencil) + { + internalFormat = GL_DEPTH24_STENCIL8; + } } - GLCHECK( - ::glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, layout, pixelType, data)); + GLCHECK(::glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, + 0, layout, pixelType, data)); } void GLFunctions::glTexSubImage2D(int x, int y, int width, int height, glConst layout, diff --git a/drape/glfunctions.hpp b/drape/glfunctions.hpp index 4c3e87c4d5..c950203e62 100644 --- a/drape/glfunctions.hpp +++ b/drape/glfunctions.hpp @@ -19,8 +19,7 @@ public: static bool glHasExtension(std::string const & name); static void glClearColor(float r, float g, float b, float a); - static void glClear(); - static void glClearDepth(); + static void glClear(uint32_t clearBits); static void glViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h); static void glScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h); static void glFlush(); @@ -29,6 +28,9 @@ public: static void glFrontFace(glConst mode); static void glCullFace(glConst face); + static void glStencilOpSeparate(glConst face, glConst sfail, glConst dpfail, glConst dppass); + static void glStencilFuncSeparate(glConst face, glConst func, int ref, uint32_t mask); + static void glPixelStore(glConst name, uint32_t value); static int32_t glGetInteger(glConst pname); diff --git a/drape/hw_texture.cpp b/drape/hw_texture.cpp index 06a6c580b7..3fde271920 100644 --- a/drape/hw_texture.cpp +++ b/drape/hw_texture.cpp @@ -75,17 +75,23 @@ float HWTexture::GetT(uint32_t y) const void HWTexture::UnpackFormat(TextureFormat format, glConst & layout, glConst & pixelType) { + // Now we support only 1-byte-per-channel textures. + pixelType = gl_const::GL8BitOnChannel; + switch (format) { case RGBA8: layout = gl_const::GLRGBA; - pixelType = gl_const::GL8BitOnChannel; break; case ALPHA: // On OpenGL ES3 GLAlpha is not supported, we use GLRed instead. layout = GLFunctions::CurrentApiVersion == dp::ApiVersion::OpenGLES2 ? gl_const::GLAlpha : gl_const::GLRed; - pixelType = gl_const::GL8BitOnChannel; + break; + case RED_GREEN: + // On OpenGL ES2 2-channel textures are not supported. + layout = GLFunctions::CurrentApiVersion == dp::ApiVersion::OpenGLES2 ? gl_const::GLRGBA + : gl_const::GLRedGreen; break; default: ASSERT(false, ()); break; } @@ -109,6 +115,7 @@ void HWTexture::SetFilter(glConst filter) } int32_t HWTexture::GetID() const { return m_textureID; } + OpenGLHWTexture::~OpenGLHWTexture() { if (m_textureID != -1) diff --git a/drape/static_texture.cpp b/drape/static_texture.cpp index f131129b03..8638787e20 100644 --- a/drape/static_texture.cpp +++ b/drape/static_texture.cpp @@ -4,8 +4,8 @@ #include "platform/platform.hpp" -#include "coding/reader.hpp" #include "coding/parse_xml.hpp" +#include "coding/reader.hpp" #include "base/string_utils.hpp" @@ -14,26 +14,32 @@ #endif #include "3party/stb_image/stb_image.h" +#include + namespace dp { +std::string const StaticTexture::kDefaultResource = "default"; namespace { - using TLoadingCompletion = function; -using TLoadingFailure = function; +using TLoadingFailure = function; -bool LoadData(string const & textureName, string const & skinPathName, - TLoadingCompletion const & completionHandler, +bool LoadData(std::string const & textureName, std::string const & skinPathName, + uint8_t bytesPerPixel, TLoadingCompletion const & completionHandler, TLoadingFailure const & failureHandler) { ASSERT(completionHandler != nullptr, ()); ASSERT(failureHandler != nullptr, ()); - vector rawData; + std::vector rawData; try { - ReaderPtr reader = GetStyleReader().GetResourceReader(textureName + ".png", skinPathName); + std::string const fullName = textureName + ".png"; + ReaderPtr reader = skinPathName == StaticTexture::kDefaultResource ? + GetStyleReader().GetDefaultResourceReader(fullName) : + GetStyleReader().GetResourceReader(fullName, skinPathName); + CHECK_LESS(reader.Size(), static_cast(numeric_limits::max()), ()); size_t const size = static_cast(reader.Size()); rawData.resize(size); @@ -46,12 +52,30 @@ bool LoadData(string const & textureName, string const & skinPathName, } int w, h, bpp; - unsigned char * data = stbi_load_from_memory(&rawData[0], static_cast(rawData.size()), &w, &h, &bpp, 0); - ASSERT_EQUAL(bpp, 4, ("Incorrect texture format")); + unsigned char * data = + stbi_load_from_memory(&rawData[0], static_cast(rawData.size()), &w, &h, &bpp, 0); + + uint8_t constexpr kSupportedBPP = 4; + CHECK_EQUAL(bpp, kSupportedBPP, ("Incorrect texture format")); ASSERT(glm::isPowerOfTwo(w), (w)); ASSERT(glm::isPowerOfTwo(h), (h)); - completionHandler(data, static_cast(w), static_cast(h)); + if (bytesPerPixel != bpp) + { + std::vector convertedData(static_cast(w * h * bytesPerPixel)); + uint32_t const pixelsCount = static_cast(w * h); + for (uint32_t i = 0; i < pixelsCount; i++) + { + unsigned char const * p = data + i * bpp; + convertedData[i * bytesPerPixel] = p[0]; + convertedData[i * bytesPerPixel + 1] = p[1]; + } + stbi_image_free(data); + completionHandler(convertedData.data(), static_cast(w), static_cast(h)); + return true; + } + + completionHandler(data, static_cast(w), static_cast(h)); stbi_image_free(data); return true; } @@ -60,28 +84,29 @@ class StaticResourceInfo : public Texture::ResourceInfo { public: StaticResourceInfo() : Texture::ResourceInfo(m2::RectF(0.0f, 0.0f, 1.0f, 1.0f)) {} - virtual ~StaticResourceInfo(){} - + virtual ~StaticResourceInfo() {} Texture::ResourceType GetType() const override { return Texture::Static; } }; +} // namespace -} // namespace - -StaticTexture::StaticTexture(string const & textureName, string const & skinPathName, - ref_ptr allocator) +StaticTexture::StaticTexture(std::string const & textureName, std::string const & skinPathName, + dp::TextureFormat format, ref_ptr allocator) : m_textureName(textureName) + , m_skinPathName(skinPathName) + , m_format(format) , m_info(make_unique_dp()) { - m_isLoadingCorrect = Load(skinPathName, allocator); + m_isLoadingCorrect = Load(allocator); } -bool StaticTexture::Load(string const & skinPathName, ref_ptr allocator) +bool StaticTexture::Load(ref_ptr allocator) { - auto completionHandler = [this, &allocator](unsigned char * data, uint32_t width, uint32_t height) + auto completionHandler = [this, &allocator](unsigned char * data, uint32_t width, + uint32_t height) { Texture::Params p; p.m_allocator = allocator; - p.m_format = dp::RGBA8; + p.m_format = m_format; p.m_width = width; p.m_height = height; p.m_wrapSMode = gl_const::GLRepeate; @@ -90,22 +115,25 @@ bool StaticTexture::Load(string const & skinPathName, ref_ptr allocator) +void StaticTexture::Invalidate(ref_ptr allocator) { Destroy(); - m_isLoadingCorrect = Load(skinPathName, allocator); + m_isLoadingCorrect = Load(allocator); } -ref_ptr StaticTexture::FindResource(Texture::Key const & key, bool & newResource) +ref_ptr StaticTexture::FindResource(Texture::Key const & key, + bool & newResource) { newResource = false; if (key.GetType() != Texture::Static) @@ -115,14 +143,12 @@ ref_ptr StaticTexture::FindResource(Texture::Key const & void StaticTexture::Fail() { - int32_t alfaTexture = 0; + int32_t alphaTexture = 0; Texture::Params p; p.m_allocator = GetDefaultAllocator(); p.m_format = dp::RGBA8; p.m_width = 1; p.m_height = 1; - - Create(p, make_ref(&alfaTexture)); + Create(p, make_ref(&alphaTexture)); } - -} // namespace dp +} // namespace dp diff --git a/drape/static_texture.hpp b/drape/static_texture.hpp index aa2aa7e4c5..d7a6950445 100644 --- a/drape/static_texture.hpp +++ b/drape/static_texture.hpp @@ -2,11 +2,10 @@ #include "drape/texture.hpp" -#include "std/string.hpp" +#include namespace dp { - class StaticTexture : public Texture { public: @@ -16,23 +15,26 @@ public: ResourceType GetType() const override { return ResourceType::Static; } }; - StaticTexture(string const & textureName, string const & skinPathName, - ref_ptr allocator); + static std::string const kDefaultResource; + + StaticTexture(std::string const & textureName, std::string const & skinPathName, + dp::TextureFormat format, ref_ptr allocator); ref_ptr FindResource(Key const & key, bool & newResource) override; - void Invalidate(string const & skinPathName, ref_ptr allocator); + void Invalidate(ref_ptr allocator); bool IsLoadingCorrect() const { return m_isLoadingCorrect; } - private: void Fail(); - bool Load(string const & skinPathName, ref_ptr allocator); + bool Load(ref_ptr allocator); + + std::string const m_textureName; + std::string const m_skinPathName; + dp::TextureFormat const m_format; - string m_textureName; drape_ptr m_info; bool m_isLoadingCorrect; }; - -} // namespace dp +} // namespace dp diff --git a/drape/support_manager.cpp b/drape/support_manager.cpp index 6a68449086..bd745335f4 100644 --- a/drape/support_manager.cpp +++ b/drape/support_manager.cpp @@ -1,20 +1,24 @@ #include "drape/support_manager.hpp" #include "drape/glfunctions.hpp" -#include "base/logging.hpp" +#include "platform/settings.hpp" -#include "std/algorithm.hpp" -#include "std/vector.hpp" +#include "base/logging.hpp" #include "3party/Alohalytics/src/alohalytics.h" +#include +#include +#include + namespace dp { +char const * kSupportedAntialiasing = "Antialiasing"; void SupportManager::Init() { - string const renderer = GLFunctions::glGetString(gl_const::GLRenderer); - string const version = GLFunctions::glGetString(gl_const::GLVersion); + std::string const renderer = GLFunctions::glGetString(gl_const::GLRenderer); + std::string const version = GLFunctions::glGetString(gl_const::GLVersion); LOG(LINFO, ("Renderer =", renderer, "Api =", GLFunctions::CurrentApiVersion, "Driver version =", version)); // On Android the engine may be recreated. Here we guarantee that GPU info is sent once per session. @@ -29,12 +33,12 @@ void SupportManager::Init() if (m_isSamsungGoogleNexus) LOG(LINFO, ("Samsung Google Nexus detected.")); - if (renderer.find("Adreno") != string::npos) + if (renderer.find("Adreno") != std::string::npos) { - vector const models = { "200", "203", "205", "220", "225" }; + std::vector const models = { "200", "203", "205", "220", "225" }; for (auto const & model : models) { - if (renderer.find(model) != string::npos) + if (renderer.find(model) != std::string::npos) { LOG(LINFO, ("Adreno 200 device detected.")); m_isAdreno200 = true; @@ -43,32 +47,28 @@ void SupportManager::Init() } } - m_isTegra = (renderer.find("Tegra") != string::npos); + m_isTegra = (renderer.find("Tegra") != std::string::npos); if (m_isTegra) LOG(LINFO, ("NVidia Tegra device detected.")); - m_maxLineWidth = max(1, GLFunctions::glGetMaxLineWidth()); + m_maxLineWidth = std::max(1, GLFunctions::glGetMaxLineWidth()); LOG(LINFO, ("Max line width =", m_maxLineWidth)); -} -bool SupportManager::IsSamsungGoogleNexus() const -{ - return m_isSamsungGoogleNexus; -} - -bool SupportManager::IsAdreno200Device() const -{ - return m_isAdreno200; -} - -bool SupportManager::IsTegraDevice() const -{ - return m_isTegra; -} - -int SupportManager::GetMaxLineWidth() const -{ - return m_maxLineWidth; + // Set up default antialiasing value. + bool val; + if (!settings::Get(kSupportedAntialiasing, val)) + { +#ifdef OMIM_OS_ANDROID + std::vector const models = {"Mali-G71", "Mali-T880", + "Adreno (TM) 540", "Adreno (TM) 530", + "Adreno (TM) 430", "Adreno (TM) 330"}; + m_isAntialiasingEnabledByDefault = + (std::find(models.begin(), models.end(), renderer) != models.end()); +#else + m_isAntialiasingEnabledByDefault = true; +#endif + settings::Set(kSupportedAntialiasing, m_isAntialiasingEnabledByDefault); + } } SupportManager & SupportManager::Instance() @@ -76,5 +76,4 @@ SupportManager & SupportManager::Instance() static SupportManager manager; return manager; } - -} // namespace dp +} // namespace dp diff --git a/drape/support_manager.hpp b/drape/support_manager.hpp index c59fdbcbbe..e7a9df6aa9 100644 --- a/drape/support_manager.hpp +++ b/drape/support_manager.hpp @@ -1,11 +1,12 @@ #pragma once -#include "std/noncopyable.hpp" +#include "base/macros.hpp" namespace dp { +extern char const * kSupportedAntialiasing; -class SupportManager : public noncopyable +class SupportManager { public: // This singleton must be available only from rendering threads. @@ -14,21 +15,21 @@ public: // Initialization must be called only when OpenGL context is created. void Init(); - bool IsSamsungGoogleNexus() const; - bool IsAdreno200Device() const; - bool IsTegraDevice() const; - - int GetMaxLineWidth() const; + bool IsSamsungGoogleNexus() const { return m_isSamsungGoogleNexus; } + bool IsAdreno200Device() const { return m_isAdreno200; } + bool IsTegraDevice() const { return m_isTegra; } + int GetMaxLineWidth() const { return m_maxLineWidth; } + bool IsAntialiasingEnabledByDefault() const { return m_isAntialiasingEnabledByDefault; } private: SupportManager() = default; - ~SupportManager() = default; bool m_isSamsungGoogleNexus = false; bool m_isAdreno200 = false; bool m_isTegra = false; - int m_maxLineWidth = 1; -}; + bool m_isAntialiasingEnabledByDefault = false; -} // namespace dp + DISALLOW_COPY_AND_MOVE(SupportManager); +}; +} // namespace dp diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 2811e4fa22..6c6acc5554 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -19,6 +19,8 @@ #include "std/vector.hpp" #include "std/bind.hpp" +#include + namespace dp { @@ -43,7 +45,6 @@ uint32_t const kDefaultSymbolsIndex = 0; namespace { - void MultilineTextToUniString(TextureManager::TMultilineText const & text, strings::UniString & outString) { size_t cnt = 0; @@ -117,8 +118,23 @@ void ParsePatternsList(string const & patternsFile, ToDo toDo) toDo(pattern); }); } +m2::PointU StipplePenTextureSize(size_t patternsCount, uint32_t maxTextureSize) +{ + uint32_t const sz = my::NextPowOf2(static_cast(patternsCount) + kReservedPatterns); + uint32_t const stippleTextureHeight = + std::min(maxTextureSize, std::max(sz, kMinStippleTextureHeight)); + return m2::PointU(kStippleTextureWidth, stippleTextureHeight); +} -} // namespace +m2::PointU ColorTextureSize(size_t colorsCount, uint32_t maxTextureSize) +{ + uint32_t const sz = static_cast(floor(sqrt(colorsCount + kReservedColors))); + uint32_t colorTextureSize = std::max(my::NextPowOf2(sz), kMinColorTextureSize); + colorTextureSize *= ColorTexture::GetColorSizeInPixels(); + colorTextureSize = std::min(maxTextureSize, colorTextureSize); + return m2::PointU(colorTextureSize, colorTextureSize); +} +} // namespace TextureManager::TextureManager() : m_maxTextureSize(0) @@ -178,8 +194,7 @@ m2::RectF const & TextureManager::BaseRegion::GetTexRect() const TextureManager::GlyphRegion::GlyphRegion() : BaseRegion() -{ -} +{} float TextureManager::GlyphRegion::GetOffsetX() const { @@ -228,6 +243,8 @@ void TextureManager::Release() m_trafficArrowTexture.reset(); m_hatchingTexture.reset(); + m_smaaAreaTexture.reset(); + m_smaaSearchTexture.reset(); m_glyphTextures.clear(); @@ -390,39 +407,46 @@ size_t TextureManager::FindHybridGlyphsGroup(TMultilineText const & text, int fi void TextureManager::Init(Params const & params) { + m_resPostfix = params.m_resPostfix; m_textureAllocator = CreateAllocator(); - m_maxTextureSize = min(kMaxTextureSize, (uint32_t)GLFunctions::glGetInteger(gl_const::GLMaxTextureSize)); + m_maxTextureSize = std::min(kMaxTextureSize, + static_cast(GLFunctions::glGetInteger(gl_const::GLMaxTextureSize))); GLFunctions::glPixelStore(gl_const::GLUnpackAlignment, 1); + // Initialize symbols. for (size_t i = 0; i < ARRAY_SIZE(kSymbolTextures); ++i) { - m_symbolTextures.push_back(make_unique_dp(params.m_resPostfix, kSymbolTextures[i], + m_symbolTextures.push_back(make_unique_dp(m_resPostfix, kSymbolTextures[i], make_ref(m_textureAllocator))); } - m_trafficArrowTexture = make_unique_dp("traffic-arrow", params.m_resPostfix, - make_ref(m_textureAllocator)); + // Initialize static textures. + m_trafficArrowTexture = make_unique_dp("traffic-arrow", m_resPostfix, + dp::RGBA8, make_ref(m_textureAllocator)); + m_hatchingTexture = make_unique_dp("area-hatching", m_resPostfix, + dp::RGBA8, make_ref(m_textureAllocator)); - m_hatchingTexture = make_unique_dp("area-hatching", params.m_resPostfix, - make_ref(m_textureAllocator)); + if (GLFunctions::CurrentApiVersion == dp::ApiVersion::OpenGLES3) + { + m_smaaAreaTexture = make_unique_dp("smaa-area", StaticTexture::kDefaultResource, + dp::RED_GREEN, make_ref(m_textureAllocator)); + m_smaaSearchTexture = make_unique_dp("smaa-search", StaticTexture::kDefaultResource, + dp::ALPHA, make_ref(m_textureAllocator)); + } - // initialize patterns + // Initialize patterns. buffer_vector, 64> patterns; double const visualScale = params.m_visualScale; ParsePatternsList(params.m_patterns, [&patterns, visualScale](buffer_vector const & pattern) { buffer_vector p; for (size_t i = 0; i < pattern.size(); i++) - p.push_back(pattern[i] * visualScale); + p.push_back(static_cast(pattern[i] * visualScale)); patterns.push_back(move(p)); }); - - uint32_t stippleTextureHeight = max(my::NextPowOf2(static_cast(patterns.size()) + kReservedPatterns), - kMinStippleTextureHeight); - stippleTextureHeight = min(m_maxTextureSize, stippleTextureHeight); - m_stipplePenTexture = make_unique_dp(m2::PointU(kStippleTextureWidth, stippleTextureHeight), + m_stipplePenTexture = make_unique_dp(StipplePenTextureSize(patterns.size(), m_maxTextureSize), make_ref(m_textureAllocator)); LOG(LDEBUG, ("Patterns texture size = ", m_stipplePenTexture->GetWidth(), m_stipplePenTexture->GetHeight())); @@ -430,17 +454,13 @@ void TextureManager::Init(Params const & params) for (auto it = patterns.begin(); it != patterns.end(); ++it) stipplePenTextureTex->ReservePattern(*it); - // initialize colors + // Initialize colors. buffer_vector colors; ParseColorsList(params.m_colors, [&colors](dp::Color const & color) { colors.push_back(color); }); - - uint32_t colorTextureSize = max(my::NextPowOf2(floor(sqrt(colors.size() + kReservedColors))), kMinColorTextureSize); - colorTextureSize *= ColorTexture::GetColorSizeInPixels(); - colorTextureSize = min(m_maxTextureSize, colorTextureSize); - m_colorTexture = make_unique_dp(m2::PointU(colorTextureSize, colorTextureSize), + m_colorTexture = make_unique_dp(ColorTextureSize(colors.size(), m_maxTextureSize), make_ref(m_textureAllocator)); LOG(LDEBUG, ("Colors texture size = ", m_colorTexture->GetWidth(), m_colorTexture->GetHeight())); @@ -448,15 +468,16 @@ void TextureManager::Init(Params const & params) for (auto it = colors.begin(); it != colors.end(); ++it) colorTex->ReserveColor(*it); - // initialize glyphs + // Initialize glyphs. m_glyphManager = make_unique_dp(params.m_glyphMngParams); uint32_t const textureSquare = m_maxTextureSize * m_maxTextureSize; - uint32_t const baseGlyphHeight = params.m_glyphMngParams.m_baseGlyphHeight * kGlyphAreaMultiplier; - uint32_t const avarageGlyphSquare = baseGlyphHeight * baseGlyphHeight; + uint32_t const baseGlyphHeight = + static_cast(params.m_glyphMngParams.m_baseGlyphHeight * kGlyphAreaMultiplier); + uint32_t const averageGlyphSquare = baseGlyphHeight * baseGlyphHeight; m_glyphGroups.push_back(GlyphGroup()); - m_maxGlypsCount = ceil(kGlyphAreaCoverage * textureSquare / avarageGlyphSquare); + m_maxGlypsCount = static_cast(ceil(kGlyphAreaCoverage * textureSquare / averageGlyphSquare)); m_glyphManager->ForEachUnicodeBlock([this](strings::UniChar const & start, strings::UniChar const & end) { if (m_glyphGroups.empty()) @@ -475,22 +496,27 @@ void TextureManager::Init(Params const & params) }); } -void TextureManager::Invalidate(string const & resPostfix) +void TextureManager::OnSwitchMapStyle() { + // Here we need invalidate only textures which can be changed in map style switch. for (size_t i = 0; i < m_symbolTextures.size(); ++i) { ASSERT(m_symbolTextures[i] != nullptr, ()); + ASSERT(dynamic_cast(m_symbolTextures[i].get()) != nullptr, ()); ref_ptr symbolsTexture = make_ref(m_symbolTextures[i]); - symbolsTexture->Invalidate(resPostfix, make_ref(m_textureAllocator)); + symbolsTexture->Invalidate(m_resPostfix, make_ref(m_textureAllocator)); } - ASSERT(m_trafficArrowTexture != nullptr, ()); - ref_ptr trafficArrowTexture = make_ref(m_trafficArrowTexture); - trafficArrowTexture->Invalidate(resPostfix, make_ref(m_textureAllocator)); - - ASSERT(m_hatchingTexture != nullptr, ()); - ref_ptr hatchingTexture = make_ref(m_hatchingTexture); - hatchingTexture->Invalidate(resPostfix, make_ref(m_textureAllocator)); + // Uncomment if static textures can be changed. + //ref_ptr staticTextures[] = {make_ref(m_trafficArrowTexture), + // make_ref(m_hatchingTexture)}; + //for (uint32_t i = 0; i < ARRAY_SIZE(staticTextures); i++) + //{ + // ASSERT(staticTextures[i] != nullptr, ()); + // ASSERT(dynamic_cast(staticTextures[i].get()) != nullptr, ()); + // ref_ptr t = staticTextures[i]; + // t->Invalidate(make_ref(m_textureAllocator)); + //} } void TextureManager::GetSymbolRegion(string const & symbolName, SymbolRegion & region) @@ -569,9 +595,18 @@ ref_ptr TextureManager::GetHatchingTexture() const return make_ref(m_hatchingTexture); } +ref_ptr TextureManager::GetSMAAAreaTexture() const +{ + return make_ref(m_smaaAreaTexture); +} + +ref_ptr TextureManager::GetSMAASearchTexture() const +{ + return make_ref(m_smaaSearchTexture); +} + constexpr size_t TextureManager::GetInvalidGlyphGroup() { return kInvalidGlyphGroup; } - -} // namespace dp +} // namespace dp diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index c0a9a74a9d..fa9edb7167 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -10,6 +10,7 @@ #include #include +#include #include namespace dp @@ -81,7 +82,7 @@ public: void Release(); void Init(Params const & params); - void Invalidate(string const & resPostfix); + void OnSwitchMapStyle(); void GetSymbolRegion(string const & symbolName, SymbolRegion & region); @@ -107,6 +108,8 @@ public: ref_ptr GetSymbolsTexture() const; ref_ptr GetTrafficArrowTexture() const; ref_ptr GetHatchingTexture() const; + ref_ptr GetSMAAAreaTexture() const; + ref_ptr GetSMAASearchTexture() const; private: struct GlyphGroup @@ -239,6 +242,7 @@ private: static constexpr size_t GetInvalidGlyphGroup(); private: + std::string m_resPostfix; std::vector> m_symbolTextures; drape_ptr m_stipplePenTexture; drape_ptr m_colorTexture; @@ -246,6 +250,8 @@ private: drape_ptr m_trafficArrowTexture; drape_ptr m_hatchingTexture; + drape_ptr m_smaaAreaTexture; + drape_ptr m_smaaSearchTexture; drape_ptr m_glyphManager; drape_ptr m_textureAllocator; diff --git a/drape_frontend/CMakeLists.txt b/drape_frontend/CMakeLists.txt index 3a130ac449..7b3f68f7bc 100644 --- a/drape_frontend/CMakeLists.txt +++ b/drape_frontend/CMakeLists.txt @@ -145,6 +145,8 @@ set( path_text_shape.hpp poi_symbol_shape.cpp poi_symbol_shape.hpp + postprocess_renderer.cpp + postprocess_renderer.hpp read_manager.cpp read_manager.hpp read_mwm_task.cpp @@ -274,6 +276,12 @@ set( shaders/screen_quad.vsh.glsl shaders/shader_index.txt shaders/shaders_lib.glsl + shaders/smaa_blending_weight.fsh.glsl + shaders/smaa_blending_weight.vsh.glsl + shaders/smaa_edges.fsh.glsl + shaders/smaa_edges.vsh.glsl + shaders/smaa_final.fsh.glsl + shaders/smaa_final.vsh.glsl shaders/solid_color.fsh.glsl shaders/text.fsh.glsl shaders/text.vsh.glsl diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 0f6d844711..edc94f2874 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -308,9 +308,9 @@ void BackendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::InvalidateTextures: + case Message::SwitchMapStyle: { - m_texMng->Invalidate(VisualParams::Instance().GetResourcePostfix()); + m_texMng->OnSwitchMapStyle(); RecacheMapShapes(); m_trafficGenerator->InvalidateTexturesCache(); break; @@ -536,6 +536,14 @@ void BackendRenderer::InitGLDependentResource() GetPlatform().GetFontNames(params.m_glyphMngParams.m_fonts); m_texMng->Init(params); + + // Send some textures to frontend renderer. + drape_ptr textures = make_unique_dp(); + textures->m_smaaAreaTexture = m_texMng->GetSMAAAreaTexture(); + textures->m_smaaSearchTexture = m_texMng->GetSMAASearchTexture(); + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(std::move(textures)), + MessagePriority::High); } void BackendRenderer::RecacheMapShapes() diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 115e0fade9..c95d101565 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -1,17 +1,19 @@ #include "drape_frontend/drape_engine.hpp" -#include "drape_frontend/message_subclasses.hpp" -#include "drape_frontend/visual_params.hpp" -#include "drape_frontend/my_position_controller.hpp" +#include "drape_frontend/message_subclasses.hpp" #include "drape_frontend/gui/drape_gui.hpp" +#include "drape_frontend/my_position_controller.hpp" +#include "drape_frontend/visual_params.hpp" + +#include "drape/support_manager.hpp" #include "platform/settings.hpp" namespace df { DrapeEngine::DrapeEngine(Params && params) - : m_myPositionModeChanged(move(params.m_myPositionModeChanged)) - , m_viewport(move(params.m_viewport)) + : m_myPositionModeChanged(std::move(params.m_myPositionModeChanged)) + , m_viewport(std::move(params.m_viewport)) { VisualParams::Init(params.m_vs, df::CalculateTileSize(m_viewport.GetWidth(), m_viewport.GetHeight())); @@ -32,8 +34,8 @@ DrapeEngine::DrapeEngine(Params && params) } else if (mode == location::FollowAndRotate) { - // If the screen rect setting in follow and rotate mode is missing or invalid, it could cause invalid animations, - // so the follow and rotate mode should be discarded. + // If the screen rect setting in follow and rotate mode is missing or invalid, it could cause + // invalid animations, so the follow and rotate mode should be discarded. m2::AnyRectD rect; if (!(settings::Get("ScreenClipRect", rect) && df::GetWorldRect().IsRectInside(rect.GetGlobalRect()))) mode = location::Follow; @@ -44,6 +46,18 @@ DrapeEngine::DrapeEngine(Params && params) if (settings::Get("LastEnterBackground", lastEnterBackground)) timeInBackground = my::Timer::LocalTime() - lastEnterBackground; + std::vector effects; + + bool enabledAntialiasing; + if (!settings::Get(dp::kSupportedAntialiasing, enabledAntialiasing)) + enabledAntialiasing = false; + + if (enabledAntialiasing) + { + LOG(LINFO, ("Antialiasing is enabled")); + effects.push_back(PostprocessRenderer::Antialiasing); + } + MyPositionController::Params mpParams(mode, timeInBackground, params.m_hints, @@ -55,18 +69,19 @@ DrapeEngine::DrapeEngine(Params && params) make_ref(m_threadCommutator), params.m_factory, make_ref(m_textureManager), - move(mpParams), + std::move(mpParams), m_viewport, bind(&DrapeEngine::ModelViewChanged, this, _1), bind(&DrapeEngine::TapEvent, this, _1), bind(&DrapeEngine::UserPositionChanged, this, _1), make_ref(m_requestedTiles), - move(params.m_overlaysShowStatsCallback), + std::move(params.m_overlaysShowStatsCallback), params.m_allow3dBuildings, params.m_trafficEnabled, - params.m_blockTapEvents); + params.m_blockTapEvents, + std::move(effects)); - m_frontend = make_unique_dp(move(frParams)); + m_frontend = make_unique_dp(std::move(frParams)); BackendRenderer::Params brParams(params.m_apiVersion, frParams.m_commutator, @@ -79,15 +94,15 @@ DrapeEngine::DrapeEngine(Params && params) params.m_trafficEnabled, params.m_simplifiedTrafficColors); - m_backend = make_unique_dp(move(brParams)); + m_backend = make_unique_dp(std::move(brParams)); - m_widgetsInfo = move(params.m_info); + m_widgetsInfo = std::move(params.m_info); RecacheGui(false); RecacheMapShapes(); if (params.m_showChoosePositionMark) - EnableChoosePositionMode(true, move(params.m_boundAreaTriangles), false, m2::PointD()); + EnableChoosePositionMode(true, std::move(params.m_boundAreaTriangles), false, m2::PointD()); ResizeImpl(m_viewport.GetWidth(), m_viewport.GetHeight()); } @@ -251,7 +266,7 @@ void DrapeEngine::RecacheGui(bool needResetOldGui) void DrapeEngine::AddUserEvent(drape_ptr && e) { - m_frontend->AddUserEvent(move(e)); + m_frontend->AddUserEvent(std::move(e)); } void DrapeEngine::ModelViewChanged(ScreenBase const & screen) @@ -293,7 +308,8 @@ void DrapeEngine::SetCompassInfo(location::CompassInfo const & info) MessagePriority::High); } -void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, const location::RouteMatchingInfo & routeInfo) +void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, + const location::RouteMatchingInfo & routeInfo) { m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp(info, isNavigable, routeInfo), @@ -302,45 +318,49 @@ void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, c void DrapeEngine::SwitchMyPositionNextMode() { + using Mode = ChangeMyPositionModeMessage::EChangeType; m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(ChangeMyPositionModeMessage::SwitchNextMode), + make_unique_dp(Mode::SwitchNextMode), MessagePriority::High); } void DrapeEngine::LoseLocation() { + using Mode = ChangeMyPositionModeMessage::EChangeType; m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(ChangeMyPositionModeMessage::LoseLocation), + make_unique_dp(Mode::LoseLocation), MessagePriority::High); } void DrapeEngine::StopLocationFollow() { + using Mode = ChangeMyPositionModeMessage::EChangeType; m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(ChangeMyPositionModeMessage::StopFollowing), + make_unique_dp(Mode::StopFollowing), MessagePriority::High); } void DrapeEngine::FollowRoute(int preferredZoomLevel, int preferredZoomLevel3d, bool enableAutoZoom) { m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(preferredZoomLevel, preferredZoomLevel3d, enableAutoZoom), + make_unique_dp(preferredZoomLevel, + preferredZoomLevel3d, enableAutoZoom), MessagePriority::High); } void DrapeEngine::SetModelViewListener(TModelViewListenerFn && fn) { - m_modelViewChanged = move(fn); + m_modelViewChanged = std::move(fn); } void DrapeEngine::SetTapEventInfoListener(TTapEventInfoFn && fn) { - m_tapListener = move(fn); + m_tapListener = std::move(fn); } void DrapeEngine::SetUserPositionListener(TUserPositionChangedFn && fn) { - m_userPositionChanged = move(fn); + m_userPositionChanged = std::move(fn); } FeatureID DrapeEngine::GetVisiblePOI(m2::PointD const & glbPoint) @@ -355,7 +375,8 @@ FeatureID DrapeEngine::GetVisiblePOI(m2::PointD const & glbPoint) return result; } -void DrapeEngine::SelectObject(SelectionShape::ESelectedObject obj, m2::PointD const & pt, FeatureID const & featureId, bool isAnim) +void DrapeEngine::SelectObject(SelectionShape::ESelectedObject obj, m2::PointD const & pt, + FeatureID const & featureId, bool isAnim) { m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp(obj, pt, featureId, isAnim), @@ -393,12 +414,13 @@ bool DrapeEngine::GetMyPosition(m2::PointD & myPosition) return hasPosition; } -void DrapeEngine::AddRoute(m2::PolylineD const & routePolyline, vector const & turns, - df::ColorConstant color, vector const & traffic, +void DrapeEngine::AddRoute(m2::PolylineD const & routePolyline, std::vector const & turns, + df::ColorConstant color, std::vector const & traffic, df::RoutePattern pattern) { m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(routePolyline, turns, color, traffic, pattern), + make_unique_dp(routePolyline, turns, + color, traffic, pattern), MessagePriority::Normal); } @@ -425,7 +447,7 @@ void DrapeEngine::SetRoutePoint(m2::PointD const & position, bool isStart, bool void DrapeEngine::SetWidgetLayout(gui::TWidgetsLayoutInfo && info) { - m_widgetsLayout = move(info); + m_widgetsLayout = std::move(info); for (auto const & layout : m_widgetsLayout) { auto const itInfo = m_widgetsInfo.find(layout.first); @@ -451,7 +473,8 @@ void DrapeEngine::Allow3dMode(bool allowPerspectiveInNavigation, bool allow3dBui MessagePriority::Normal); m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(allowPerspectiveInNavigation, allow3dBuildings), + make_unique_dp(allowPerspectiveInNavigation, + allow3dBuildings), MessagePriority::Normal); } @@ -462,10 +485,12 @@ void DrapeEngine::EnablePerspective() MessagePriority::Normal); } -void DrapeEngine::UpdateGpsTrackPoints(vector && toAdd, vector && toRemove) +void DrapeEngine::UpdateGpsTrackPoints(std::vector && toAdd, + std::vector && toRemove) { m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(move(toAdd), move(toRemove)), + make_unique_dp(std::move(toAdd), + std::move(toRemove)), MessagePriority::Normal); } @@ -476,7 +501,7 @@ void DrapeEngine::ClearGpsTrackPoints() MessagePriority::Normal); } -void DrapeEngine::EnableChoosePositionMode(bool enable, vector && boundAreaTriangles, +void DrapeEngine::EnableChoosePositionMode(bool enable, std::vector && boundAreaTriangles, bool hasPosition, m2::PointD const & position) { m_choosePositionMode = enable; @@ -494,7 +519,7 @@ void DrapeEngine::EnableChoosePositionMode(bool enable, vector && RecacheGui(true); } m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(enable, move(boundAreaTriangles), + make_unique_dp(enable, std::move(boundAreaTriangles), kineticScroll, hasPosition, position), MessagePriority::High); } @@ -531,7 +556,7 @@ void DrapeEngine::SetDisplacementMode(int mode) MessagePriority::Normal); } -void DrapeEngine::RequestSymbolsSize(vector const & symbols, +void DrapeEngine::RequestSymbolsSize(std::vector const & symbols, TRequestSymbolsSizeCallback const & callback) { m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, @@ -560,7 +585,7 @@ void DrapeEngine::UpdateTraffic(traffic::TrafficInfo const & info) segmentsColoring.emplace(info.GetMwmId(), info.GetColoring()); m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(move(segmentsColoring)), + make_unique_dp(std::move(segmentsColoring)), MessagePriority::Normal); } @@ -594,7 +619,7 @@ void DrapeEngine::RunScenario(ScenarioManager::ScenarioData && scenarioData, { auto const & manager = m_frontend->GetScenarioManager(); if (manager != nullptr) - manager->RunScenario(move(scenarioData), onStartFn, onFinishFn); + manager->RunScenario(std::move(scenarioData), onStartFn, onFinishFn); } void DrapeEngine::AddCustomSymbols(CustomSymbols && symbols) @@ -618,4 +643,16 @@ void DrapeEngine::RemoveAllCustomSymbols() MessagePriority::Normal); } -} // namespace df +void DrapeEngine::SetPosteffectEnabled(PostprocessRenderer::Effect effect, bool enabled) +{ + if (effect == df::PostprocessRenderer::Antialiasing) + { + LOG(LINFO, ("Antialiasing is", (enabled ? "enabled" : "disabled"))); + settings::Set(dp::kSupportedAntialiasing, enabled); + } + + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(effect, enabled), + MessagePriority::Normal); +} +} // namespace df diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 64e9b5924e..debfbc2494 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -7,6 +7,7 @@ #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/route_shape.hpp" #include "drape_frontend/overlays_tracker.hpp" +#include "drape_frontend/postprocess_renderer.hpp" #include "drape_frontend/scenario_manager.hpp" #include "drape_frontend/selection_shape.hpp" #include "drape_frontend/threads_commutator.hpp" @@ -25,8 +26,8 @@ #include "base/strings_bundle.hpp" -#include "std/map.hpp" -#include "std/mutex.hpp" +#include +#include namespace dp { @@ -58,7 +59,7 @@ public: bool trafficEnabled, bool blockTapEvents, bool showChoosePositionMark, - vector && boundAreaTriangles, + std::vector && boundAreaTriangles, bool isRoutingActive, bool isAutozoomEnabled, bool simplifiedTrafficColors, @@ -71,18 +72,18 @@ public: , m_hints(hints) , m_vs(vs) , m_fontsScaleFactor(fontsScaleFactor) - , m_info(move(info)) + , m_info(std::move(info)) , m_initialMyPositionMode(initialMyPositionMode) - , m_myPositionModeChanged(move(myPositionModeChanged)) + , m_myPositionModeChanged(std::move(myPositionModeChanged)) , m_allow3dBuildings(allow3dBuildings) , m_trafficEnabled(trafficEnabled) , m_blockTapEvents(blockTapEvents) , m_showChoosePositionMark(showChoosePositionMark) - , m_boundAreaTriangles(move(boundAreaTriangles)) + , m_boundAreaTriangles(std::move(boundAreaTriangles)) , m_isRoutingActive(isRoutingActive) , m_isAutozoomEnabled(isAutozoomEnabled) , m_simplifiedTrafficColors(simplifiedTrafficColors) - , m_overlaysShowStatsCallback(move(overlaysShowStatsCallback)) + , m_overlaysShowStatsCallback(std::move(overlaysShowStatsCallback)) {} dp::ApiVersion m_apiVersion; @@ -100,7 +101,7 @@ public: bool m_trafficEnabled; bool m_blockTapEvents; bool m_showChoosePositionMark; - vector m_boundAreaTriangles; + std::vector m_boundAreaTriangles; bool m_isRoutingActive; bool m_isAutozoomEnabled; bool m_simplifiedTrafficColors; @@ -120,7 +121,7 @@ public: void AddTouchEvent(TouchEvent const & event); void Scale(double factor, m2::PointD const & pxPoint, bool isAnim); - /// if zoom == -1, then current zoom will not change + // If zoom == -1 then current zoom will not be changed. void SetModelViewCenter(m2::PointD const & centerPt, int zoom, bool isAnim); void SetModelViewRect(m2::RectD const & rect, bool applyRotation, int zoom, bool isAnim); void SetModelViewAnyRect(m2::AnyRectD const & rect, bool isAnim); @@ -149,13 +150,14 @@ public: void SetUserPositionListener(TUserPositionChangedFn && fn); FeatureID GetVisiblePOI(m2::PointD const & glbPoint); - void SelectObject(SelectionShape::ESelectedObject obj, m2::PointD const & pt, FeatureID const & featureID, bool isAnim); + void SelectObject(SelectionShape::ESelectedObject obj, m2::PointD const & pt, + FeatureID const & featureID, bool isAnim); void DeselectObject(); bool GetMyPosition(m2::PointD & myPosition); SelectionShape::ESelectedObject GetSelectedObject(); - void AddRoute(m2::PolylineD const & routePolyline, vector const & turns, - df::ColorConstant color, vector const & traffic, + void AddRoute(m2::PolylineD const & routePolyline, std::vector const & turns, + df::ColorConstant color, std::vector const & traffic, df::RoutePattern pattern = df::RoutePattern()); void RemoveRoute(bool deactivateFollowing); void FollowRoute(int preferredZoomLevel, int preferredZoomLevel3d, bool enableAutoZoom); @@ -169,10 +171,11 @@ public: void Allow3dMode(bool allowPerspectiveInNavigation, bool allow3dBuildings); void EnablePerspective(); - void UpdateGpsTrackPoints(vector && toAdd, vector && toRemove); + void UpdateGpsTrackPoints(std::vector && toAdd, + std::vector && toRemove); void ClearGpsTrackPoints(); - void EnableChoosePositionMode(bool enable, vector && boundAreaTriangles, + void EnableChoosePositionMode(bool enable, std::vector && boundAreaTriangles, bool hasPosition, m2::PointD const & position); void BlockTapEvents(bool block); @@ -182,9 +185,9 @@ public: void SetDisplacementMode(int mode); - using TRequestSymbolsSizeCallback = function const &)>; + using TRequestSymbolsSizeCallback = std::function const &)>; - void RequestSymbolsSize(vector const & symbols, + void RequestSymbolsSize(std::vector const & symbols, TRequestSymbolsSizeCallback const & callback); void EnableTraffic(bool trafficEnabled); @@ -202,6 +205,8 @@ public: void RemoveCustomSymbols(MwmSet::MwmId const & mwmId); void RemoveAllCustomSymbols(); + void SetPosteffectEnabled(PostprocessRenderer::Effect effect, bool enabled); + private: void AddUserEvent(drape_ptr && e); void ModelViewChanged(ScreenBase const & screen); diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 15e0f007bc..51077eb59f 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -71,6 +71,7 @@ SOURCES += \ path_symbol_shape.cpp \ path_text_shape.cpp \ poi_symbol_shape.cpp \ + postprocess_renderer.cpp \ read_manager.cpp \ read_mwm_task.cpp \ render_group.cpp \ @@ -179,6 +180,7 @@ HEADERS += \ path_symbol_shape.hpp \ path_text_shape.hpp \ poi_symbol_shape.hpp \ + postprocess_renderer.hpp \ read_manager.hpp \ read_mwm_task.hpp \ render_group.hpp \ @@ -267,6 +269,12 @@ OTHER_FILES += \ shaders/screen_quad.vsh.glsl \ shaders/shader_index.txt \ shaders/shaders_lib.glsl \ + shaders/smaa_blending_weight.fsh.glsl \ + shaders/smaa_blending_weight.vsh.glsl \ + shaders/smaa_edges.fsh.glsl \ + shaders/smaa_edges.vsh.glsl \ + shaders/smaa_final.fsh.glsl \ + shaders/smaa_final.vsh.glsl \ shaders/solid_color.fsh.glsl \ shaders/text.fsh.glsl \ shaders/text.vsh.glsl \ diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index ee52189864..fb9c01c920 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -6,6 +6,7 @@ #include "drape_frontend/gui/drape_gui.hpp" #include "drape_frontend/gui/ruler_helper.hpp" #include "drape_frontend/message_subclasses.hpp" +#include "drape_frontend/postprocess_renderer.hpp" #include "drape_frontend/scenario_manager.hpp" #include "drape_frontend/screen_operations.hpp" #include "drape_frontend/screen_quad_renderer.hpp" @@ -31,10 +32,9 @@ #include "base/logging.hpp" #include "base/stl_add.hpp" -#include "std/algorithm.hpp" -#include "std/bind.hpp" -#include "std/cmath.hpp" -#include "std/chrono.hpp" +#include +#include +#include namespace df { @@ -62,7 +62,7 @@ struct MergedGroupKey }; template -bool RemoveGroups(ToDo & filter, vector> & groups, +bool RemoveGroups(ToDo & filter, std::vector> & groups, ref_ptr tree) { size_t startCount = groups.size(); @@ -90,9 +90,9 @@ bool RemoveGroups(ToDo & filter, vector> & groups, struct RemoveTilePredicate { mutable bool m_deletionMark = false; - function const &)> const & m_predicate; + std::function const &)> const & m_predicate; - RemoveTilePredicate(function const &)> const & predicate) + RemoveTilePredicate(std::function const &)> const & predicate) : m_predicate(predicate) {} @@ -108,7 +108,6 @@ struct RemoveTilePredicate return false; } }; - } // namespace FrontendRenderer::FrontendRenderer(Params && params) @@ -116,10 +115,8 @@ FrontendRenderer::FrontendRenderer(Params && params) , m_gpuProgramManager(new dp::GpuProgramManager()) , m_routeRenderer(new RouteRenderer()) , m_trafficRenderer(new TrafficRenderer()) - , m_framebuffer(new dp::Framebuffer()) - , m_screenQuadRenderer(new ScreenQuadRenderer()) , m_gpsTrackRenderer( - new GpsTrackRenderer(bind(&FrontendRenderer::PrepareGpsTrackPoints, this, _1))) + new GpsTrackRenderer(std::bind(&FrontendRenderer::PrepareGpsTrackPoints, this, _1))) , m_drapeApiRenderer(new DrapeApiRenderer()) , m_overlayTree(new dp::OverlayTree()) , m_enablePerspectiveInNavigation(false) @@ -136,8 +133,9 @@ FrontendRenderer::FrontendRenderer(Params && params) , m_needRestoreSize(false) , m_trafficEnabled(params.m_trafficEnabled) , m_overlaysTracker(new OverlaysTracker()) - , m_overlaysShowStatsCallback(move(params.m_overlaysShowStatsCallback)) + , m_overlaysShowStatsCallback(std::move(params.m_overlaysShowStatsCallback)) , m_forceUpdateScene(false) + , m_postprocessRenderer(new PostprocessRenderer()) #ifdef SCENARIO_ENABLE , m_scenarioManager(new ScenarioManager(this)) #endif @@ -149,7 +147,11 @@ FrontendRenderer::FrontendRenderer(Params && params) ASSERT(m_tapEventInfoFn, ()); ASSERT(m_userPositionChangedFn, ()); - m_myPositionController.reset(new MyPositionController(move(params.m_myPositionParams))); + m_myPositionController.reset(new MyPositionController(std::move(params.m_myPositionParams))); + + for (auto const & effect : params.m_enabledEffects) + m_postprocessRenderer->SetEffectEnabled(effect, true /* enabled */); + StartThread(); } @@ -171,7 +173,7 @@ void FrontendRenderer::UpdateCanBeDeletedStatus() { m2::RectD const & screenRect = m_userEventStream.GetCurrentScreen().ClipRect(); - vector notFinishedTileRects; + std::vector notFinishedTileRects; notFinishedTileRects.reserve(m_notFinishedTiles.size()); for (auto const & tileKey : m_notFinishedTiles) notFinishedTileRects.push_back(tileKey.GetGlobalRect()); @@ -180,26 +182,18 @@ void FrontendRenderer::UpdateCanBeDeletedStatus() { for (auto & group : layer.m_renderGroups) { - if (group->IsPendingOnDelete()) + if (!group->IsPendingOnDelete()) + continue; + + bool canBeDeleted = true; + if (!notFinishedTileRects.empty()) { - bool canBeDeleted = true; - if (!notFinishedTileRects.empty()) - { - m2::RectD const tileRect = group->GetTileKey().GetGlobalRect(); - if (tileRect.IsIntersect(screenRect)) - { - for (auto const & notFinishedRect : notFinishedTileRects) - { - if (notFinishedRect.IsIntersect(tileRect)) - { - canBeDeleted = false; - break; - } - } - } - } - layer.m_isDirty |= group->UpdateCanBeDeletedStatus(canBeDeleted, m_currentZoomLevel, make_ref(m_overlayTree)); + m2::RectD const tileRect = group->GetTileKey().GetGlobalRect(); + if (tileRect.IsIntersect(screenRect)) + canBeDeleted = !HasIntersection(tileRect, notFinishedTileRects); } + layer.m_isDirty |= group->UpdateCanBeDeletedStatus(canBeDeleted, m_currentZoomLevel, + make_ref(m_overlayTree)); } } } @@ -217,7 +211,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) if (key.m_zoomLevel == m_currentZoomLevel && CheckTileGenerations(key)) { PrepareBucket(state, bucket); - AddToRenderGroup(state, move(bucket), key); + AddToRenderGroup(state, std::move(bucket), key); } break; } @@ -232,7 +226,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) CheckTileGenerations(overlayRenderData.m_tileKey)) { PrepareBucket(overlayRenderData.m_state, overlayRenderData.m_bucket); - AddToRenderGroup(overlayRenderData.m_state, move(overlayRenderData.m_bucket), overlayRenderData.m_tileKey); + AddToRenderGroup(overlayRenderData.m_state, std::move(overlayRenderData.m_bucket), + overlayRenderData.m_tileKey); } } UpdateCanBeDeletedStatus(); @@ -285,8 +280,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) auto program = m_gpuProgramManager->GetProgram(shape.m_state.GetProgramIndex()); auto program3d = m_gpuProgramManager->GetProgram(shape.m_state.GetProgram3dIndex()); auto group = make_unique_dp(layerId, shape.m_state, shape.m_tileKey, - move(shape.m_bucket)); - m_userMarkRenderGroups.push_back(move(group)); + std::move(shape.m_bucket)); + m_userMarkRenderGroups.push_back(std::move(group)); m_userMarkRenderGroups.back()->SetRenderParams(program, program3d, make_ref(&m_generalUniforms)); } break; @@ -301,9 +296,9 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) return g->GetLayerId() == layerId; }; - auto const iter = remove_if(m_userMarkRenderGroups.begin(), - m_userMarkRenderGroups.end(), - functor); + auto const iter = std::remove_if(m_userMarkRenderGroups.begin(), + m_userMarkRenderGroups.end(), + functor); m_userMarkRenderGroups.erase(iter, m_userMarkRenderGroups.end()); break; } @@ -321,12 +316,12 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::GuiLayerRecached: { ref_ptr msg = message; - drape_ptr renderer = move(msg->AcceptRenderer()); + drape_ptr renderer = std::move(msg->AcceptRenderer()); renderer->Build(make_ref(m_gpuProgramManager)); if (msg->NeedResetOldGui()) m_guiRenderer.release(); if (m_guiRenderer == nullptr) - m_guiRenderer = move(renderer); + m_guiRenderer = std::move(renderer); else m_guiRenderer->Merge(make_ref(renderer)); @@ -410,7 +405,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) m_routeRenderer->UpdateDistanceFromBegin(info.GetDistanceFromBegin()); // Here we have to recache route arrows. m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(), - bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); } break; @@ -467,10 +462,10 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; m2::PointD const finishPoint = routeData->m_sourcePolyline.Back(); - m_routeRenderer->SetRouteData(move(routeData), make_ref(m_gpuProgramManager)); + m_routeRenderer->SetRouteData(std::move(routeData), make_ref(m_gpuProgramManager)); // Here we have to recache route arrows. m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(), - bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); if (!m_routeRenderer->GetFinishPoint()) { @@ -497,7 +492,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) if (routeSignData->m_recacheId > 0 && routeSignData->m_recacheId < m_lastRecacheRouteId) break; - m_routeRenderer->SetRouteSign(move(routeSignData), make_ref(m_gpuProgramManager)); + m_routeRenderer->SetRouteSign(std::move(routeSignData), make_ref(m_gpuProgramManager)); break; } @@ -509,7 +504,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) if (routeArrowsData->m_recacheId > 0 && routeArrowsData->m_recacheId < m_lastRecacheRouteId) break; - m_routeRenderer->SetRouteArrows(move(routeArrowsData), make_ref(m_gpuProgramManager)); + m_routeRenderer->SetRouteArrows(std::move(routeArrowsData), make_ref(m_gpuProgramManager)); break; } @@ -536,8 +531,9 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) // receive FollowRoute message before FlushRoute message, so we need to postpone its processing. if (m_routeRenderer->GetRouteData() == nullptr) { - m_pendingFollowRoute.reset(new FollowRouteData(msg->GetPreferredZoomLevel(), msg->GetPreferredZoomLevelIn3d(), - msg->EnableAutoZoom())); + m_pendingFollowRoute = my::make_unique(msg->GetPreferredZoomLevel(), + msg->GetPreferredZoomLevelIn3d(), + msg->EnableAutoZoom()); break; } @@ -578,11 +574,11 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) blocker.Wait(); } - // Invalidate textures and wait for completion. + // Notify backend renderer and wait for completion. { BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(blocker), + make_unique_dp(blocker), MessagePriority::High); blocker.Wait(); } @@ -784,6 +780,20 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::SetPostprocessStaticTextures: + { + ref_ptr msg = message; + m_postprocessRenderer->SetStaticTextures(msg->AcceptTextures()); + break; + } + + case Message::SetPosteffectEnabled: + { + ref_ptr msg = message; + m_postprocessRenderer->SetEffectEnabled(msg->GetEffect(), msg->IsEnabled()); + break; + } + default: ASSERT(false, ()); } @@ -824,7 +834,7 @@ void FrontendRenderer::UpdateGLResources() routeData->m_color, routeData->m_traffic, routeData->m_pattern, m_lastRecacheRouteId); m_routeRenderer->ClearGLDependentResources(); - m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, move(recacheRouteMsg), + m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, std::move(recacheRouteMsg), MessagePriority::Normal); } @@ -833,7 +843,8 @@ void FrontendRenderer::UpdateGLResources() // Request new tiles. ScreenBase screen = m_userEventStream.GetCurrentScreen(); m_lastReadedModelView = screen; - m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), m_forceUpdateScene, ResolveTileKeys(screen)); + m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), + m_forceUpdateScene, ResolveTileKeys(screen)); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp(), MessagePriority::UberHighSingleton); @@ -841,10 +852,12 @@ void FrontendRenderer::UpdateGLResources() m_gpsTrackRenderer->Update(); } -void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLevelIn3d, bool enableAutoZoom) +void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLevelIn3d, + bool enableAutoZoom) { - m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel : preferredZoomLevelIn3d, - enableAutoZoom); + m_myPositionController->ActivateRouting( + !m_enablePerspectiveInNavigation ? preferredZoomLevel : preferredZoomLevelIn3d, + enableAutoZoom); if (m_enablePerspectiveInNavigation) AddUserEvent(make_unique_dp(true /* isAutoPerspective */)); @@ -904,16 +917,20 @@ void FrontendRenderer::OnResize(ScreenBase const & screen) m_myPositionController->OnUpdateScreen(screen); + uint32_t const sx = static_cast(viewportRect.SizeX()); + uint32_t const sy = static_cast(viewportRect.SizeY()); + if (viewportChanged) { m_myPositionController->UpdatePosition(); - m_viewport.SetViewport(0, 0, viewportRect.SizeX(), viewportRect.SizeY()); + m_viewport.SetViewport(0, 0, sx, sy); } if (viewportChanged || m_needRestoreSize) { - m_contextFactory->getDrawContext()->resize(viewportRect.SizeX(), viewportRect.SizeY()); - m_framebuffer->SetSize(viewportRect.SizeX(), viewportRect.SizeY()); + m_contextFactory->getDrawContext()->resize(sx, sy); + m_buildingsFramebuffer->SetSize(sx, sy); + m_postprocessRenderer->Resize(sx, sy); m_needRestoreSize = false; } @@ -932,7 +949,7 @@ void FrontendRenderer::AddToRenderGroup(dp::GLState const & state, { if (!g->IsPendingOnDelete() && g->GetState() == state && g->GetTileKey().EqualStrict(newTile)) { - g->AddBucket(move(renderBucket)); + g->AddBucket(std::move(renderBucket)); layer.m_isDirty = true; return; } @@ -942,7 +959,7 @@ void FrontendRenderer::AddToRenderGroup(dp::GLState const & state, ref_ptr program = m_gpuProgramManager->GetProgram(state.GetProgramIndex()); ref_ptr program3d = m_gpuProgramManager->GetProgram(state.GetProgram3dIndex()); group->SetRenderParams(program, program3d, make_ref(&m_generalUniforms)); - group->AddBucket(move(renderBucket)); + group->AddBucket(std::move(renderBucket)); layer.m_renderGroups.push_back(move(group)); layer.m_isDirty = true; @@ -1102,14 +1119,16 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) DrapeMeasurer::Instance().BeforeRenderFrame(); #endif + m_postprocessRenderer->BeginFrame(); + GLFunctions::glEnable(gl_const::GLDepthTest); m_viewport.Apply(); RefreshBgColor(); - GLFunctions::glClear(); + GLFunctions::glClear(gl_const::GLColorBit | gl_const::GLDepthBit | gl_const::GLStencilBit); Render2dLayer(modelView); - if (m_framebuffer->IsSupported()) + if (m_buildingsFramebuffer->IsSupported()) { RenderTrafficAndRouteLayer(modelView); Render3dLayer(modelView, true /* useFramebuffer */); @@ -1122,7 +1141,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) // After this line we do not use (almost) depth buffer. GLFunctions::glDisable(gl_const::GLDepthTest); - GLFunctions::glClearDepth(); + GLFunctions::glClear(gl_const::GLDepthBit); if (m_selectionShape != nullptr) { @@ -1131,38 +1150,56 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) { ASSERT(m_myPositionController->IsModeHasPosition(), ()); m_selectionShape->SetPosition(m_myPositionController->Position()); - m_selectionShape->Render(modelView, m_currentZoomLevel, - make_ref(m_gpuProgramManager), m_generalUniforms); + m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), + m_generalUniforms); } else if (selectedObject == SelectionShape::OBJECT_POI) { - m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms); + m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), + m_generalUniforms); } } - RenderOverlayLayer(modelView); + { + StencilWriterGuard guard(make_ref(m_postprocessRenderer)); + RenderOverlayLayer(modelView); + } - m_gpsTrackRenderer->RenderTrack(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms); + m_gpsTrackRenderer->RenderTrack(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), + m_generalUniforms); - if (m_selectionShape != nullptr && m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_USER_MARK) - m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms); + if (m_selectionShape != nullptr && + m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_USER_MARK) + { + m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), + m_generalUniforms); + } - RenderUserMarksLayer(modelView); + { + StencilWriterGuard guard(make_ref(m_postprocessRenderer)); + RenderUserMarksLayer(modelView); + m_routeRenderer->RenderRouteSigns(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); + } - m_routeRenderer->RenderRouteSigns(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); - - m_myPositionController->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms); + m_myPositionController->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), + m_generalUniforms); m_drapeApiRenderer->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); if (m_guiRenderer != nullptr) - m_guiRenderer->Render(make_ref(m_gpuProgramManager), m_myPositionController->IsInRouting(), modelView); + { + StencilWriterGuard guard(make_ref(m_postprocessRenderer)); + m_guiRenderer->Render(make_ref(m_gpuProgramManager), m_myPositionController->IsInRouting(), + modelView); + } #if defined(RENDER_DEBUG_RECTS) && defined(COLLECT_DISPLACEMENT_INFO) for (auto const & arrow : m_overlayTree->GetDisplacementInfo()) dp::DebugRectRenderer::Instance().DrawArrow(modelView, arrow); #endif + m_postprocessRenderer->EndFrame(make_ref(m_gpuProgramManager)); + #if defined(DRAPE_MEASURER) && (defined(RENDER_STATISTIC) || defined(TRACK_GPU_MEM)) DrapeMeasurer::Instance().AfterRenderFrame(); #endif @@ -1184,13 +1221,13 @@ void FrontendRenderer::Render3dLayer(ScreenBase const & modelView, bool useFrame float const kOpacity = 0.7f; if (useFramebuffer) { - ASSERT(m_framebuffer->IsSupported(), ()); - m_framebuffer->Enable(); + ASSERT(m_buildingsFramebuffer->IsSupported(), ()); + m_buildingsFramebuffer->Enable(); GLFunctions::glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - GLFunctions::glClear(); + GLFunctions::glClear(gl_const::GLColorBit); } - GLFunctions::glClearDepth(); + GLFunctions::glClear(gl_const::GLDepthBit); GLFunctions::glEnable(gl_const::GLDepthTest); RenderLayer & layer = m_layers[RenderLayer::Geometry3dID]; layer.Sort(make_ref(m_overlayTree)); @@ -1199,10 +1236,10 @@ void FrontendRenderer::Render3dLayer(ScreenBase const & modelView, bool useFrame if (useFramebuffer) { - m_framebuffer->Disable(); - GLFunctions::glDisable(gl_const::GLDepthTest); - m_screenQuadRenderer->RenderTexture(m_framebuffer->GetTextureId(), - make_ref(m_gpuProgramManager), kOpacity); + m_buildingsFramebuffer->Disable(); + m_screenQuadRenderer->RenderTexture(make_ref(m_gpuProgramManager), + m_buildingsFramebuffer->GetTextureId(), + kOpacity); } } @@ -1216,14 +1253,14 @@ void FrontendRenderer::RenderOverlayLayer(ScreenBase const & modelView) void FrontendRenderer::RenderTrafficAndRouteLayer(ScreenBase const & modelView) { - GLFunctions::glClearDepth(); + GLFunctions::glClear(gl_const::GLDepthBit); GLFunctions::glEnable(gl_const::GLDepthTest); if (m_trafficRenderer->HasRenderData()) { m_trafficRenderer->RenderTraffic(modelView, m_currentZoomLevel, 1.0f /* opacity */, make_ref(m_gpuProgramManager), m_generalUniforms); } - GLFunctions::glClearDepth(); + GLFunctions::glClear(gl_const::GLDepthBit); m_routeRenderer->RenderRoute(modelView, m_trafficRenderer->HasRenderData(), make_ref(m_gpuProgramManager), m_generalUniforms); } @@ -1282,10 +1319,10 @@ void FrontendRenderer::MergeBuckets() if (layer.m_renderGroups.empty()) return; - using TGroupMap = map>>; + using TGroupMap = map>>; TGroupMap forMerge; - vector> newGroups; + std::vector> newGroups; newGroups.reserve(layer.m_renderGroups.size()); size_t groupsCount = layer.m_renderGroups.size(); @@ -1296,23 +1333,24 @@ void FrontendRenderer::MergeBuckets() { dp::GLState state = group->GetState(); ASSERT_EQUAL(state.GetDepthLayer(), dp::GLState::GeometryLayer, ()); - forMerge[MergedGroupKey(state, group->GetTileKey())].push_back(move(layer.m_renderGroups[i])); + MergedGroupKey const k(state, group->GetTileKey()); + forMerge[k].push_back(std::move(layer.m_renderGroups[i])); } else { - newGroups.push_back(move(layer.m_renderGroups[i])); + newGroups.push_back(std::move(layer.m_renderGroups[i])); } } for (TGroupMap::value_type & node : forMerge) { if (node.second.size() < 2) - newGroups.emplace_back(move(node.second.front())); + newGroups.emplace_back(std::move(node.second.front())); else BatchMergeHelper::MergeBatches(node.second, newGroups, isPerspective); } - layer.m_renderGroups = move(newGroups); + layer.m_renderGroups = std::move(newGroups); layer.m_isDirty = true; }; @@ -1321,11 +1359,6 @@ void FrontendRenderer::MergeBuckets() mergeFn(m_layers[RenderLayer::Geometry3dID], isPerspective); } -bool FrontendRenderer::IsPerspective() const -{ - return m_userEventStream.GetCurrentScreen().isPerspective(); -} - void FrontendRenderer::RenderSingleGroup(ScreenBase const & modelView, ref_ptr group) { group->UpdateAnimation(); @@ -1334,15 +1367,14 @@ void FrontendRenderer::RenderSingleGroup(ScreenBase const & modelView, ref_ptr m; - + std::array m; dp::MakeProjection(m, 0.0f, screen.GetWidth(), screen.GetHeight(), 0.0f); m_generalUniforms.SetMatrix4x4Value("projection", m.data()); } void FrontendRenderer::RefreshZScale(ScreenBase const & screen) { - m_generalUniforms.SetFloatValue("zScale", screen.GetZScale()); + m_generalUniforms.SetFloatValue("zScale", static_cast(screen.GetZScale())); } void FrontendRenderer::RefreshPivotTransform(ScreenBase const & screen) @@ -1355,7 +1387,7 @@ void FrontendRenderer::RefreshPivotTransform(ScreenBase const & screen) else if (m_isIsometry) { math::Matrix transform(math::Identity()); - transform(2, 1) = -1.0f / tan(kIsometryAngle); + transform(2, 1) = -1.0f / static_cast(tan(kIsometryAngle)); transform(2, 2) = 1.0f / screen.GetHeight(); m_generalUniforms.SetMatrix4x4Value("pivotTransform", transform.m_data); } @@ -1449,7 +1481,7 @@ void FrontendRenderer::OnTwoFingersTap() bool FrontendRenderer::OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) { - // This method can be called before gui rendererer initialization. + // This method can be called before gui renderer initialization. if (m_guiRenderer == nullptr) return false; @@ -1526,11 +1558,12 @@ void FrontendRenderer::OnTouchMapAction() { m_myPositionController->ResetRoutingNotFollowTimer(); } - -bool FrontendRenderer::OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) +bool FrontendRenderer::OnNewVisibleViewport(m2::RectD const & oldViewport, + m2::RectD const & newViewport, m2::PointD & gOffset) { gOffset = m2::PointD(0, 0); - if (m_myPositionController->IsModeChangeViewport() || m_selectionShape == nullptr || oldViewport == newViewport) + if (m_myPositionController->IsModeChangeViewport() || m_selectionShape == nullptr || + oldViewport == newViewport) return false; ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); @@ -1611,7 +1644,7 @@ TTilesCollection FrontendRenderer::ResolveTileKeys(ScreenBase const & screen) return group->GetTileKey().m_zoomLevel == m_currentZoomLevel && (key.m_x < result.m_minTileX || key.m_x >= result.m_maxTileX || key.m_y < result.m_minTileY || key.m_y >= result.m_maxTileY || - find(tilesToDelete.begin(), tilesToDelete.end(), key) != tilesToDelete.end()); + std::find(tilesToDelete.begin(), tilesToDelete.end(), key) != tilesToDelete.end()); }; for (RenderLayer & layer : m_layers) layer.m_isDirty |= RemoveGroups(removePredicate, layer.m_renderGroups, make_ref(m_overlayTree)); @@ -1647,7 +1680,7 @@ void FrontendRenderer::OnContextDestroy() m_userMarkRenderGroups.clear(); m_guiRenderer.reset(); m_selectionShape.reset(); - m_framebuffer.reset(); + m_buildingsFramebuffer.reset(); m_screenQuadRenderer.reset(); m_myPositionController->ResetRenderShape(); @@ -1655,6 +1688,7 @@ void FrontendRenderer::OnContextDestroy() m_gpsTrackRenderer->ClearRenderData(); m_trafficRenderer->ClearGLDependentResources(); m_drapeApiRenderer->Clear(); + m_postprocessRenderer->ClearGLDependentResources(); #ifdef RENDER_DEBUG_RECTS dp::DebugRectRenderer::Instance().Destroy(); @@ -1700,11 +1734,19 @@ void FrontendRenderer::OnContextCreate() dp::DebugRectRenderer::Instance().Init(make_ref(m_gpuProgramManager), gpu::DEBUG_RECT_PROGRAM); #endif - // resources recovering - m_framebuffer.reset(new dp::Framebuffer()); - m_framebuffer->SetDefaultContext(context); - + // Resources recovering. m_screenQuadRenderer.reset(new ScreenQuadRenderer()); + + m_postprocessRenderer->Init([context]() { context->setDefaultFramebuffer(); }); + m_postprocessRenderer->SetEnabled(m_apiVersion == dp::ApiVersion::OpenGLES3); + if (dp::SupportManager::Instance().IsAntialiasingEnabledByDefault()) + m_postprocessRenderer->SetEffectEnabled(PostprocessRenderer::Antialiasing, true); + + m_buildingsFramebuffer.reset(new dp::Framebuffer(gl_const::GLRGBA, false /* stencilEnabled */)); + m_buildingsFramebuffer->SetFramebufferFallback([this]() + { + m_postprocessRenderer->OnFramebufferFallback(); + }); } FrontendRenderer::Routine::Routine(FrontendRenderer & renderer) : m_renderer(renderer) {} @@ -1713,7 +1755,7 @@ void FrontendRenderer::Routine::Do() { LOG(LINFO, ("Start routine.")); - gui::DrapeGui::Instance().ConnectOnCompassTappedHandler(bind(&FrontendRenderer::OnCompassTapped, &m_renderer)); + gui::DrapeGui::Instance().ConnectOnCompassTappedHandler(std::bind(&FrontendRenderer::OnCompassTapped, &m_renderer)); m_renderer.m_myPositionController->SetListener(ref_ptr(&m_renderer)); m_renderer.m_userEventStream.SetListener(ref_ptr(&m_renderer)); @@ -1738,8 +1780,6 @@ void FrontendRenderer::Routine::Do() if (viewportChanged) m_renderer.OnResize(modelView); - context->setDefaultFramebuffer(); - if (modelViewChanged || viewportChanged) m_renderer.PrepareScene(modelView); @@ -1783,7 +1823,7 @@ void FrontendRenderer::Routine::Do() activityTimer.Reset(); availableTime = kVSyncInterval - timer.ElapsedSeconds(); } - while (availableTime > 0); + while (availableTime > 0.0); } context->present(); @@ -1796,7 +1836,7 @@ void FrontendRenderer::Routine::Do() m_renderer.m_myPositionController->IsRouteFollowingActive() && frameTime < kFrameTime) { uint32_t const ms = static_cast((kFrameTime - frameTime) * 1000); - this_thread::sleep_for(milliseconds(ms)); + this_thread::sleep_for(std::chrono::milliseconds(ms)); } if (m_renderer.m_overlaysTracker->IsValid() && @@ -1828,9 +1868,10 @@ void FrontendRenderer::ReleaseResources() m_myPositionController.reset(); m_selectionShape.release(); m_routeRenderer.reset(); - m_framebuffer.reset(); + m_buildingsFramebuffer.reset(); m_screenQuadRenderer.reset(); m_trafficRenderer.reset(); + m_postprocessRenderer.reset(); m_gpuProgramManager.reset(); m_contextFactory->getDrawContext()->doneCurrent(); @@ -1842,7 +1883,7 @@ void FrontendRenderer::AddUserEvent(drape_ptr && event) if (m_scenarioManager->IsRunning() && event->GetType() == UserEvent::EventType::Touch) return; #endif - m_userEventStream.AddEvent(move(event)); + m_userEventStream.AddEvent(std::move(event)); if (IsInInfinityWaiting()) CancelMessageWaiting(); } @@ -1852,17 +1893,20 @@ void FrontendRenderer::PositionChanged(m2::PointD const & position) m_userPositionChangedFn(position); } -void FrontendRenderer::ChangeModelView(m2::PointD const & center, int zoomLevel, TAnimationCreator const & parallelAnimCreator) +void FrontendRenderer::ChangeModelView(m2::PointD const & center, int zoomLevel, + TAnimationCreator const & parallelAnimCreator) { AddUserEvent(make_unique_dp(center, zoomLevel, true, parallelAnimCreator)); } -void FrontendRenderer::ChangeModelView(double azimuth, TAnimationCreator const & parallelAnimCreator) +void FrontendRenderer::ChangeModelView(double azimuth, + TAnimationCreator const & parallelAnimCreator) { AddUserEvent(make_unique_dp(azimuth, parallelAnimCreator)); } -void FrontendRenderer::ChangeModelView(m2::RectD const & rect, TAnimationCreator const & parallelAnimCreator) +void FrontendRenderer::ChangeModelView(m2::RectD const & rect, + TAnimationCreator const & parallelAnimCreator) { AddUserEvent(make_unique_dp(rect, true, kDoNotChangeZoom, true, parallelAnimCreator)); } @@ -1871,13 +1915,16 @@ void FrontendRenderer::ChangeModelView(m2::PointD const & userPos, double azimut m2::PointD const & pxZero, int preferredZoomLevel, TAnimationCreator const & parallelAnimCreator) { - AddUserEvent(make_unique_dp(userPos, pxZero, azimuth, preferredZoomLevel, true, parallelAnimCreator)); + AddUserEvent(make_unique_dp(userPos, pxZero, azimuth, preferredZoomLevel, + true, parallelAnimCreator)); } -void FrontendRenderer::ChangeModelView(double autoScale, m2::PointD const & userPos, double azimuth, m2::PointD const & pxZero, +void FrontendRenderer::ChangeModelView(double autoScale, m2::PointD const & userPos, double azimuth, + m2::PointD const & pxZero, TAnimationCreator const & parallelAnimCreator) { - AddUserEvent(make_unique_dp(userPos, pxZero, azimuth, autoScale, parallelAnimCreator)); + AddUserEvent(make_unique_dp(userPos, pxZero, azimuth, autoScale, + parallelAnimCreator)); } ScreenBase const & FrontendRenderer::ProcessEvents(bool & modelViewChanged, bool & viewportChanged) @@ -1894,7 +1941,7 @@ void FrontendRenderer::PrepareScene(ScreenBase const & modelView) RefreshPivotTransform(modelView); m_myPositionController->OnUpdateScreen(modelView); - m_routeRenderer->UpdateRoute(modelView, bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); + m_routeRenderer->UpdateRoute(modelView, std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); } void FrontendRenderer::UpdateScene(ScreenBase const & modelView) @@ -1931,7 +1978,7 @@ void FrontendRenderer::EmitModelViewChanged(ScreenBase const & modelView) const m_modelViewChangedFn(modelView); } -void FrontendRenderer::OnCacheRouteArrows(int routeIndex, vector const & borders) +void FrontendRenderer::OnCacheRouteArrows(int routeIndex, std::vector const & borders) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp(routeIndex, borders), @@ -1954,7 +2001,8 @@ FrontendRenderer::RenderLayer::RenderLayerID FrontendRenderer::RenderLayer::GetL if (state.GetDepthLayer() == dp::GLState::OverlayLayer) return OverlayID; - if (state.GetProgram3dIndex() == gpu::AREA_3D_PROGRAM || state.GetProgram3dIndex() == gpu::AREA_3D_OUTLINE_PROGRAM) + if (state.GetProgram3dIndex() == gpu::AREA_3D_PROGRAM || + state.GetProgram3dIndex() == gpu::AREA_3D_OUTLINE_PROGRAM) return Geometry3dID; return Geometry2dID; diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 3fa2cebb33..309e7e6acc 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -14,27 +14,28 @@ #include "drape_frontend/render_group.hpp" #include "drape_frontend/requested_tiles.hpp" #include "drape_frontend/route_renderer.hpp" +#include "drape_frontend/postprocess_renderer.hpp" #include "drape_frontend/threads_commutator.hpp" #include "drape_frontend/tile_info.hpp" #include "drape_frontend/traffic_renderer.hpp" #include "drape_frontend/user_event_stream.hpp" -#include "drape/pointers.hpp" #include "drape/glstate.hpp" -#include "drape/vertex_array_buffer.hpp" #include "drape/gpu_program_manager.hpp" #include "drape/overlay_tree.hpp" +#include "drape/pointers.hpp" #include "drape/uniform_values_storage.hpp" +#include "drape/vertex_array_buffer.hpp" #include "platform/location.hpp" #include "geometry/screenbase.hpp" #include "geometry/triangle2d.hpp" -#include "std/function.hpp" -#include "std/map.hpp" -#include "std/array.hpp" -#include "std/unordered_set.hpp" +#include +#include +#include +#include namespace dp { @@ -58,42 +59,37 @@ struct TapInfo FeatureID const m_featureTapped; }; -class FrontendRenderer : public BaseRenderer - , public MyPositionController::Listener - , public UserEventStream::Listener +class FrontendRenderer : public BaseRenderer, + public MyPositionController::Listener, + public UserEventStream::Listener { public: - using TModelViewChanged = function; - using TTapEventInfoFn = function; - using TUserPositionChangedFn = function; + using TModelViewChanged = std::function; + using TTapEventInfoFn = std::function; + using TUserPositionChangedFn = std::function; struct Params : BaseRenderer::Params { - Params(dp::ApiVersion apiVersion, - ref_ptr commutator, - ref_ptr factory, - ref_ptr texMng, - MyPositionController::Params && myPositionParams, - dp::Viewport viewport, - TModelViewChanged const & modelViewChangedFn, - TTapEventInfoFn const & tapEventFn, - TUserPositionChangedFn const & positionChangedFn, - ref_ptr requestedTiles, + Params(dp::ApiVersion apiVersion, ref_ptr commutator, + ref_ptr factory, ref_ptr texMng, + MyPositionController::Params && myPositionParams, dp::Viewport viewport, + TModelViewChanged const & modelViewChangedFn, TTapEventInfoFn const & tapEventFn, + TUserPositionChangedFn const & positionChangedFn, ref_ptr requestedTiles, OverlaysShowStatsCallback && overlaysShowStatsCallback, - bool allow3dBuildings, - bool trafficEnabled, - bool blockTapEvents) + bool allow3dBuildings, bool trafficEnabled, bool blockTapEvents, + std::vector && enabledEffects) : BaseRenderer::Params(apiVersion, commutator, factory, texMng) - , m_myPositionParams(move(myPositionParams)) + , m_myPositionParams(std::move(myPositionParams)) , m_viewport(viewport) , m_modelViewChangedFn(modelViewChangedFn) , m_tapEventFn(tapEventFn) , m_positionChangedFn(positionChangedFn) , m_requestedTiles(requestedTiles) - , m_overlaysShowStatsCallback(move(overlaysShowStatsCallback)) + , m_overlaysShowStatsCallback(std::move(overlaysShowStatsCallback)) , m_allow3dBuildings(allow3dBuildings) , m_trafficEnabled(trafficEnabled) , m_blockTapEvents(blockTapEvents) + , m_enabledEffects(std::move(enabledEffects)) {} MyPositionController::Params m_myPositionParams; @@ -101,18 +97,12 @@ public: TModelViewChanged m_modelViewChangedFn; TTapEventInfoFn m_tapEventFn; TUserPositionChangedFn m_positionChangedFn; - location::TMyPositionModeChanged m_myPositionModeCallback; - location::EMyPositionMode m_initMyPositionMode; ref_ptr m_requestedTiles; OverlaysShowStatsCallback m_overlaysShowStatsCallback; - double m_timeInBackground; bool m_allow3dBuildings; bool m_trafficEnabled; bool m_blockTapEvents; - bool m_firstLaunch; - bool m_isLaunchByDeepLink; - bool m_isRoutingActive; - bool m_isAutozoomEnabled; + std::vector m_enabledEffects; }; FrontendRenderer(Params && params); @@ -122,14 +112,18 @@ public: void AddUserEvent(drape_ptr && event); - /// MyPositionController::Listener + // MyPositionController::Listener void PositionChanged(m2::PointD const & position) override; - void ChangeModelView(m2::PointD const & center, int zoomLevel, TAnimationCreator const & parallelAnimCreator) override; + void ChangeModelView(m2::PointD const & center, int zoomLevel, + TAnimationCreator const & parallelAnimCreator) override; void ChangeModelView(double azimuth, TAnimationCreator const & parallelAnimCreator) override; - void ChangeModelView(m2::RectD const & rect, TAnimationCreator const & parallelAnimCreator) override; + void ChangeModelView(m2::RectD const & rect, + TAnimationCreator const & parallelAnimCreator) override; void ChangeModelView(m2::PointD const & userPos, double azimuth, m2::PointD const & pxZero, - int preferredZoomLevel, TAnimationCreator const & parallelAnimCreator) override; - void ChangeModelView(double autoScale, m2::PointD const & userPos, double azimuth, m2::PointD const & pxZero, + int preferredZoomLevel, + TAnimationCreator const & parallelAnimCreator) override; + void ChangeModelView(double autoScale, m2::PointD const & userPos, double azimuth, + m2::PointD const & pxZero, TAnimationCreator const & parallelAnimCreator) override; drape_ptr const & GetScenarioManager() const; @@ -151,14 +145,13 @@ private: void RefreshPivotTransform(ScreenBase const & screen); void RefreshBgColor(); - ////// - /// Render part of scene + // Render part of scene void Render2dLayer(ScreenBase const & modelView); void Render3dLayer(ScreenBase const & modelView, bool useFramebuffer); void RenderOverlayLayer(ScreenBase const & modelView); void RenderUserMarksLayer(ScreenBase const & modelView); void RenderTrafficAndRouteLayer(ScreenBase const & modelView); - ////// + ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged); void PrepareScene(ScreenBase const & modelView); void UpdateScene(ScreenBase const & modelView); @@ -189,14 +182,13 @@ private: void OnScaleEnded() override; void OnAnimatedScaleEnded() override; void OnTouchMapAction() override; - bool OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) override; + bool OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, + m2::PointD & gOffset) override; class Routine : public threads::IRoutine { public: Routine(FrontendRenderer & renderer); - - // threads::IRoutine overrides: void Do() override; private: @@ -210,11 +202,10 @@ private: void UpdateOverlayTree(ScreenBase const & modelView, drape_ptr & renderGroup); void EndUpdateOverlayTree(); - void AddToRenderGroup(dp::GLState const & state, - drape_ptr && renderBucket, + void AddToRenderGroup(dp::GLState const & state, drape_ptr && renderBucket, TileKey const & newTile); - using TRenderGroupRemovePredicate = function const &)>; + using TRenderGroupRemovePredicate = std::function const &)>; void RemoveRenderGroupsLater(TRenderGroupRemovePredicate const & predicate); void FollowRoute(int preferredZoomLevel, int preferredZoomLevelIn3d, bool enableAutoZoom); @@ -227,15 +218,13 @@ private: FeatureID GetVisiblePOI(m2::PointD const & pixelPoint); FeatureID GetVisiblePOI(m2::RectD const & pixelRect); - bool IsPerspective() const; - void PrepareGpsTrackPoints(uint32_t pointsCount); void PullToBoundArea(bool randomPlace, bool applyZoom); void ProcessSelection(ref_ptr msg); - void OnCacheRouteArrows(int routeIndex, vector const & borders); + void OnCacheRouteArrows(int routeIndex, std::vector const & borders); void CollectShowOverlaysEvents(); @@ -253,22 +242,22 @@ private: static RenderLayerID GetLayerID(dp::GLState const & renderGroup); - vector> m_renderGroups; + std::vector> m_renderGroups; bool m_isDirty = false; void Sort(ref_ptr overlayTree); }; - array m_layers; - vector> m_userMarkRenderGroups; - unordered_set m_userMarkVisibility; + std::array m_layers; + std::vector> m_userMarkRenderGroups; + std::unordered_set m_userMarkVisibility; drape_ptr m_guiRenderer; drape_ptr m_myPositionController; drape_ptr m_selectionShape; drape_ptr m_routeRenderer; drape_ptr m_trafficRenderer; - drape_ptr m_framebuffer; + drape_ptr m_buildingsFramebuffer; drape_ptr m_screenQuadRenderer; drape_ptr m_gpsTrackRenderer; drape_ptr m_drapeApiRenderer; @@ -295,7 +284,7 @@ private: TTilesCollection m_notFinishedTiles; int m_currentZoomLevel = -1; - + ref_ptr m_requestedTiles; uint64_t m_maxGeneration; int m_mergeBucketsCounter = 0; @@ -304,9 +293,7 @@ private: struct FollowRouteData { - FollowRouteData(int preferredZoomLevel, - int preferredZoomLevelIn3d, - bool enableAutoZoom) + FollowRouteData(int preferredZoomLevel, int preferredZoomLevelIn3d, bool enableAutoZoom) : m_preferredZoomLevel(preferredZoomLevel) , m_preferredZoomLevelIn3d(preferredZoomLevelIn3d) , m_enableAutoZoom(enableAutoZoom) @@ -319,7 +306,7 @@ private: unique_ptr m_pendingFollowRoute; - vector m_dragBoundArea; + std::vector m_dragBoundArea; drape_ptr m_selectObjectMessage; @@ -332,11 +319,12 @@ private: bool m_forceUpdateScene; + drape_ptr m_postprocessRenderer; + drape_ptr m_scenarioManager; #ifdef DEBUG bool m_isTeardowned; #endif }; - -} // namespace df +} // namespace df diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 69ee6c4172..048f167290 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -46,7 +46,7 @@ public: FollowRoute, DeactivateRouteFollowing, UpdateMapStyle, - InvalidateTextures, + SwitchMapStyle, Invalidate, Allow3dMode, Allow3dBuildings, @@ -78,6 +78,8 @@ public: AddCustomSymbols, RemoveCustomSymbols, UpdateCustomSymbols, + SetPostprocessStaticTextures, + SetPosteffectEnabled, }; virtual ~Message() {} diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 17b9ea5c3d..d322832e69 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -12,6 +12,7 @@ #include "drape_frontend/message.hpp" #include "drape_frontend/my_position.hpp" #include "drape_frontend/overlay_batcher.hpp" +#include "drape_frontend/postprocess_renderer.hpp" #include "drape_frontend/route_builder.hpp" #include "drape_frontend/selection_shape.hpp" #include "drape_frontend/tile_utils.hpp" @@ -785,14 +786,14 @@ private: bool const m_enableAutoZoom; }; -class InvalidateTexturesMessage : public BaseBlockingMessage +class SwitchMapStyleMessage : public BaseBlockingMessage { public: - InvalidateTexturesMessage(Blocker & blocker) + SwitchMapStyleMessage(Blocker & blocker) : BaseBlockingMessage(blocker) {} - Type GetType() const override { return Message::InvalidateTextures; } + Type GetType() const override { return Message::SwitchMapStyle; } }; class InvalidateMessage : public Message @@ -1198,4 +1199,35 @@ private: std::vector m_symbolsFeatures; }; -} // namespace df +class SetPostprocessStaticTexturesMessage : public Message +{ +public: + explicit SetPostprocessStaticTexturesMessage(drape_ptr && textures) + : m_textures(std::move(textures)) + {} + + Type GetType() const override { return Message::SetPostprocessStaticTextures; } + + drape_ptr && AcceptTextures() { return std::move(m_textures); } + +private: + drape_ptr m_textures; +}; + +class SetPosteffectEnabledMessage : public Message +{ +public: + SetPosteffectEnabledMessage(PostprocessRenderer::Effect effect, bool enabled) + : m_effect(effect) + , m_enabled(enabled) + {} + + Type GetType() const override { return Message::SetPosteffectEnabled; } + PostprocessRenderer::Effect GetEffect() const { return m_effect; } + bool IsEnabled() const { return m_enabled; } + +private: + PostprocessRenderer::Effect const m_effect; + bool const m_enabled; +}; +} // namespace df diff --git a/drape_frontend/postprocess_renderer.cpp b/drape_frontend/postprocess_renderer.cpp new file mode 100644 index 0000000000..37d77fc5dc --- /dev/null +++ b/drape_frontend/postprocess_renderer.cpp @@ -0,0 +1,416 @@ +#include "drape_frontend/postprocess_renderer.hpp" +#include "drape_frontend/screen_quad_renderer.hpp" +#include "drape_frontend/shader_def.hpp" + +#include "drape/glfunctions.hpp" +#include "drape/glstate.hpp" +#include "drape/gpu_program_manager.hpp" +#include "drape/texture_manager.hpp" +#include "drape/uniform_values_storage.hpp" + +#include "base/assert.hpp" + +namespace df +{ +namespace +{ +class SMAABaseRendererContext : public RendererContext +{ +protected: + void ApplyFramebufferMetrics(ref_ptr prg) + { + dp::UniformValuesStorage uniforms; + uniforms.SetFloatValue("u_framebufferMetrics", 1.0f / m_width, 1.0f / m_height, + m_width, m_height); + dp::ApplyUniforms(uniforms, prg); + } + + float m_width = 1.0f; + float m_height = 1.0f; +}; + +class EdgesRendererContext : public SMAABaseRendererContext +{ +public: + int GetGpuProgram() const override { return gpu::SMAA_EDGES_PROGRAM; } + + void PreRender(ref_ptr prg) override + { + GLFunctions::glClear(gl_const::GLColorBit); + + BindTexture(m_textureId, prg, "u_colorTex", 0 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + ApplyFramebufferMetrics(prg); + + GLFunctions::glDisable(gl_const::GLDepthTest); + GLFunctions::glDisable(gl_const::GLBlending); + } + + void SetParams(uint32_t textureId, uint32_t width, uint32_t height) + { + m_textureId = textureId; + m_width = static_cast(width); + m_height = static_cast(height); + } + +protected: + uint32_t m_textureId = 0; +}; + +class BlendingWeightRendererContext : public SMAABaseRendererContext +{ +public: + int GetGpuProgram() const override { return gpu::SMAA_BLENDING_WEIGHT_PROGRAM; } + + void PreRender(ref_ptr prg) override + { + GLFunctions::glClear(gl_const::GLColorBit); + + BindTexture(m_edgesTextureId, prg, "u_colorTex", 0 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + BindTexture(m_areaTextureId, prg, "u_smaaArea", 1 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + BindTexture(m_searchTextureId, prg, "u_smaaSearch", 2 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + ApplyFramebufferMetrics(prg); + + GLFunctions::glDisable(gl_const::GLDepthTest); + GLFunctions::glDisable(gl_const::GLBlending); + } + + void PostRender() override + { + GLFunctions::glActiveTexture(gl_const::GLTexture0 + 2); + GLFunctions::glBindTexture(0); + } + + void SetParams(uint32_t edgesTextureId, uint32_t areaTextureId, uint32_t searchTextureId, + uint32_t width, uint32_t height) + { + m_edgesTextureId = edgesTextureId; + m_areaTextureId = areaTextureId; + m_searchTextureId = searchTextureId; + m_width = static_cast(width); + m_height = static_cast(height); + } + +private: + uint32_t m_edgesTextureId = 0; + uint32_t m_areaTextureId = 0; + uint32_t m_searchTextureId = 0; +}; + +class SMAAFinalRendererContext : public SMAABaseRendererContext +{ +public: + int GetGpuProgram() const override { return gpu::SMAA_FINAL_PROGRAM; } + + void PreRender(ref_ptr prg) override + { + GLFunctions::glClear(gl_const::GLColorBit); + + BindTexture(m_colorTextureId, prg, "u_colorTex", 0 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + BindTexture(m_blendingWeightTextureId, prg, "u_blendingWeightTex", 1 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + ApplyFramebufferMetrics(prg); + + GLFunctions::glDisable(gl_const::GLDepthTest); + GLFunctions::glDisable(gl_const::GLBlending); + } + + void PostRender() override + { + GLFunctions::glActiveTexture(gl_const::GLTexture0 + 1); + GLFunctions::glBindTexture(0); + GLFunctions::glActiveTexture(gl_const::GLTexture0); + GLFunctions::glBindTexture(0); + } + + void SetParams(uint32_t colorTextureId, uint32_t blendingWeightTextureId, uint32_t width, + uint32_t height) + { + m_colorTextureId = colorTextureId; + m_blendingWeightTextureId = blendingWeightTextureId; + m_width = static_cast(width); + m_height = static_cast(height); + } + +private: + uint32_t m_colorTextureId = 0; + uint32_t m_blendingWeightTextureId = 0; +}; + +void InitFramebuffer(drape_ptr & framebuffer, uint32_t width, uint32_t height) +{ + if (framebuffer == nullptr) + framebuffer.reset(new dp::Framebuffer(gl_const::GLRGBA, true /* stencilEnabled */)); + framebuffer->SetSize(width, height); +} + +void InitFramebuffer(drape_ptr & framebuffer, uint32_t colorFormat, + ref_ptr depthStencilRef, + uint32_t width, uint32_t height) +{ + if (framebuffer == nullptr) + framebuffer.reset(new dp::Framebuffer(colorFormat)); + framebuffer->SetDepthStencilRef(depthStencilRef); + framebuffer->SetSize(width, height); +} + +bool IsSupported(drape_ptr const & framebuffer) +{ + return framebuffer != nullptr && framebuffer->IsSupported(); +} +} // namespace + +PostprocessRenderer::PostprocessRenderer() + : m_isEnabled(false) + , m_effects(0) + , m_width(0) + , m_height(0) + , m_edgesRendererContext(make_unique_dp()) + , m_bwRendererContext(make_unique_dp()) + , m_smaaFinalRendererContext(make_unique_dp()) + , m_frameStarted(false) +{} + +PostprocessRenderer::~PostprocessRenderer() +{ + ClearGLDependentResources(); +} + +void PostprocessRenderer::Init(dp::FramebufferFallback && fallback) +{ + m_screenQuadRenderer.reset(new ScreenQuadRenderer()); + m_framebufferFallback = std::move(fallback); + ASSERT(m_framebufferFallback != nullptr, ()); +} + +void PostprocessRenderer::ClearGLDependentResources() +{ + m_screenQuadRenderer.reset(); + m_framebufferFallback = nullptr; + m_staticTextures.reset(); + + m_mainFramebuffer.reset(); + m_edgesFramebuffer.reset(); + m_blendingWeightFramebuffer.reset(); +} + +void PostprocessRenderer::Resize(uint32_t width, uint32_t height) +{ + m_width = width; + m_height = height; + + UpdateFramebuffers(m_width, m_height); +} + +void PostprocessRenderer::SetStaticTextures(drape_ptr && textures) +{ + m_staticTextures = std::move(textures); +} + +void PostprocessRenderer::SetEnabled(bool enabled) +{ + m_isEnabled = enabled; + if (m_isEnabled && m_width != 0 && m_height != 0) + UpdateFramebuffers(m_width, m_height); +} + +bool PostprocessRenderer::IsEnabled() const +{ + if (!m_isEnabled || m_effects == 0 || m_staticTextures == nullptr) + return false; + + if (!IsSupported(m_mainFramebuffer)) + return false; + + if (IsEffectEnabled(Effect::Antialiasing) && + (!IsSupported(m_edgesFramebuffer) || !IsSupported(m_blendingWeightFramebuffer))) + { + return false; + } + + // Insert checking new effects here. + + return true; +} + +void PostprocessRenderer::SetEffectEnabled(Effect effect, bool enabled) +{ + uint32_t const oldValue = m_effects; + uint32_t const effectMask = static_cast(effect); + m_effects = (m_effects & ~effectMask) | (enabled ? effectMask : 0); + + if (m_width != 0 && m_height != 0 && oldValue != m_effects) + UpdateFramebuffers(m_width, m_height); +} + +bool PostprocessRenderer::IsEffectEnabled(Effect effect) const +{ + return (m_effects & static_cast(effect)) > 0; +} + +void PostprocessRenderer::BeginFrame() +{ + if (!IsEnabled()) + { + m_framebufferFallback(); + return; + } + + // Check if Subpixel Morphological Antialiasing (SMAA) is unavailable. + ASSERT(m_staticTextures != nullptr, ()); + if (m_staticTextures->m_smaaSearchTexture == nullptr || + m_staticTextures->m_smaaAreaTexture == nullptr || + m_staticTextures->m_smaaAreaTexture->GetID() < 0 || + m_staticTextures->m_smaaSearchTexture->GetID() < 0) + { + SetEffectEnabled(Effect::Antialiasing, false); + } + + m_mainFramebuffer->Enable(); + m_frameStarted = true; + + GLFunctions::glDisable(gl_const::GLStencilTest); +} + +void PostprocessRenderer::EndFrame(ref_ptr gpuProgramManager) +{ + if (!IsEnabled() && !m_frameStarted) + return; + + bool wasPostEffect = false; + + // Subpixel Morphological Antialiasing (SMAA). + if (IsEffectEnabled(Effect::Antialiasing)) + { + wasPostEffect = true; + + ASSERT(m_staticTextures->m_smaaAreaTexture != nullptr, ()); + ASSERT_GREATER_OR_EQUAL(m_staticTextures->m_smaaAreaTexture->GetID(), 0, ()); + + ASSERT(m_staticTextures->m_smaaSearchTexture != nullptr, ()); + ASSERT_GREATER_OR_EQUAL(m_staticTextures->m_smaaSearchTexture->GetID(), 0, ()); + + GLFunctions::glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GLFunctions::glEnable(gl_const::GLStencilTest); + + // Render edges to texture. + { + m_edgesFramebuffer->Enable(); + + GLFunctions::glStencilFuncSeparate(gl_const::GLFrontAndBack, gl_const::GLNotEqual, 1, 1); + GLFunctions::glStencilOpSeparate(gl_const::GLFrontAndBack, gl_const::GLZero, + gl_const::GLZero, gl_const::GLReplace); + + ASSERT(dynamic_cast(m_edgesRendererContext.get()) != nullptr, ()); + auto context = static_cast(m_edgesRendererContext.get()); + context->SetParams(m_mainFramebuffer->GetTextureId(), m_width, m_height); + m_screenQuadRenderer->Render(gpuProgramManager, make_ref(m_edgesRendererContext)); + } + + // Render blending weight to texture. + { + m_blendingWeightFramebuffer->Enable(); + + GLFunctions::glStencilFuncSeparate(gl_const::GLFrontAndBack, gl_const::GLEqual, 1, 1); + GLFunctions::glStencilOpSeparate(gl_const::GLFrontAndBack, gl_const::GLKeep, + gl_const::GLKeep, gl_const::GLKeep); + + ASSERT(dynamic_cast(m_bwRendererContext.get()) != nullptr, ()); + auto context = static_cast(m_bwRendererContext.get()); + context->SetParams(m_edgesFramebuffer->GetTextureId(), + static_cast(m_staticTextures->m_smaaAreaTexture->GetID()), + static_cast(m_staticTextures->m_smaaSearchTexture->GetID()), + m_width, m_height); + m_screenQuadRenderer->Render(gpuProgramManager, make_ref(m_bwRendererContext)); + } + + // SMAA final pass. + GLFunctions::glDisable(gl_const::GLStencilTest); + { + m_framebufferFallback(); + ASSERT(dynamic_cast(m_smaaFinalRendererContext.get()) != nullptr, ()); + auto context = static_cast(m_smaaFinalRendererContext.get()); + context->SetParams(m_mainFramebuffer->GetTextureId(), + m_blendingWeightFramebuffer->GetTextureId(), + m_width, m_height); + m_screenQuadRenderer->Render(gpuProgramManager, make_ref(m_smaaFinalRendererContext)); + } + } + + if (!wasPostEffect) + { + m_framebufferFallback(); + GLFunctions::glClear(gl_const::GLColorBit); + m_screenQuadRenderer->RenderTexture(gpuProgramManager, m_mainFramebuffer->GetTextureId(), + 1.0f /* opacity */); + } + m_frameStarted = false; +} + +void PostprocessRenderer::EnableWritingToStencil() const +{ + if (!m_frameStarted) + return; + GLFunctions::glEnable(gl_const::GLStencilTest); + GLFunctions::glStencilFuncSeparate(gl_const::GLFrontAndBack, gl_const::GLAlways, 1, 1); + GLFunctions::glStencilOpSeparate(gl_const::GLFrontAndBack, gl_const::GLKeep, + gl_const::GLKeep, gl_const::GLReplace); +} + +void PostprocessRenderer::DisableWritingToStencil() const +{ + if (!m_frameStarted) + return; + GLFunctions::glDisable(gl_const::GLStencilTest); +} + +void PostprocessRenderer::UpdateFramebuffers(uint32_t width, uint32_t height) +{ + ASSERT_NOT_EQUAL(width, 0, ()); + ASSERT_NOT_EQUAL(height, 0, ()); + + if (m_effects != 0) + InitFramebuffer(m_mainFramebuffer, width, height); + else + m_mainFramebuffer.reset(); + + if (IsEffectEnabled(Effect::Antialiasing)) + { + InitFramebuffer(m_edgesFramebuffer, gl_const::GLRedGreen, + m_mainFramebuffer->GetDepthStencilRef(), + width, height); + InitFramebuffer(m_blendingWeightFramebuffer, gl_const::GLRGBA, + m_mainFramebuffer->GetDepthStencilRef(), + width, height); + } + else + { + m_edgesFramebuffer.reset(); + m_blendingWeightFramebuffer.reset(); + } +} + +void PostprocessRenderer::OnFramebufferFallback() +{ + if (m_frameStarted) + m_mainFramebuffer->Enable(); + else + m_framebufferFallback(); +} + +StencilWriterGuard::StencilWriterGuard(ref_ptr renderer) + : m_renderer(renderer) +{ + ASSERT(m_renderer != nullptr, ()); + m_renderer->EnableWritingToStencil(); +} + +StencilWriterGuard::~StencilWriterGuard() +{ + m_renderer->DisableWritingToStencil(); +} +} // namespace df diff --git a/drape_frontend/postprocess_renderer.hpp b/drape_frontend/postprocess_renderer.hpp new file mode 100644 index 0000000000..ce926218cf --- /dev/null +++ b/drape_frontend/postprocess_renderer.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include "drape/framebuffer.hpp" +#include "drape/pointers.hpp" + +namespace dp +{ +class GpuProgramManager; +class Texture; +} // namespace dp + +namespace df +{ +class ScreenQuadRenderer; +class RendererContext; + +struct PostprocessStaticTextures +{ + ref_ptr m_smaaAreaTexture; + ref_ptr m_smaaSearchTexture; +}; + +class PostprocessRenderer +{ +public: + enum Effect + { + Antialiasing = 1 + }; + + PostprocessRenderer(); + ~PostprocessRenderer(); + + void Init(dp::FramebufferFallback && fallback); + void ClearGLDependentResources(); + void Resize(uint32_t width, uint32_t height); + void SetStaticTextures(drape_ptr && textures); + + void SetEnabled(bool enabled); + bool IsEnabled() const; + void SetEffectEnabled(Effect effect, bool enabled); + bool IsEffectEnabled(Effect effect) const; + + void OnFramebufferFallback(); + + void BeginFrame(); + void EndFrame(ref_ptr gpuProgramManager); + + void EnableWritingToStencil() const; + void DisableWritingToStencil() const; + +private: + void UpdateFramebuffers(uint32_t width, uint32_t height); + + bool m_isEnabled; + uint32_t m_effects; + + drape_ptr m_screenQuadRenderer; + dp::FramebufferFallback m_framebufferFallback; + drape_ptr m_staticTextures; + uint32_t m_width; + uint32_t m_height; + + drape_ptr m_mainFramebuffer; + drape_ptr m_edgesFramebuffer; + drape_ptr m_blendingWeightFramebuffer; + + drape_ptr m_edgesRendererContext; + drape_ptr m_bwRendererContext; + drape_ptr m_smaaFinalRendererContext; + + bool m_frameStarted; +}; + +class StencilWriterGuard +{ +public: + StencilWriterGuard(ref_ptr renderer); + ~StencilWriterGuard(); +private: + ref_ptr const m_renderer; +}; +} // namespace df diff --git a/drape_frontend/screen_quad_renderer.cpp b/drape_frontend/screen_quad_renderer.cpp index 22818bd365..7da2089685 100644 --- a/drape_frontend/screen_quad_renderer.cpp +++ b/drape_frontend/screen_quad_renderer.cpp @@ -13,10 +13,73 @@ namespace df { +namespace +{ +class TextureRendererContext : public RendererContext +{ +public: + int GetGpuProgram() const override { return gpu::SCREEN_QUAD_PROGRAM; } + + void PreRender(ref_ptr prg) override + { + BindTexture(m_textureId, prg, "u_colorTex", 0 /* slotIndex */, + gl_const::GLLinear, gl_const::GLClampToEdge); + + dp::UniformValuesStorage uniforms; + uniforms.SetFloatValue("u_opacity", m_opacity); + dp::ApplyUniforms(uniforms, prg); + + GLFunctions::glDisable(gl_const::GLDepthTest); + GLFunctions::glEnable(gl_const::GLBlending); + } + + void PostRender() override + { + GLFunctions::glDisable(gl_const::GLBlending); + GLFunctions::glBindTexture(0); + } + + void SetParams(uint32_t textureId, float opacity) + { + m_textureId = textureId; + m_opacity = opacity; + } + +private: + uint32_t m_textureId = 0; + float m_opacity = 1.0f; +}; +} // namespace + +void RendererContext::BindTexture(uint32_t textureId, ref_ptr prg, + std::string const & uniformName, uint8_t slotIndex, + uint32_t filteringMode, uint32_t wrappingMode) +{ + int8_t const textureLocation = prg->GetUniformLocation(uniformName); + ASSERT_NOT_EQUAL(textureLocation, -1, ()); + if (textureLocation < 0) + return; + + GLFunctions::glActiveTexture(gl_const::GLTexture0 + slotIndex); + GLFunctions::glBindTexture(textureId); + GLFunctions::glUniformValuei(textureLocation, slotIndex); + GLFunctions::glTexParameter(gl_const::GLMinFilter, filteringMode); + GLFunctions::glTexParameter(gl_const::GLMagFilter, filteringMode); + GLFunctions::glTexParameter(gl_const::GLWrapS, wrappingMode); + GLFunctions::glTexParameter(gl_const::GLWrapT, wrappingMode); +} + +ScreenQuadRenderer::ScreenQuadRenderer() + : m_textureRendererContext(make_unique_dp()) +{} + ScreenQuadRenderer::~ScreenQuadRenderer() { if (m_bufferId != 0) GLFunctions::glDeleteBuffer(m_bufferId); + + if (m_VAO != 0) + GLFunctions::glDeleteVertexArray(m_VAO); } void ScreenQuadRenderer::Build(ref_ptr prg) @@ -31,10 +94,7 @@ void ScreenQuadRenderer::Build(ref_ptr prg) m_attributeTexCoord = prg->GetAttributeLocation("a_tcoord"); ASSERT_NOT_EQUAL(m_attributeTexCoord, -1, ()); - - m_textureLocation = prg->GetUniformLocation("u_colorTex"); - ASSERT_NOT_EQUAL(m_textureLocation, -1, ()); - + std::vector vertices = {-1.0f, 1.0f, m_textureRect.minX(), m_textureRect.maxY(), 1.0f, 1.0f, m_textureRect.maxX(), m_textureRect.maxY(), -1.0f, -1.0f, m_textureRect.minX(), m_textureRect.minY(), @@ -50,29 +110,17 @@ void ScreenQuadRenderer::Build(ref_ptr prg) GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); } -void ScreenQuadRenderer::RenderTexture(uint32_t textureId, ref_ptr mng, - float opacity) +void ScreenQuadRenderer::Render(ref_ptr mng, ref_ptr context) { - ref_ptr prg = mng->GetProgram(gpu::SCREEN_QUAD_PROGRAM); + ref_ptr prg = mng->GetProgram(context->GetGpuProgram()); prg->Bind(); if (m_bufferId == 0) Build(prg); - if (dp::GLExtensionsList::Instance().IsSupported(dp::GLExtensionsList::VertexArrayObject)) + if (m_VAO != 0) GLFunctions::glBindVertexArray(m_VAO); - if (m_textureLocation >= 0) - { - GLFunctions::glActiveTexture(gl_const::GLTexture0); - GLFunctions::glBindTexture(textureId); - GLFunctions::glUniformValuei(m_textureLocation, 0); - GLFunctions::glTexParameter(gl_const::GLMinFilter, gl_const::GLLinear); - GLFunctions::glTexParameter(gl_const::GLMagFilter, gl_const::GLLinear); - GLFunctions::glTexParameter(gl_const::GLWrapS, gl_const::GLClampToEdge); - GLFunctions::glTexParameter(gl_const::GLWrapT, gl_const::GLClampToEdge); - } - GLFunctions::glBindBuffer(m_bufferId, gl_const::GLArrayBuffer); GLFunctions::glEnableVertexAttribute(m_attributePosition); @@ -82,29 +130,39 @@ void ScreenQuadRenderer::RenderTexture(uint32_t textureId, ref_ptrPreRender(prg); GLFunctions::glDrawArrays(gl_const::GLTriangleStrip, 0, 4); - GLFunctions::glDisable(gl_const::GLBlending); + context->PostRender(); prg->Unbind(); - if (dp::GLExtensionsList::Instance().IsSupported(dp::GLExtensionsList::VertexArrayObject)) - GLFunctions::glBindVertexArray(0); - GLFunctions::glBindTexture(0); GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); + + if (m_VAO != 0) + GLFunctions::glBindVertexArray(0); } -void ScreenQuadRenderer::SetTextureRect(m2::RectF const & rect, ref_ptr mng) +void ScreenQuadRenderer::RenderTexture(ref_ptr mng, uint32_t textureId, + float opacity) +{ + ASSERT(dynamic_cast(m_textureRendererContext.get()) != nullptr, ()); + + auto context = static_cast(m_textureRendererContext.get()); + context->SetParams(textureId, opacity); + + Render(mng, make_ref(m_textureRendererContext)); +} + +void ScreenQuadRenderer::SetTextureRect(m2::RectF const & rect, ref_ptr prg) { m_textureRect = rect; + Rebuild(prg); +} +void ScreenQuadRenderer::Rebuild(ref_ptr prg) +{ if (m_bufferId != 0) GLFunctions::glDeleteBuffer(m_bufferId); - ref_ptr prg = mng->GetProgram(gpu::SCREEN_QUAD_PROGRAM); prg->Bind(); Build(prg); prg->Unbind(); diff --git a/drape_frontend/screen_quad_renderer.hpp b/drape_frontend/screen_quad_renderer.hpp index 2231aab638..512ed29d89 100644 --- a/drape_frontend/screen_quad_renderer.hpp +++ b/drape_frontend/screen_quad_renderer.hpp @@ -4,6 +4,8 @@ #include "geometry/rect2d.hpp" +#include + namespace dp { class GpuProgram; @@ -12,16 +14,33 @@ class GpuProgramManager; namespace df { +class RendererContext +{ +public: + virtual ~RendererContext() {} + virtual int GetGpuProgram() const = 0; + virtual void PreRender(ref_ptr prg) {} + virtual void PostRender() {} +protected: + void BindTexture(uint32_t textureId, ref_ptr prg, + std::string const & uniformName, uint8_t slotIndex, + uint32_t filteringMode, uint32_t wrappingMode); +}; + class ScreenQuadRenderer { public: - ScreenQuadRenderer() = default; + ScreenQuadRenderer(); ~ScreenQuadRenderer(); - void SetTextureRect(m2::RectF const & rect, ref_ptr mng); + void SetTextureRect(m2::RectF const & rect, ref_ptr prg); + void Rebuild(ref_ptr prg); + bool IsInitialized() const { return m_bufferId != 0; } m2::RectF const & GetTextureRect() const { return m_textureRect; } - void RenderTexture(uint32_t textureId, ref_ptr mng, float opacity); + + void Render(ref_ptr mng, ref_ptr context); + void RenderTexture(ref_ptr mng, uint32_t textureId, float opacity); private: void Build(ref_ptr prg); @@ -30,7 +49,8 @@ private: uint32_t m_VAO = 0; int8_t m_attributePosition = -1; int8_t m_attributeTexCoord = -1; - int8_t m_textureLocation = -1; m2::RectF m_textureRect = m2::RectF(0.0f, 0.0f, 1.0f, 1.0f); + + drape_ptr m_textureRendererContext; }; } // namespace df diff --git a/drape_frontend/shaders/shader_index.txt b/drape_frontend/shaders/shader_index.txt index e0dea148f2..d3eabfc6c8 100644 --- a/drape_frontend/shaders/shader_index.txt +++ b/drape_frontend/shaders/shader_index.txt @@ -37,3 +37,6 @@ TEXT_FIXED_BILLBOARD_PROGRAM text_billboard.vsh.glsl text_fixed.fsh.glsl BOOKMARK_BILLBOARD_PROGRAM user_mark_billboard.vsh.glsl texturing.fsh.glsl TRAFFIC_PROGRAM traffic.vsh.glsl traffic.fsh.glsl TRAFFIC_LINE_PROGRAM traffic_line.vsh.glsl traffic_line.fsh.glsl +SMAA_EDGES_PROGRAM smaa_edges.vsh.glsl smaa_edges.fsh.glsl +SMAA_BLENDING_WEIGHT_PROGRAM smaa_blending_weight.vsh.glsl smaa_blending_weight.fsh.glsl +SMAA_FINAL_PROGRAM smaa_final.vsh.glsl smaa_final.fsh.glsl diff --git a/drape_frontend/shaders/smaa_blending_weight.fsh.glsl b/drape_frontend/shaders/smaa_blending_weight.fsh.glsl new file mode 100644 index 0000000000..284fe0a48d --- /dev/null +++ b/drape_frontend/shaders/smaa_blending_weight.fsh.glsl @@ -0,0 +1,189 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +uniform sampler2D u_colorTex; +uniform sampler2D u_smaaArea; +uniform sampler2D u_smaaSearch; + +uniform vec4 u_framebufferMetrics; + +varying vec4 v_coords; +varying vec4 v_offset0; +varying vec4 v_offset1; +varying vec4 v_offset2; + +#define SMAA_SEARCHTEX_SIZE vec2(66.0, 33.0) +#define SMAA_SEARCHTEX_PACKED_SIZE vec2(64.0, 16.0) +#define SMAA_AREATEX_MAX_DISTANCE 16.0 +#define SMAA_AREATEX_PIXEL_SIZE (vec2(1.0 / 256.0, 1.0 / 1024.0)) + +#ifdef GLES3 + #define SMAALoopBegin(condition) while (condition) { + #define SMAALoopEnd } + #define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0) + #define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset) + #define SMAARound(v) round((v)) + #define SMAAOffset(x,y) ivec2(x,y) +#else + #define SMAA_MAX_SEARCH_STEPS 8 + #define SMAALoopBegin(condition) for (int i = 0; i < SMAA_MAX_SEARCH_STEPS; i++) { if (!(condition)) break; + #define SMAALoopEnd } + #define SMAASampleLevelZero(tex, coord) texture2D(tex, coord) + #define SMAASampleLevelZeroOffset(tex, coord, offset) texture2D(tex, coord + vec2(offset) * u_framebufferMetrics.xy) + #define SMAARound(v) floor((v) + 0.5) + #define SMAAOffset(x,y) vec2(x,y) +#endif + +const vec2 kAreaTexMaxDistance = vec2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE); +const float kActivationThreshold = 0.8281; + +float SMAASearchLength(vec2 e, float offset) +{ + // The texture is flipped vertically, with left and right cases taking half + // of the space horizontally. + vec2 scale = SMAA_SEARCHTEX_SIZE * vec2(0.5, -1.0); + vec2 bias = SMAA_SEARCHTEX_SIZE * vec2(offset, 1.0); + + // Scale and bias to access texel centers. + scale += vec2(-1.0, 1.0); + bias += vec2( 0.5, -0.5); + + // Convert from pixel coordinates to texcoords. + // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped). + scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + + // Lookup the search texture. +#ifdef GLES3 + return SMAASampleLevelZero(u_smaaSearch, scale * e + bias).r; +#else + return SMAASampleLevelZero(u_smaaSearch, scale * e + bias).a; +#endif +} + +float SMAASearchXLeft(vec2 texcoord, float end) +{ + vec2 e = vec2(0.0, 1.0); + SMAALoopBegin(texcoord.x > end && e.g > kActivationThreshold && e.r == 0.0) + e = SMAASampleLevelZero(u_colorTex, texcoord).rg; + texcoord = vec2(-2.0, 0.0) * u_framebufferMetrics.xy + texcoord; + SMAALoopEnd + float offset = 3.25 - (255.0 / 127.0) * SMAASearchLength(e, 0.0); + return u_framebufferMetrics.x * offset + texcoord.x; +} + +float SMAASearchXRight(vec2 texcoord, float end) +{ + vec2 e = vec2(0.0, 1.0); + SMAALoopBegin(texcoord.x < end && e.g > kActivationThreshold && e.r == 0.0) + e = SMAASampleLevelZero(u_colorTex, texcoord).rg; + texcoord = vec2(2.0, 0.0) * u_framebufferMetrics.xy + texcoord; + SMAALoopEnd + float offset = 3.25 - (255.0 / 127.0) * SMAASearchLength(e, 0.5); + return -u_framebufferMetrics.x * offset + texcoord.x; +} + +float SMAASearchYUp(vec2 texcoord, float end) +{ + vec2 e = vec2(1.0, 0.0); + SMAALoopBegin(texcoord.y > end && e.r > kActivationThreshold && e.g == 0.0) + e = SMAASampleLevelZero(u_colorTex, texcoord).rg; + texcoord = vec2(0.0, -2.0) * u_framebufferMetrics.xy + texcoord; + SMAALoopEnd + float offset = 3.25 - (255.0 / 127.0) * SMAASearchLength(e.gr, 0.0); + return u_framebufferMetrics.y * offset + texcoord.y; +} + +float SMAASearchYDown(vec2 texcoord, float end) +{ + vec2 e = vec2(1.0, 0.0); + SMAALoopBegin(texcoord.y < end && e.r > kActivationThreshold && e.g == 0.0) + e = SMAASampleLevelZero(u_colorTex, texcoord).rg; + texcoord = vec2(0.0, 2.0) * u_framebufferMetrics.xy + texcoord; + SMAALoopEnd + float offset = 3.25 - (255.0 / 127.0) * SMAASearchLength(e.gr, 0.5); + return -u_framebufferMetrics.y * offset + texcoord.y; +} + +// Here, we have the distance and both crossing edges. So, what are the areas +// at each side of current edge? +vec2 SMAAArea(vec2 dist, float e1, float e2) +{ + // Rounding prevents precision errors of bilinear filtering. + vec2 texcoord = kAreaTexMaxDistance * SMAARound(4.0 * vec2(e1, e2)) + dist; + // We do a scale and bias for mapping to texel space. + texcoord = SMAA_AREATEX_PIXEL_SIZE * (texcoord + 0.5); + return SMAASampleLevelZero(u_smaaArea, texcoord).rg; +} + +void main() +{ + vec4 weights = vec4(0.0, 0.0, 0.0, 0.0); + vec2 e = texture2D(u_colorTex, v_coords.xy).rg; + + if (e.g > 0.0) // Edge at north + { + vec2 d; + + // Find the distance to the left. + vec3 coords; + coords.x = SMAASearchXLeft(v_offset0.xy, v_offset2.x); + coords.y = v_offset1.y; + d.x = coords.x; + + // Now fetch the left crossing edges, two at a time using bilinear + // filtering. Sampling at -0.25 enables to discern what value each edge has. + float e1 = SMAASampleLevelZero(u_colorTex, coords.xy).r; + + // Find the distance to the right. + coords.z = SMAASearchXRight(v_offset0.zw, v_offset2.y); + d.y = coords.z; + + // We want the distances to be in pixel units (doing this here allow to + // better interleave arithmetic and memory accesses). + d = abs(SMAARound(u_framebufferMetrics.zz * d - v_coords.zz)); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically. + vec2 sqrt_d = sqrt(d); + + // Fetch the right crossing edges. + float e2 = SMAASampleLevelZeroOffset(u_colorTex, coords.zy, SMAAOffset(1, 0)).r; + + // Here we know how this pattern looks like, now it is time for getting + // the actual area. + weights.rg = SMAAArea(sqrt_d, e1, e2); + } + + if (e.r > 0.0) // Edge at west + { + vec2 d; + + // Find the distance to the top. + vec3 coords; + coords.y = SMAASearchYUp(v_offset1.xy, v_offset2.z); + coords.x = v_offset0.x; + d.x = coords.y; + + // Fetch the top crossing edges. + float e1 = SMAASampleLevelZero(u_colorTex, coords.xy).g; + + // Find the distance to the bottom. + coords.z = SMAASearchYDown(v_offset1.zw, v_offset2.w); + d.y = coords.z; + + // We want the distances to be in pixel units. + d = abs(SMAARound(u_framebufferMetrics.ww * d - v_coords.ww)); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically. + vec2 sqrt_d = sqrt(d); + + // Fetch the bottom crossing edges. + float e2 = SMAASampleLevelZeroOffset(u_colorTex, coords.xz, SMAAOffset(0, 1)).g; + + // Get the area for this direction. + weights.ba = SMAAArea(sqrt_d, e1, e2); + } + + gl_FragColor = weights; +} diff --git a/drape_frontend/shaders/smaa_blending_weight.vsh.glsl b/drape_frontend/shaders/smaa_blending_weight.vsh.glsl new file mode 100644 index 0000000000..621cd2a332 --- /dev/null +++ b/drape_frontend/shaders/smaa_blending_weight.vsh.glsl @@ -0,0 +1,28 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +attribute vec2 a_pos; +attribute vec2 a_tcoord; + +uniform vec4 u_framebufferMetrics; + +varying vec4 v_coords; +varying vec4 v_offset0; +varying vec4 v_offset1; +varying vec4 v_offset2; + +// SMAA_MAX_SEARCH_STEPS specifies the maximum steps performed in the +// horizontal/vertical pattern searches, at each side of the pixel. +#define SMAA_MAX_SEARCH_STEPS 8.0 +const vec4 kMaxSearchSteps = vec4(-2.0 * SMAA_MAX_SEARCH_STEPS, 2.0 * SMAA_MAX_SEARCH_STEPS, + -2.0 * SMAA_MAX_SEARCH_STEPS, 2.0 * SMAA_MAX_SEARCH_STEPS); + +void main() +{ + v_coords = vec4(a_tcoord, a_tcoord * u_framebufferMetrics.zw); + // We will use these offsets for the searches. + v_offset0 = u_framebufferMetrics.xyxy * vec4(-0.25, -0.125, 1.25, -0.125) + a_tcoord.xyxy; + v_offset1 = u_framebufferMetrics.xyxy * vec4(-0.125, -0.25, -0.125, 1.25) + a_tcoord.xyxy; + // And these for the searches, they indicate the ends of the loops. + v_offset2 = u_framebufferMetrics.xxyy * kMaxSearchSteps + vec4(v_offset0.xz, v_offset1.yw); + gl_Position = vec4(a_pos, 0.0, 1.0); +} diff --git a/drape_frontend/shaders/smaa_edges.fsh.glsl b/drape_frontend/shaders/smaa_edges.fsh.glsl new file mode 100644 index 0000000000..69322a954d --- /dev/null +++ b/drape_frontend/shaders/smaa_edges.fsh.glsl @@ -0,0 +1,65 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +uniform sampler2D u_colorTex; + +varying vec2 v_colorTexCoords; +varying vec4 v_offset0; +varying vec4 v_offset1; +varying vec4 v_offset2; + +// SMAA_THRESHOLD specifies the threshold or sensitivity to edges. +// Lowering this value you will be able to detect more edges at the expense of +// performance. +// Range: [0, 0.5] +// 0.1 is a reasonable value, and allows to catch most visible edges. +// 0.05 is a rather overkill value, that allows to catch 'em all. +#define SMAA_THRESHOLD 0.05 +const vec2 kThreshold = vec2(SMAA_THRESHOLD, SMAA_THRESHOLD); + +// If there is an neighbor edge that has SMAA_LOCAL_CONTRAST_FACTOR times +// bigger contrast than current edge, current edge will be discarded. +// This allows to eliminate spurious crossing edges, and is based on the fact +// that, if there is too much contrast in a direction, that will hide +// perceptually contrast in the other neighbors. +#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0 + +// Standard relative luminance weights. +// https://en.wikipedia.org/wiki/Relative_luminance +const vec3 kWeights = vec3(0.2126, 0.7152, 0.0722); + +void main() +{ + // Calculate lumas. + float L = dot(texture2D(u_colorTex, v_colorTexCoords).rgb, kWeights); + float Lleft = dot(texture2D(u_colorTex, v_offset0.xy).rgb, kWeights); + float Ltop = dot(texture2D(u_colorTex, v_offset0.zw).rgb, kWeights); + + // We do the usual threshold. + vec4 delta; + delta.xy = abs(L - vec2(Lleft, Ltop)); + vec2 edges = step(kThreshold, delta.xy); + if (dot(edges, vec2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas. + float Lright = dot(texture2D(u_colorTex, v_offset1.xy).rgb, kWeights); + float Lbottom = dot(texture2D(u_colorTex, v_offset1.zw).rgb, kWeights); + delta.zw = abs(L - vec2(Lright, Lbottom)); + + // Calculate the maximum delta in the direct neighborhood. + vec2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas. + float Lleftleft = dot(texture2D(u_colorTex, v_offset2.xy).rgb, kWeights); + float Ltoptop = dot(texture2D(u_colorTex, v_offset2.zw).rgb, kWeights); + delta.zw = abs(vec2(Lleft, Ltop) - vec2(Lleftleft, Ltoptop)); + + // Calculate the final maximum delta. + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation + edges *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); + + gl_FragColor = vec4(edges, 0.0, 1.0); +} diff --git a/drape_frontend/shaders/smaa_edges.vsh.glsl b/drape_frontend/shaders/smaa_edges.vsh.glsl new file mode 100644 index 0000000000..efcd5e118d --- /dev/null +++ b/drape_frontend/shaders/smaa_edges.vsh.glsl @@ -0,0 +1,21 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +attribute vec2 a_pos; +attribute vec2 a_tcoord; + +uniform vec4 u_framebufferMetrics; + +varying vec2 v_colorTexCoords; +varying vec4 v_offset0; +varying vec4 v_offset1; +varying vec4 v_offset2; + +void main() +{ + v_colorTexCoords = a_tcoord; + v_offset0 = u_framebufferMetrics.xyxy * vec4(-1.0, 0.0, 0.0, -1.0) + a_tcoord.xyxy; + v_offset1 = u_framebufferMetrics.xyxy * vec4( 1.0, 0.0, 0.0, 1.0) + a_tcoord.xyxy; + v_offset2 = u_framebufferMetrics.xyxy * vec4(-2.0, 0.0, 0.0, -2.0) + a_tcoord.xyxy; + gl_Position = vec4(a_pos, 0.0, 1.0); +} + diff --git a/drape_frontend/shaders/smaa_final.fsh.glsl b/drape_frontend/shaders/smaa_final.fsh.glsl new file mode 100644 index 0000000000..01054dedb4 --- /dev/null +++ b/drape_frontend/shaders/smaa_final.fsh.glsl @@ -0,0 +1,51 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +uniform sampler2D u_colorTex; +uniform sampler2D u_blendingWeightTex; + +uniform vec4 u_framebufferMetrics; + +varying vec2 v_colorTexCoords; +varying vec4 v_offset; + +#ifdef GLES3 + #define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0) +#else + #define SMAASampleLevelZero(tex, coord) texture2D(tex, coord) +#endif + +void main() +{ + // Fetch the blending weights for current pixel. + vec4 a; + a.x = texture2D(u_blendingWeightTex, v_offset.xy).a; // Right + a.y = texture2D(u_blendingWeightTex, v_offset.zw).g; // Top + a.wz = texture2D(u_blendingWeightTex, v_colorTexCoords).xz; // Bottom / Left + + // Is there any blending weight with a value greater than 0.0? + if (dot(a, vec4(1.0, 1.0, 1.0, 1.0)) < 1e-5) + { + gl_FragColor = texture2D(u_colorTex, v_colorTexCoords); + } + else + { + // Calculate the blending offsets. + vec4 blendingOffset = vec4(0.0, a.y, 0.0, a.w); + vec2 blendingWeight = a.yw; + if (max(a.x, a.z) > max(a.y, a.w)) + { + blendingOffset = vec4(a.x, 0.0, a.z, 0.0); + blendingWeight = a.xz; + } + blendingWeight /= dot(blendingWeight, vec2(1.0, 1.0)); + + // Calculate the texture coordinates. + vec4 bc = blendingOffset * vec4(u_framebufferMetrics.xy, -u_framebufferMetrics.xy); + bc += v_colorTexCoords.xyxy; + + // We exploit bilinear filtering to mix current pixel with the chosen neighbor. + vec4 color = blendingWeight.x * SMAASampleLevelZero(u_colorTex, bc.xy); + color += blendingWeight.y * SMAASampleLevelZero(u_colorTex, bc.zw); + gl_FragColor = color; + } +} diff --git a/drape_frontend/shaders/smaa_final.vsh.glsl b/drape_frontend/shaders/smaa_final.vsh.glsl new file mode 100644 index 0000000000..7f872d4f1d --- /dev/null +++ b/drape_frontend/shaders/smaa_final.vsh.glsl @@ -0,0 +1,16 @@ +// Implementation of Subpixel Morphological Antialiasing (SMAA) is based on https://github.com/iryoku/smaa + +attribute vec2 a_pos; +attribute vec2 a_tcoord; + +uniform vec4 u_framebufferMetrics; + +varying vec2 v_colorTexCoords; +varying vec4 v_offset; + +void main() +{ + v_colorTexCoords = a_tcoord; + v_offset = u_framebufferMetrics.xyxy * vec4(1.0, 0.0, 0.0, 1.0) + a_tcoord.xyxy; + gl_Position = vec4(a_pos, 0.0, 1.0); +} diff --git a/geometry/rect2d.hpp b/geometry/rect2d.hpp index 4eb42e75a4..bb77e21a49 100644 --- a/geometry/rect2d.hpp +++ b/geometry/rect2d.hpp @@ -355,6 +355,17 @@ namespace m2 ); } + template + inline bool HasIntersection(m2::Rect const & rect, TCollection const & geometry) + { + for (auto const & g : geometry) + { + if (rect.IsIntersect(g)) + return true; + } + return false; + }; + template TArchive & operator >> (TArchive & ar, m2::Rect & rect) { diff --git a/indexer/map_style_reader.cpp b/indexer/map_style_reader.cpp index 68f38a7213..1ebedfaccb 100644 --- a/indexer/map_style_reader.cpp +++ b/indexer/map_style_reader.cpp @@ -1,16 +1,13 @@ #include "map_style_reader.hpp" -#include "base/logging.hpp" - #include "coding/file_name_utils.hpp" #include "platform/platform.hpp" -#include +#include "base/logging.hpp" namespace { - std::string const kSuffixDark = "_dark"; std::string const kSuffixClear = "_clear"; std::string const kSuffixVehicleDark = "_vehicle_dark"; @@ -18,7 +15,7 @@ std::string const kSuffixVehicleClear = "_vehicle_clear"; std::string const kStylesOverrideDir = "styles"; -string GetStyleRulesSuffix(MapStyle mapStyle) +std::string GetStyleRulesSuffix(MapStyle mapStyle) { switch (mapStyle) { @@ -31,7 +28,7 @@ string GetStyleRulesSuffix(MapStyle mapStyle) case MapStyleVehicleClear: return kSuffixVehicleClear; case MapStyleMerged: - return string(); + return std::string(); case MapStyleCount: break; @@ -40,7 +37,7 @@ string GetStyleRulesSuffix(MapStyle mapStyle) return kSuffixClear; } -string GetStyleResourcesSuffix(MapStyle mapStyle) +std::string GetStyleResourcesSuffix(MapStyle mapStyle) { // We use the same resources for default and vehicle styles // to avoid textures duplication and package size increasing. @@ -53,7 +50,7 @@ string GetStyleResourcesSuffix(MapStyle mapStyle) case MapStyleVehicleClear: return kSuffixClear; case MapStyleMerged: - return string(); + return std::string(); case MapStyleCount: break; @@ -61,13 +58,11 @@ string GetStyleResourcesSuffix(MapStyle mapStyle) LOG(LWARNING, ("Unknown map style", mapStyle)); return kSuffixClear; } - } // namespace StyleReader::StyleReader() : m_mapStyle(kDefaultMapStyle) -{ -} +{} void StyleReader::SetCurrentStyle(MapStyle mapStyle) { @@ -81,27 +76,37 @@ MapStyle StyleReader::GetCurrentStyle() ReaderPtr StyleReader::GetDrawingRulesReader() { - string rulesFile = string("drules_proto") + GetStyleRulesSuffix(GetCurrentStyle()) + ".bin"; + std::string rulesFile = + std::string("drules_proto") + GetStyleRulesSuffix(GetCurrentStyle()) + ".bin"; - auto overriddenRulesFile = my::JoinFoldersToPath({GetPlatform().WritableDir(), kStylesOverrideDir}, rulesFile); + auto overriddenRulesFile = + my::JoinFoldersToPath({GetPlatform().WritableDir(), kStylesOverrideDir}, rulesFile); if (GetPlatform().IsFileExistsByFullPath(overriddenRulesFile)) rulesFile = overriddenRulesFile; return GetPlatform().GetReader(rulesFile); } -ReaderPtr StyleReader::GetResourceReader(string const & file, string const & density) +ReaderPtr StyleReader::GetResourceReader(std::string const & file, + std::string const & density) { - string const resourceDir = string("resources-") + density + GetStyleResourcesSuffix(GetCurrentStyle()); - string resFile = my::JoinFoldersToPath(resourceDir, file); + std::string const resourceDir = + std::string("resources-") + density + GetStyleResourcesSuffix(GetCurrentStyle()); + std::string resFile = my::JoinFoldersToPath(resourceDir, file); - auto overriddenResFile = my::JoinFoldersToPath({GetPlatform().WritableDir(), kStylesOverrideDir}, resFile); + auto overriddenResFile = + my::JoinFoldersToPath({GetPlatform().WritableDir(), kStylesOverrideDir}, resFile); if (GetPlatform().IsFileExistsByFullPath(overriddenResFile)) resFile = overriddenResFile; return GetPlatform().GetReader(resFile); } +ReaderPtr StyleReader::GetDefaultResourceReader(std::string const & file) +{ + return GetPlatform().GetReader(my::JoinFoldersToPath("resources-default", file)); +} + StyleReader & GetStyleReader() { static StyleReader instance; diff --git a/indexer/map_style_reader.hpp b/indexer/map_style_reader.hpp index 63ff46a47a..5c488614d3 100644 --- a/indexer/map_style_reader.hpp +++ b/indexer/map_style_reader.hpp @@ -4,6 +4,8 @@ #include "map_style.hpp" +#include + class StyleReader { public: @@ -14,7 +16,8 @@ public: ReaderPtr GetDrawingRulesReader(); - ReaderPtr GetResourceReader(string const & file, string const & density); + ReaderPtr GetResourceReader(std::string const & file, std::string const & density); + ReaderPtr GetDefaultResourceReader(std::string const & file); private: MapStyle m_mapStyle; diff --git a/map/framework.cpp b/map/framework.cpp index 969cd06b19..15caf2ccab 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -3072,16 +3072,31 @@ bool Framework::ParseDrapeDebugCommand(std::string const & query) desiredStyle = MapStyleVehicleDark; else if (query == "?vlight" || query == "mapstyle:vehicle_light") desiredStyle = MapStyleVehicleClear; - else - return false; + if (desiredStyle != MapStyleCount) + { #if defined(OMIM_OS_ANDROID) - MarkMapStyle(desiredStyle); + MarkMapStyle(desiredStyle); #else - SetMapStyle(desiredStyle); + SetMapStyle(desiredStyle); #endif + return true; + } - return true; + if (query == "?aa" || query == "effect:antialiasing") + { + m_drapeEngine->SetPosteffectEnabled(df::PostprocessRenderer::Antialiasing, + true /* enabled */); + return true; + } + else if (query == "?no-aa" || query == "effect:no-antialiasing") + { + m_drapeEngine->SetPosteffectEnabled(df::PostprocessRenderer::Antialiasing, + false /* enabled */); + return true; + } + + return false; } bool Framework::ParseEditorDebugCommand(search::SearchParams const & params) diff --git a/qt/qt_common/map_widget.cpp b/qt/qt_common/map_widget.cpp index 4af959574b..bd2746a890 100644 --- a/qt/qt_common/map_widget.cpp +++ b/qt/qt_common/map_widget.cpp @@ -21,6 +21,8 @@ namespace qt { namespace common { +//#define ENABLE_AA_SWITCH + MapWidget::MapWidget(Framework & framework, bool apiOpenGLES3, QWidget * parent) : QOpenGLWidget(parent) , m_framework(framework) @@ -54,6 +56,11 @@ void MapWidget::BindHotkeys(QWidget & parent) {Qt::Key_Minus, SLOT(ScaleMinus())}, {Qt::ALT + Qt::Key_Equal, SLOT(ScalePlusLight())}, {Qt::ALT + Qt::Key_Minus, SLOT(ScaleMinusLight())}, + {Qt::ALT + Qt::Key_Minus, SLOT(ScaleMinusLight())}, +#ifdef ENABLE_AA_SWITCH + {Qt::ALT + Qt::Key_A, SLOT(AntialiasingOn())}, + {Qt::ALT + Qt::Key_S, SLOT(AntialiasingOff())}, +#endif }; for (auto const & hotkey : hotkeys) @@ -104,6 +111,20 @@ void MapWidget::ScalePlusLight() { m_framework.Scale(Framework::SCALE_MAG_LIGHT, void MapWidget::ScaleMinusLight() { m_framework.Scale(Framework::SCALE_MIN_LIGHT, true); } +void MapWidget::AntialiasingOn() +{ + auto engine = m_framework.GetDrapeEngine(); + if (engine != nullptr) + engine->SetPosteffectEnabled(df::PostprocessRenderer::Antialiasing, true); +} + +void MapWidget::AntialiasingOff() +{ + auto engine = m_framework.GetDrapeEngine(); + if (engine != nullptr) + engine->SetPosteffectEnabled(df::PostprocessRenderer::Antialiasing, false); +} + void MapWidget::ScaleChanged(int action) { if (!m_slider) diff --git a/qt/qt_common/map_widget.hpp b/qt/qt_common/map_widget.hpp index ce37dcf09e..4956b592a8 100644 --- a/qt/qt_common/map_widget.hpp +++ b/qt/qt_common/map_widget.hpp @@ -46,6 +46,9 @@ public Q_SLOTS: void SliderPressed(); void SliderReleased(); + void AntialiasingOn(); + void AntialiasingOff(); + public: Q_SIGNAL void BeforeEngineCreation(); diff --git a/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj b/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj index 40fb7faddc..bd30acd56a 100644 --- a/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj +++ b/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj @@ -45,6 +45,8 @@ 454C19BD1CCE3EC0002A2C86 /* animation_system.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 454C19BA1CCE3EC0002A2C86 /* animation_system.hpp */; }; 45580ABA1E28DB2600CD535D /* scenario_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45580AB81E28DB2600CD535D /* scenario_manager.cpp */; }; 45580ABB1E28DB2600CD535D /* scenario_manager.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 45580AB91E28DB2600CD535D /* scenario_manager.hpp */; }; + 456B3F991ED464FE009B3D1F /* postprocess_renderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 456B3F971ED464FE009B3D1F /* postprocess_renderer.cpp */; }; + 456B3F9A1ED464FE009B3D1F /* postprocess_renderer.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 456B3F981ED464FE009B3D1F /* postprocess_renderer.hpp */; }; 457D89251E7AE89500049500 /* custom_symbol.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 457D89241E7AE89500049500 /* custom_symbol.hpp */; }; 45B4B8CB1CF5C16B00A54761 /* screen_animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45B4B8C71CF5C16B00A54761 /* screen_animations.cpp */; }; 45B4B8CC1CF5C16B00A54761 /* screen_animations.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 45B4B8C81CF5C16B00A54761 /* screen_animations.hpp */; }; @@ -275,6 +277,8 @@ 45580AB81E28DB2600CD535D /* scenario_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scenario_manager.cpp; sourceTree = ""; }; 45580AB91E28DB2600CD535D /* scenario_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = scenario_manager.hpp; sourceTree = ""; }; 4560692B1EB9F9D2009AB7B7 /* shaders_lib.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = shaders_lib.glsl; path = shaders/shaders_lib.glsl; sourceTree = ""; }; + 456B3F971ED464FE009B3D1F /* postprocess_renderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = postprocess_renderer.cpp; sourceTree = ""; }; + 456B3F981ED464FE009B3D1F /* postprocess_renderer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = postprocess_renderer.hpp; sourceTree = ""; }; 457D89241E7AE89500049500 /* custom_symbol.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = custom_symbol.hpp; sourceTree = ""; }; 45B4B8C71CF5C16B00A54761 /* screen_animations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = screen_animations.cpp; sourceTree = ""; }; 45B4B8C81CF5C16B00A54761 /* screen_animations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = screen_animations.hpp; sourceTree = ""; }; @@ -605,6 +609,8 @@ 670947411BDF9B99005014C0 /* drape_frontend */ = { isa = PBXGroup; children = ( + 456B3F971ED464FE009B3D1F /* postprocess_renderer.cpp */, + 456B3F981ED464FE009B3D1F /* postprocess_renderer.hpp */, 45BB025B1EB8BE5200FE5C0C /* shader_def.cpp */, 45BB025C1EB8BE5200FE5C0C /* shader_def.hpp */, 45BB02221EB8BE1400FE5C0C /* shaders */, @@ -859,6 +865,7 @@ 6709486A1BDF9C7F005014C0 /* brush_info.hpp in Headers */, 675D218E1BFB871D00717E4F /* rect.h in Headers */, 670948191BDF9C39005014C0 /* interpolations.hpp in Headers */, + 456B3F9A1ED464FE009B3D1F /* postprocess_renderer.hpp in Headers */, 670947CB1BDF9BE1005014C0 /* threads_commutator.hpp in Headers */, 347F52121DC2334A0064B273 /* drape_api.hpp in Headers */, 670948701BDF9C7F005014C0 /* feature_processor.hpp in Headers */, @@ -1106,6 +1113,7 @@ 347F52111DC2334A0064B273 /* drape_api.cpp in Sources */, 347F520F1DC2334A0064B273 /* drape_api_renderer.cpp in Sources */, 347F520D1DC2334A0064B273 /* drape_api_builder.cpp in Sources */, + 456B3F991ED464FE009B3D1F /* postprocess_renderer.cpp in Sources */, 670947CA1BDF9BE1005014C0 /* threads_commutator.cpp in Sources */, 670947981BDF9BE1005014C0 /* map_data_provider.cpp in Sources */, 670948181BDF9C39005014C0 /* interpolations.cpp in Sources */,