From c6661f145b593f11c6b20df8fffaaf3d21715834 Mon Sep 17 00:00:00 2001 From: renderexpert Date: Fri, 10 Jan 2025 20:06:17 +0000 Subject: [PATCH] Add support for injection external rendering code to the Drape Signed-off-by: renderexpert --- drape/CMakeLists.txt | 4 + drape/drape_global.hpp | 16 +- drape/drape_routine.hpp | 13 +- .../drape_tests/testing_graphics_context.hpp | 2 + drape/glsl_types.hpp | 4 + drape/graphics_context.hpp | 2 + drape/mesh_object.cpp | 189 ++++++++++----- drape/mesh_object.hpp | 117 +++++++-- drape/metal/metal_base_context.hpp | 7 +- drape/metal/metal_base_context.mm | 33 +++ drape/metal/metal_gpu_buffer_impl.hpp | 1 + drape/metal/metal_mesh_object_impl.mm | 70 +++++- drape/oglcontext.cpp | 13 + drape/oglcontext.hpp | 3 + drape/static_texture.cpp | 3 + drape/static_texture.hpp | 2 + drape/texture_manager.cpp | 5 + drape/texture_manager.hpp | 2 + drape/vulkan/vulkan_base_context.cpp | 42 +++- drape/vulkan/vulkan_base_context.hpp | 3 + drape/vulkan/vulkan_layers.cpp | 16 +- drape/vulkan/vulkan_mesh_object_impl.cpp | 224 ++++++++++++------ drape/vulkan/vulkan_object_manager.cpp | 7 +- drape/vulkan/vulkan_pipeline.cpp | 8 +- drape/vulkan/vulkan_pipeline.hpp | 1 + drape/vulkan/vulkan_texture.hpp | 1 + drape/vulkan/vulkan_utils.cpp | 41 +++- drape/vulkan/vulkan_utils.hpp | 27 +++ drape_frontend/arrow3d.cpp | 4 +- drape_frontend/debug_rect_renderer.cpp | 12 +- drape_frontend/drape_engine.cpp | 8 +- drape_frontend/drape_engine.hpp | 7 +- .../user_event_stream_tests.cpp | 4 +- drape_frontend/frontend_renderer.cpp | 20 +- drape_frontend/frontend_renderer.hpp | 10 +- drape_frontend/user_event_stream.cpp | 10 +- drape_frontend/user_event_stream.hpp | 14 +- map/framework.cpp | 9 +- map/framework.hpp | 3 + shaders/CMakeLists.txt | 7 +- 40 files changed, 751 insertions(+), 213 deletions(-) diff --git a/drape/CMakeLists.txt b/drape/CMakeLists.txt index 945fe08f99..1501dbf5c0 100644 --- a/drape/CMakeLists.txt +++ b/drape/CMakeLists.txt @@ -170,6 +170,10 @@ if (PLATFORM_LINUX) find_package(OpenGL) endif() +if (PLATFORM_MAC) + set_target_properties(${PROJECT_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) +endif() + set(DRAPE_LINK_LIBRARIES indexer platform diff --git a/drape/drape_global.hpp b/drape/drape_global.hpp index 68cb3d3b4d..d0f449483b 100644 --- a/drape/drape_global.hpp +++ b/drape/drape_global.hpp @@ -1,6 +1,7 @@ #pragma once #include "drape/color.hpp" +#include "drape/pointers.hpp" #include "geometry/point2d.hpp" @@ -9,11 +10,17 @@ #include "std/target_os.hpp" #include +#include -#if defined(__APPLE__) && !defined(OMIM_OS_MAC) +#if defined(__APPLE__) #define OMIM_METAL_AVAILABLE #endif +namespace gpu +{ +class ProgramManager; +} // namespace gpu + namespace dp { enum class ApiVersion @@ -130,4 +137,11 @@ inline dp::ApiVersion ApiVersionFromString(std::string const & str) return dp::ApiVersion::OpenGLES3; #endif } + +class GraphicsContext; +class TextureManager; +using RenderInjectionHandler = std::function, + ref_ptr, + ref_ptr, + bool shutdown)>; } // namespace dp diff --git a/drape/drape_routine.hpp b/drape/drape_routine.hpp index 927d561b43..c4a49d5d20 100644 --- a/drape/drape_routine.hpp +++ b/drape/drape_routine.hpp @@ -48,7 +48,7 @@ public: static void Init() { - Instance(); + Instance(true /* reinitialize*/); } static void Shutdown() @@ -106,10 +106,15 @@ public: } private: - static DrapeRoutine & Instance() + static DrapeRoutine & Instance(bool reinitialize = false) { - static DrapeRoutine instance; - return instance; + static std::unique_ptr instance; + if (!instance || reinitialize) { + if (instance) + instance->FinishAll(); + instance = std::unique_ptr(new DrapeRoutine()); + } + return *instance; } DrapeRoutine() : m_workerThread(4 /* threads count */) {} diff --git a/drape/drape_tests/testing_graphics_context.hpp b/drape/drape_tests/testing_graphics_context.hpp index 7270f02086..95b9580c3c 100644 --- a/drape/drape_tests/testing_graphics_context.hpp +++ b/drape/drape_tests/testing_graphics_context.hpp @@ -27,6 +27,7 @@ public: void Clear(uint32_t clearBits, uint32_t storeBits) override {} void Flush() override {} void SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override {} + void SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override {} void SetDepthTestEnabled(bool enabled) override {} void SetDepthTestFunction(dp::TestFunction depthFunction) override {} void SetStencilTestEnabled(bool enabled) override {} @@ -34,6 +35,7 @@ public: void SetStencilActions(dp::StencilFace face, dp::StencilAction stencilFailAction, dp::StencilAction depthFailAction, dp::StencilAction passAction) override {} void SetStencilReferenceValue(uint32_t stencilReferenceValue) override {} + void SetCullingEnabled(bool enabled) override {} private: dp::ApiVersion m_apiVersion = dp::ApiVersion::OpenGLES2; diff --git a/drape/glsl_types.hpp b/drape/glsl_types.hpp index d2ba26e82a..2a8a58a865 100644 --- a/drape/glsl_types.hpp +++ b/drape/glsl_types.hpp @@ -29,6 +29,10 @@ using glm::ivec2; using glm::ivec3; using glm::ivec4; +using glm::uvec2; +using glm::uvec3; +using glm::uvec4; + using glm::mat3; using glm::mat4; using glm::mat4x2; diff --git a/drape/graphics_context.hpp b/drape/graphics_context.hpp index 56e30bec99..0215a49cce 100644 --- a/drape/graphics_context.hpp +++ b/drape/graphics_context.hpp @@ -81,6 +81,7 @@ public: virtual void Clear(uint32_t clearBits, uint32_t storeBits) = 0; virtual void Flush() = 0; virtual void SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; + virtual void SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; virtual void SetDepthTestEnabled(bool enabled) = 0; virtual void SetDepthTestFunction(TestFunction depthFunction) = 0; virtual void SetStencilTestEnabled(bool enabled) = 0; @@ -88,5 +89,6 @@ public: virtual void SetStencilActions(StencilFace face, StencilAction stencilFailAction, StencilAction depthFailAction, StencilAction passAction) = 0; virtual void SetStencilReferenceValue(uint32_t stencilReferenceValue) = 0; + virtual void SetCullingEnabled(bool enabled) = 0; }; } // namespace dp diff --git a/drape/mesh_object.cpp b/drape/mesh_object.cpp index 268d793535..525c31b0cb 100644 --- a/drape/mesh_object.cpp +++ b/drape/mesh_object.cpp @@ -46,27 +46,35 @@ public: for (auto & buffer : m_mesh->m_buffers) { - buffer.m_bufferId = GLFunctions::glGenBuffer(); - GLFunctions::glBindBuffer(buffer.m_bufferId, gl_const::GLArrayBuffer); + buffer->m_bufferId = GLFunctions::glGenBuffer(); + GLFunctions::glBindBuffer(buffer->m_bufferId, gl_const::GLArrayBuffer); - if (!buffer.m_data.empty()) + if (buffer->GetSizeInBytes() != 0) { - GLFunctions::glBufferData(gl_const::GLArrayBuffer, - static_cast(buffer.m_data.size()) * sizeof(buffer.m_data[0]), - buffer.m_data.data(), gl_const::GLStaticDraw); + GLFunctions::glBufferData(gl_const::GLArrayBuffer, buffer->GetSizeInBytes(), + buffer->GetData(), gl_const::GLStaticDraw); + } + + if (!m_mesh->m_indices.empty()) + { + m_indexBuffer = GLFunctions::glGenBuffer(); + GLFunctions::glBindBuffer(m_indexBuffer, gl_const::GLElementArrayBuffer); + GLFunctions::glBufferData(gl_const::GLElementArrayBuffer, + m_mesh->m_indices.size() * sizeof(uint16_t), + m_mesh->m_indices.data(), gl_const::GLStaticDraw); } if (isVAOSupported) { ref_ptr p = program; - for (auto const & attribute : buffer.m_attributes) + for (auto const & attribute : buffer->m_attributes) { int8_t const attributePosition = p->GetAttributeLocation(attribute.m_attributeName); ASSERT_NOT_EQUAL(attributePosition, -1, ()); GLFunctions::glEnableVertexAttribute(attributePosition); GLFunctions::glVertexAttributePointer(attributePosition, attribute.m_componentsCount, - gl_const::GLFloatType, false, - buffer.m_stride, attribute.m_offset); + attribute.m_type, false, buffer->GetStrideInBytes(), + attribute.m_offset); } } } @@ -74,36 +82,56 @@ public: if (isVAOSupported) GLFunctions::glBindVertexArray(0); GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); + if (!m_mesh->m_indices.empty()) + GLFunctions::glBindBuffer(0, gl_const::GLElementArrayBuffer); } void Reset() override { for (auto & buffer : m_mesh->m_buffers) { - if (buffer.m_bufferId != 0) + if (buffer->m_bufferId != 0) { - GLFunctions::glDeleteBuffer(buffer.m_bufferId); - buffer.m_bufferId = 0; + GLFunctions::glDeleteBuffer(buffer->m_bufferId); + buffer->m_bufferId = 0; } } - if (m_VAO != 0) - GLFunctions::glDeleteVertexArray(m_VAO); + if (m_indexBuffer != 0) + { + GLFunctions::glDeleteBuffer(m_indexBuffer); + m_indexBuffer = 0; + } - m_VAO = 0; + if (m_VAO != 0) + { + GLFunctions::glDeleteVertexArray(m_VAO); + m_VAO = 0; + } } void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override { UNUSED_VALUE(context); auto & buffer = m_mesh->m_buffers[bufferInd]; - GLFunctions::glBindBuffer(buffer.m_bufferId, gl_const::GLArrayBuffer); - GLFunctions::glBufferData(gl_const::GLArrayBuffer, - static_cast(buffer.m_data.size()) * sizeof(buffer.m_data[0]), - buffer.m_data.data(), gl_const::GLStaticDraw); + GLFunctions::glBindBuffer(buffer->m_bufferId, gl_const::GLArrayBuffer); + GLFunctions::glBufferData(gl_const::GLArrayBuffer, buffer->GetSizeInBytes(), + buffer->GetData(), gl_const::GLStaticDraw); GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); } + void UpdateIndexBuffer(ref_ptr context) override + { + UNUSED_VALUE(context); + CHECK(!m_mesh->m_indices.empty(), ()); + CHECK(m_indexBuffer, ("Index buffer was not created")); + GLFunctions::glBindBuffer(m_indexBuffer, gl_const::GLElementArrayBuffer); + GLFunctions::glBufferData(gl_const::GLElementArrayBuffer, + m_mesh->m_indices.size() * sizeof(uint16_t), + m_mesh->m_indices.data(), gl_const::GLStaticDraw); + GLFunctions::glBindBuffer(0, gl_const::GLElementArrayBuffer); + } + void Bind(ref_ptr program) override { if (GLFunctions::ExtensionsList.IsSupported(dp::GLExtensionsList::VertexArrayObject)) @@ -115,15 +143,17 @@ public: ref_ptr p = program; for (auto const & buffer : m_mesh->m_buffers) { - GLFunctions::glBindBuffer(buffer.m_bufferId, gl_const::GLArrayBuffer); - for (auto const & attribute : buffer.m_attributes) + GLFunctions::glBindBuffer(buffer->m_bufferId, gl_const::GLArrayBuffer); + if (m_indexBuffer != 0) + GLFunctions::glBindBuffer(m_indexBuffer, gl_const::GLElementArrayBuffer); + for (auto const & attribute : buffer->m_attributes) { int8_t const attributePosition = p->GetAttributeLocation(attribute.m_attributeName); ASSERT_NOT_EQUAL(attributePosition, -1, ()); GLFunctions::glEnableVertexAttribute(attributePosition); GLFunctions::glVertexAttributePointer(attributePosition, attribute.m_componentsCount, - gl_const::GLFloatType, false, - buffer.m_stride, attribute.m_offset); + attribute.m_type, false, buffer->GetStrideInBytes(), + attribute.m_offset); } } } @@ -133,22 +163,38 @@ public: if (GLFunctions::ExtensionsList.IsSupported(dp::GLExtensionsList::VertexArrayObject)) GLFunctions::glBindVertexArray(0); GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); + if (m_indexBuffer != 0) + GLFunctions::glBindBuffer(0, gl_const::GLElementArrayBuffer); } - void DrawPrimitives(ref_ptr context, uint32_t verticesCount) override + void DrawPrimitives(ref_ptr context, uint32_t verticesCount, + uint32_t startVertex) override { UNUSED_VALUE(context); + GLFunctions::glDrawArrays(GetGLDrawPrimitive(m_mesh->m_drawPrimitive), + static_cast(startVertex), + verticesCount); + } - GLFunctions::glDrawArrays(GetGLDrawPrimitive(m_mesh->m_drawPrimitive), 0, verticesCount); + void DrawPrimitivesIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex) override + { + UNUSED_VALUE(context); + CHECK(m_indexBuffer != 0, ()); + GLFunctions::glDrawElements(GetGLDrawPrimitive(m_mesh->m_drawPrimitive), sizeof(uint16_t), + indexCount, startIndex); } private: ref_ptr m_mesh; uint32_t m_VAO = 0; + uint32_t m_indexBuffer = 0; }; -MeshObject::MeshObject(ref_ptr context, DrawPrimitive drawPrimitive) +MeshObject::MeshObject(ref_ptr context, DrawPrimitive drawPrimitive, + std::string const & debugName) : m_drawPrimitive(drawPrimitive) + , m_debugName(debugName) { auto const apiVersion = context->GetApiVersion(); if (apiVersion == dp::ApiVersion::OpenGLES2 || apiVersion == dp::ApiVersion::OpenGLES3) @@ -178,23 +224,12 @@ void MeshObject::InitForOpenGL() m_impl = make_unique_dp(make_ref(this)); } -void MeshObject::SetBuffer(uint32_t bufferInd, std::vector && vertices, uint32_t stride) -{ - CHECK_LESS_OR_EQUAL(bufferInd, GetNextBufferIndex(), ()); - - if (bufferInd == GetNextBufferIndex()) - m_buffers.emplace_back(std::move(vertices), stride); - else - m_buffers[bufferInd] = VertexBuffer(std::move(vertices), stride); - - Reset(); -} - void MeshObject::SetAttribute(std::string const & attributeName, uint32_t bufferInd, uint32_t offset, - uint32_t componentsCount) + uint32_t componentsCount, glConst type) { CHECK_LESS(bufferInd, m_buffers.size(), ()); - m_buffers[bufferInd].m_attributes.emplace_back(attributeName, offset, componentsCount); + CHECK(m_buffers[bufferInd], ()); + m_buffers[bufferInd]->m_attributes.emplace_back(attributeName, offset, componentsCount, type); Reset(); } @@ -207,20 +242,6 @@ void MeshObject::Reset() m_initialized = false; } -void MeshObject::UpdateBuffer(ref_ptr context, uint32_t bufferInd, - std::vector && vertices) -{ - CHECK(m_initialized, ()); - CHECK_LESS(bufferInd, static_cast(m_buffers.size()), ()); - CHECK(!vertices.empty(), ()); - - auto & buffer = m_buffers[bufferInd]; - buffer.m_data = std::move(vertices); - - CHECK(m_impl != nullptr, ()); - m_impl->UpdateBuffer(context, bufferInd); -} - void MeshObject::Build(ref_ptr context, ref_ptr program) { Reset(); @@ -242,24 +263,66 @@ void MeshObject::Bind(ref_ptr context, ref_ptrBind(program); } +void MeshObject::SetIndexBuffer(std::vector && indices) +{ + m_indices = std::move(indices); + Reset(); +} + +void MeshObject::UpdateIndexBuffer(ref_ptr context, std::vector const & indices) +{ + CHECK(!indices.empty(), ("Use SetIndexBuffer() to reset index buffer")); + CHECK_LESS_OR_EQUAL(indices.size(), m_indices.size(), ()); + memcpy(m_indices.data(), indices.data(), indices.size() * sizeof(uint16_t)); + + CHECK(m_impl != nullptr, ()); + m_impl->UpdateIndexBuffer(context); +} + +void MeshObject::DrawPrimitivesSubset(ref_ptr context, uint32_t vertexCount, + uint32_t startVertex) +{ + CHECK(m_impl != nullptr, ()); + CHECK(!m_buffers.empty(), ()); + auto const & buffer = m_buffers[0]; + auto const vertexNum = buffer->GetSizeInBytes() / buffer->GetStrideInBytes(); + CHECK_LESS(startVertex, vertexNum, ()); + CHECK_LESS_OR_EQUAL(startVertex + vertexCount, vertexNum, ()); + + m_impl->DrawPrimitives(context, vertexCount, startVertex); +} + +void MeshObject::DrawPrimitivesSubsetIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex) +{ + CHECK(m_impl != nullptr, ()); + CHECK(!m_indices.empty(), ()); + CHECK_LESS(startIndex, m_indices.size(), ()); + CHECK_LESS_OR_EQUAL(startIndex + indexCount, m_indices.size(), ()); + + m_impl->DrawPrimitivesIndexed(context, indexCount, startIndex); +} + void MeshObject::DrawPrimitives(ref_ptr context) { if (m_buffers.empty()) return; auto const & buffer = m_buffers[0]; + auto const vertexNum = buffer->GetSizeInBytes() / buffer->GetStrideInBytes(); #ifdef DEBUG for (size_t i = 1; i < m_buffers.size(); i++) { - ASSERT_EQUAL(m_buffers[i].m_data.size() / m_buffers[i].m_stride, - buffer.m_data.size() / buffer.m_stride, ()); + ASSERT_EQUAL(m_buffers[i]->GetSizeInBytes() / m_buffers[i]->GetStrideInBytes(), vertexNum, + ("All buffers in a mesh must contain the same vertex number")); } #endif - auto const verticesCount = - static_cast(buffer.m_data.size() * sizeof(buffer.m_data[0]) / buffer.m_stride); - + CHECK(m_impl != nullptr, ()); - m_impl->DrawPrimitives(context, verticesCount); + if (m_indices.empty()) + m_impl->DrawPrimitives(context, vertexNum, 0); + else + m_impl->DrawPrimitivesIndexed(context, static_cast(m_indices.size()), 0); } void MeshObject::Unbind(ref_ptr program) @@ -270,6 +333,12 @@ void MeshObject::Unbind(ref_ptr program) m_impl->Unbind(); } +void MeshObject::UpdateImpl(ref_ptr context, uint32_t bufferInd) +{ + CHECK(m_impl != nullptr, ()); + m_impl->UpdateBuffer(context, bufferInd); +} + // static std::vector MeshObject::GenerateNormalsForTriangles(std::vector const & vertices, size_t componentsCount) diff --git a/drape/mesh_object.hpp b/drape/mesh_object.hpp index 8fdd1fb5e3..7483a556cd 100644 --- a/drape/mesh_object.hpp +++ b/drape/mesh_object.hpp @@ -5,6 +5,7 @@ #include "drape/pointers.hpp" #include "drape/render_state.hpp" +#include #include #include #include @@ -42,13 +43,42 @@ public: LineStrip }; - MeshObject(ref_ptr context, DrawPrimitive drawPrimitive); + MeshObject(ref_ptr context, DrawPrimitive drawPrimitive, + std::string const & debugName = ""); virtual ~MeshObject(); - void SetBuffer(uint32_t bufferInd, std::vector && vertices, uint32_t stride); - void SetAttribute(std::string const & attributeName, uint32_t bufferInd, uint32_t offset, uint32_t componentsCount); + template + void SetBuffer(uint32_t bufferInd, std::vector && vertices, uint32_t stride = 0) + { + CHECK_LESS_OR_EQUAL(bufferInd, GetNextBufferIndex(), ()); - void UpdateBuffer(ref_ptr context, uint32_t bufferInd, std::vector && vertices); + if (bufferInd == GetNextBufferIndex()) + m_buffers.emplace_back(make_unique_dp>(std::move(vertices), stride)); + else + m_buffers[bufferInd] = make_unique_dp>(std::move(vertices), stride); + + Reset(); + } + + void SetAttribute(std::string const & attributeName, uint32_t bufferInd, uint32_t offset, + uint32_t componentsCount, glConst type = gl_const::GLFloatType); + + template + void UpdateBuffer(ref_ptr context, uint32_t bufferInd, std::vector const & vertices) + { + CHECK(m_initialized, ()); + CHECK_LESS(bufferInd, static_cast(m_buffers.size()), ()); + CHECK(!vertices.empty(), ()); + + auto & buffer = m_buffers[bufferInd]; + CHECK_LESS_OR_EQUAL(static_cast(vertices.size() * sizeof(T)), buffer->GetSizeInBytes(), ()); + memcpy(buffer->GetData(), vertices.data(), vertices.size() * sizeof(T)); + + UpdateImpl(context, bufferInd); + } + + void SetIndexBuffer(std::vector && indices); + void UpdateIndexBuffer(ref_ptr context, std::vector const & indices); template void Render(ref_ptr context, ref_ptr program, @@ -65,12 +95,34 @@ public: Unbind(program); } + template + void Render(ref_ptr context, ref_ptr program, + dp::RenderState const & state, ref_ptr paramsSetter, + TParams const & params, std::function && drawCallback) + { + Bind(context, program); + + ApplyState(context, program, state); + paramsSetter->Apply(context, program, params); + + CHECK(drawCallback, ()); + drawCallback(); + + Unbind(program); + } + uint32_t GetNextBufferIndex() const { return static_cast(m_buffers.size()); } bool IsInitialized() const { return m_initialized; } void Build(ref_ptr context, ref_ptr program); void Reset(); + // Should be called inside draw callback in Render() method + void DrawPrimitivesSubset(ref_ptr context, uint32_t vertexCount, + uint32_t startVertex); + void DrawPrimitivesSubsetIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex); + static std::vector GenerateNormalsForTriangles(std::vector const & vertices, size_t componentsCount); private: @@ -78,31 +130,51 @@ private: { AttributeMapping() = default; - AttributeMapping(std::string const & attributeName, uint32_t offset, uint32_t componentsCount) - : m_offset(offset) + AttributeMapping(std::string const & attributeName, uint32_t offset, uint32_t componentsCount, + glConst type = gl_const::GLFloatType) + : m_attributeName(attributeName) + , m_offset(offset) , m_componentsCount(componentsCount) - , m_attributeName(attributeName) + , m_type(type) {} + std::string m_attributeName; uint32_t m_offset = 0; uint32_t m_componentsCount = 0; - std::string m_attributeName; + glConst m_type = gl_const::GLFloatType; }; - struct VertexBuffer + class VertexBufferBase { + public: + virtual ~VertexBufferBase() = default; + virtual void * GetData() = 0; + virtual uint32_t GetSizeInBytes() const = 0; + virtual uint32_t GetStrideInBytes() const = 0; + + uint32_t m_bufferId = 0; + std::vector m_attributes; + }; + + template + class VertexBuffer : public VertexBufferBase { + public: VertexBuffer() = default; - VertexBuffer(std::vector && data, uint32_t stride) + VertexBuffer(std::vector && data, uint32_t stride = 0) : m_data(std::move(data)) - , m_stride(stride) - {} + , m_stride(stride == 0 ? sizeof(T) : stride) + { + CHECK_GREATER_OR_EQUAL(m_stride, sizeof(T), ()); + } - std::vector m_data; + void * GetData() override { return m_data.data(); } + uint32_t GetSizeInBytes() const override { return static_cast(m_data.size() * sizeof(T)); } + uint32_t GetStrideInBytes() const override { return m_stride; } + + private: + std::vector m_data; uint32_t m_stride = 0; - uint32_t m_bufferId = 0; - - std::vector m_attributes; }; void InitForOpenGL(); @@ -113,15 +185,20 @@ private: void InitForMetal(); #endif + void UpdateImpl(ref_ptr context, uint32_t bufferInd); + void Bind(ref_ptr context, ref_ptr program); void Unbind(ref_ptr program); void DrawPrimitives(ref_ptr context); - std::vector m_buffers; + std::vector> m_buffers; + std::vector m_indices; DrawPrimitive m_drawPrimitive = DrawPrimitive::Triangles; drape_ptr m_impl; bool m_initialized = false; + + std::string m_debugName; }; class MeshObjectImpl @@ -131,8 +208,12 @@ public: virtual void Build(ref_ptr context, ref_ptr program) = 0; virtual void Reset() = 0; virtual void UpdateBuffer(ref_ptr context, uint32_t bufferInd) = 0; + virtual void UpdateIndexBuffer(ref_ptr context) = 0; virtual void Bind(ref_ptr program) = 0; virtual void Unbind() = 0; - virtual void DrawPrimitives(ref_ptr context, uint32_t verticesCount) = 0; + virtual void DrawPrimitives(ref_ptr context, uint32_t verticesCount, + uint32_t startVertex) = 0; + virtual void DrawPrimitivesIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex) = 0; }; } // namespace dp diff --git a/drape/metal/metal_base_context.hpp b/drape/metal/metal_base_context.hpp index 5137631af7..fead43e830 100644 --- a/drape/metal/metal_base_context.hpp +++ b/drape/metal/metal_base_context.hpp @@ -49,6 +49,7 @@ public: void Clear(uint32_t clearBits, uint32_t storeBits) override; void Flush() override {} void SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; + void SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; void SetDepthTestEnabled(bool enabled) override; void SetDepthTestFunction(TestFunction depthFunction) override; void SetStencilTestEnabled(bool enabled) override; @@ -56,8 +57,10 @@ public: void SetStencilActions(StencilFace face, StencilAction stencilFailAction, StencilAction depthFailAction, StencilAction passAction) override; void SetStencilReferenceValue(uint32_t stencilReferenceValue) override { m_stencilReferenceValue = stencilReferenceValue; } - + void SetCullingEnabled(bool enabled) override; + id GetMetalDevice() const; + id GetCommandBuffer() const; id GetCommandEncoder() const; id GetDepthStencilState(); id GetPipelineState(ref_ptr program, bool blendingEnabled); @@ -71,6 +74,8 @@ public: void ApplyPipelineState(id state); bool HasAppliedPipelineState() const; void ResetPipelineStatesCache(); + + MTLRenderPassDescriptor * GetRenderPassDescriptor() const; protected: void RecreateDepthTexture(m2::PointU const & screenSize); diff --git a/drape/metal/metal_base_context.mm b/drape/metal/metal_base_context.mm index 5ed21aac01..25d4dee86b 100644 --- a/drape/metal/metal_base_context.mm +++ b/drape/metal/metal_base_context.mm @@ -265,6 +265,22 @@ void MetalBaseContext::SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t [encoder setScissorRect:(MTLScissorRect){ x, y, w, h }]; } +void MetalBaseContext::SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + id encoder = GetCommandEncoder(); + if (m_renderPassDescriptor.colorAttachments[0].texture != nil) + { + uint32_t const rpWidth = m_renderPassDescriptor.colorAttachments[0].texture.width; + uint32_t const rpHeight = m_renderPassDescriptor.colorAttachments[0].texture.height; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x + w > rpWidth) w = rpWidth - x; + if (y + h > rpHeight) h = rpHeight - y; + + [encoder setScissorRect:(MTLScissorRect){ x, y, w, h }]; + } +} + void MetalBaseContext::SetDepthTestEnabled(bool enabled) { m_currentDepthStencilKey.m_depthEnabled = enabled; @@ -292,6 +308,12 @@ void MetalBaseContext::SetStencilActions(dp::StencilFace face, { m_currentDepthStencilKey.SetStencilActions(face, stencilFailAction, depthFailAction, passAction); } + +void MetalBaseContext::SetCullingEnabled(bool enabled) +{ + id encoder = GetCommandEncoder(); + [encoder setCullMode: (enabled ? MTLCullModeBack : MTLCullModeNone)]; +} id MetalBaseContext::GetMetalDevice() const { @@ -303,6 +325,12 @@ id MetalBaseContext::GetCommandEncoder() const CHECK(m_currentCommandEncoder != nil, ("Probably encoding commands were called before ApplyFramebuffer.")); return m_currentCommandEncoder; } + +id MetalBaseContext::GetCommandBuffer() const +{ + CHECK(m_frameCommandBuffer != nil, ("Probably encoding commands were called before ApplyFramebuffer.")); + return m_frameCommandBuffer; +} id MetalBaseContext::GetDepthStencilState() { @@ -415,6 +443,11 @@ void MetalBaseContext::DebugSynchronizeWithCPU() [m_frameCommandBuffer waitUntilCompleted]; m_frameCommandBuffer = nil; } + +MTLRenderPassDescriptor * MetalBaseContext::GetRenderPassDescriptor() const +{ + return m_renderPassDescriptor; +} } // namespace metal void RenderFrameMediator(std::function && renderFrameFunction) diff --git a/drape/metal/metal_gpu_buffer_impl.hpp b/drape/metal/metal_gpu_buffer_impl.hpp index 72fe6ddb4b..6b961afc5c 100644 --- a/drape/metal/metal_gpu_buffer_impl.hpp +++ b/drape/metal/metal_gpu_buffer_impl.hpp @@ -1,3 +1,4 @@ +#pragma once #import #include "drape/data_buffer.hpp" diff --git a/drape/metal/metal_mesh_object_impl.mm b/drape/metal/metal_mesh_object_impl.mm index 377838ce54..6c15da0564 100644 --- a/drape/metal/metal_mesh_object_impl.mm +++ b/drape/metal/metal_mesh_object_impl.mm @@ -42,28 +42,38 @@ public: m_geometryBuffers.resize(m_mesh->m_buffers.size()); for (size_t i = 0; i < m_mesh->m_buffers.size(); i++) - { - if (m_mesh->m_buffers[i].m_data.empty()) + { + auto const sizeInBytes = m_mesh->m_buffers[i]->GetSizeInBytes(); + if (sizeInBytes == 0) continue; - auto const sizeInBytes = m_mesh->m_buffers[i].m_data.size() * sizeof(m_mesh->m_buffers[i].m_data[0]); - m_geometryBuffers[i] = [device newBufferWithBytes:m_mesh->m_buffers[i].m_data.data() + m_geometryBuffers[i] = [device newBufferWithBytes:m_mesh->m_buffers[i]->GetData() length:sizeInBytes options:MTLResourceCPUCacheModeWriteCombined]; std::ostringstream ss; - for (size_t j = 0; j < m_mesh->m_buffers[i].m_attributes.size(); j++) + ss << "MeshVB:"; + for (size_t j = 0; j < m_mesh->m_buffers[i]->m_attributes.size(); j++) { - ss << m_mesh->m_buffers[i].m_attributes[j].m_attributeName; - if (j + 1 < m_mesh->m_buffers[i].m_attributes.size()) + ss << m_mesh->m_buffers[i]->m_attributes[j].m_attributeName; + if (j + 1 < m_mesh->m_buffers[i]->m_attributes.size()) ss << "+"; } m_geometryBuffers[i].label = @(ss.str().c_str()); } + + if (!m_mesh->m_indices.empty()) + { + m_indexBuffer = [device newBufferWithBytes:m_mesh->m_indices.data() + length:m_mesh->m_indices.size() * sizeof(uint16_t) + options:MTLResourceCPUCacheModeWriteCombined]; + m_indexBuffer.label = @"MeshIB"; + } } void Reset() override { m_geometryBuffers.clear(); + m_indexBuffer = nil; } void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override @@ -72,18 +82,31 @@ public: CHECK_LESS(bufferInd, static_cast(m_geometryBuffers.size()), ()); auto & buffer = m_mesh->m_buffers[bufferInd]; - CHECK(!buffer.m_data.empty(), ()); + auto const sizeInBytes = buffer->GetSizeInBytes(); + CHECK(sizeInBytes != 0, ()); uint8_t * bufferPointer = (uint8_t *)[m_geometryBuffers[bufferInd] contents]; - auto const sizeInBytes = buffer.m_data.size() * sizeof(buffer.m_data[0]); - memcpy(bufferPointer, buffer.m_data.data(), sizeInBytes); + memcpy(bufferPointer, buffer->GetData(), sizeInBytes); + } + + void UpdateIndexBuffer(ref_ptr context) override + { + UNUSED_VALUE(context); + CHECK(m_indexBuffer != nil, ()); + + auto const sizeInBytes = m_mesh->m_indices.size() * sizeof(uint16_t); + CHECK(sizeInBytes != 0, ()); + + uint8_t * bufferPointer = (uint8_t *)[m_indexBuffer contents]; + memcpy(bufferPointer, m_mesh->m_indices.data(), sizeInBytes); } void Bind(ref_ptr program) override {} void Unbind() override {} - void DrawPrimitives(ref_ptr context, uint32_t verticesCount) override + void DrawPrimitives(ref_ptr context, uint32_t vertexCount, + uint32_t startVertex) override { ref_ptr metalContext = context; if (!metalContext->HasAppliedPipelineState()) @@ -93,13 +116,34 @@ public: for (size_t i = 0; i < m_geometryBuffers.size(); i++) [encoder setVertexBuffer:m_geometryBuffers[i] offset:0 atIndex:i]; - [encoder drawPrimitives:GetPrimitiveType(m_mesh->m_drawPrimitive) vertexStart:0 - vertexCount:verticesCount]; + [encoder drawPrimitives:GetPrimitiveType(m_mesh->m_drawPrimitive) + vertexStart:startVertex + vertexCount:vertexCount]; + } + + void DrawPrimitivesIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex) override + { + ref_ptr metalContext = context; + if (!metalContext->HasAppliedPipelineState()) + return; + + id encoder = metalContext->GetCommandEncoder(); + for (size_t i = 0; i < m_geometryBuffers.size(); i++) + [encoder setVertexBuffer:m_geometryBuffers[i] offset:0 atIndex:i]; + + CHECK(m_indexBuffer != nil, ()); + [encoder drawIndexedPrimitives:GetPrimitiveType(m_mesh->m_drawPrimitive) + indexCount:indexCount + indexType:MTLIndexTypeUInt16 + indexBuffer:m_indexBuffer + indexBufferOffset:startIndex * sizeof(uint16_t)]; } private: ref_ptr m_mesh; std::vector> m_geometryBuffers; + id m_indexBuffer; }; } // namespace metal diff --git a/drape/oglcontext.cpp b/drape/oglcontext.cpp index 0156d026f2..91d3398c97 100644 --- a/drape/oglcontext.cpp +++ b/drape/oglcontext.cpp @@ -180,6 +180,11 @@ void OGLContext::SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) GLCHECK(GLFunctions::glScissor(x, y, w, h)); } +void OGLContext::SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + GLCHECK(GLFunctions::glScissor(x, y, w, h)); +} + void OGLContext::SetDepthTestEnabled(bool enabled) { if (enabled) @@ -214,4 +219,12 @@ void OGLContext::SetStencilActions(StencilFace face, StencilAction stencilFailAc DecodeStencilAction(depthFailAction), DecodeStencilAction(passAction)); } + +void OGLContext::SetCullingEnabled(bool enabled) +{ + if (enabled) + GLFunctions::glEnable(gl_const::GLCullFace); + else + GLFunctions::glDisable(gl_const::GLCullFace); +} } // namespace dp diff --git a/drape/oglcontext.hpp b/drape/oglcontext.hpp index deca3687ac..6271684922 100644 --- a/drape/oglcontext.hpp +++ b/drape/oglcontext.hpp @@ -22,6 +22,7 @@ public: void Clear(uint32_t clearBits, uint32_t storeBits) override; void Flush() override; void SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; + void SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; void SetDepthTestEnabled(bool enabled) override; void SetDepthTestFunction(TestFunction depthFunction) override; void SetStencilTestEnabled(bool enabled) override; @@ -31,5 +32,7 @@ public: // Do not use custom stencil reference value in OpenGL rendering. void SetStencilReferenceValue(uint32_t stencilReferenceValue) override {} + + void SetCullingEnabled(bool enabled) override; }; } // namespace dp diff --git a/drape/static_texture.cpp b/drape/static_texture.cpp index 414bc366dd..6c21ec4804 100644 --- a/drape/static_texture.cpp +++ b/drape/static_texture.cpp @@ -94,6 +94,9 @@ public: }; } // namespace +StaticTexture::StaticTexture() + : m_info(make_unique_dp()) {} + StaticTexture::StaticTexture(ref_ptr context, std::string const & textureName, std::string const & skinPathName, dp::TextureFormat format, ref_ptr allocator, diff --git a/drape/static_texture.hpp b/drape/static_texture.hpp index 699a5d1e42..fd5a806c4c 100644 --- a/drape/static_texture.hpp +++ b/drape/static_texture.hpp @@ -18,6 +18,8 @@ public: static std::string const kDefaultResource; + StaticTexture(); + /// @todo All xxxName can be std::string_view after Platform::GetReader (StyleReader) refactoring. StaticTexture(ref_ptr context, std::string const & textureName, std::string const & skinPathName, dp::TextureFormat format, diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 2dd84f1ba6..00db093e56 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -611,4 +611,9 @@ constexpr size_t TextureManager::GetInvalidGlyphGroup() { return kInvalidGlyphGroup; } + +ref_ptr TextureManager::GetTextureAllocator() const +{ + return make_ref(m_textureAllocator); +} } // namespace dp diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index 01459c3c8a..ff4e507586 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -123,6 +123,8 @@ public: // Apply must be called on FrontendRenderer. void ApplyInvalidatedStaticTextures(); + ref_ptr GetTextureAllocator() const; + private: struct GlyphGroup { diff --git a/drape/vulkan/vulkan_base_context.cpp b/drape/vulkan/vulkan_base_context.cpp index c914ac3f22..898a9a8776 100644 --- a/drape/vulkan/vulkan_base_context.cpp +++ b/drape/vulkan/vulkan_base_context.cpp @@ -207,6 +207,14 @@ bool VulkanBaseContext::BeginRendering() return false; } + #if defined(OMIM_OS_MAC) + // MoltenVK returns VK_SUBOPTIMAL_KHR in our configuration, it means that window is not resized that's expected + // in the developer sandbox for macOS + // https://github.com/KhronosGroup/MoltenVK/issues/1753 + if (res == VK_SUBOPTIMAL_KHR) + res = VK_SUCCESS; + #endif + if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) { RecreateSwapchainAndDependencies(); @@ -357,15 +365,24 @@ void VulkanBaseContext::ApplyFramebuffer(std::string const & framebufferLabel) auto const depthStencilRef = framebuffer->GetDepthStencilRef(); auto const attachmentsCount = (depthStencilRef != nullptr) ? 2 : 1; colorFormat = VulkanFormatUnpacker::Unpack(framebuffer->GetTexture()->GetFormat()); + VkImageLayout initialDepthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED; if (depthStencilRef != nullptr) + { depthFormat = VulkanFormatUnpacker::Unpack(depthStencilRef->GetTexture()->GetFormat()); + ASSERT(dynamic_cast(depthStencilRef->GetTexture()->GetHardwareTexture().get()) != nullptr, ()); + ref_ptr depthStencilAttachment = depthStencilRef->GetTexture()->GetHardwareTexture(); + initialDepthStencilLayout = depthStencilAttachment->GetCurrentLayout(); + } fbData.m_packedAttachmentOperations = packedAttachmentOperations; fbData.m_renderPass = CreateRenderPass(attachmentsCount, attachmentsOp, colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, + depthFormat, initialDepthStencilLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } + + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_RENDER_PASS, fbData.m_renderPass, + ("RP: " + framebufferLabel).c_str()); } // Initialize framebuffers. @@ -395,6 +412,8 @@ void VulkanBaseContext::ApplyFramebuffer(std::string const & framebufferLabel) attachmentViews[0] = m_swapchainImageViews[i]; CHECK_VK_CALL(vkCreateFramebuffer(m_device, &frameBufferCreateInfo, nullptr, &fbData.m_framebuffers[i])); + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_FRAMEBUFFER, fbData.m_framebuffers[i], + ("FB: " + framebufferLabel + std::to_string(i)).c_str()); } } else @@ -431,6 +450,8 @@ void VulkanBaseContext::ApplyFramebuffer(std::string const & framebufferLabel) fbData.m_framebuffers.resize(1); CHECK_VK_CALL(vkCreateFramebuffer(m_device, &frameBufferCreateInfo, nullptr, &fbData.m_framebuffers[0])); + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_FRAMEBUFFER, fbData.m_framebuffers[0], + ("FB: " + framebufferLabel).c_str()); } } @@ -558,6 +579,7 @@ void VulkanBaseContext::UnregisterHandler(uint32_t id) void VulkanBaseContext::ResetPipelineCache() { + vkDeviceWaitIdle(m_device); if (m_pipeline) m_pipeline->ResetCache(m_device); } @@ -672,6 +694,11 @@ void VulkanBaseContext::SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t viewport.maxDepth = 1.0f; vkCmdSetViewport(m_renderingCommandBuffers[m_inflightFrameIndex], 0, 1, &viewport); + SetScissor(x, y, w, h); +} + +void VulkanBaseContext::SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ VkRect2D scissor = {}; scissor.extent = {w, h}; scissor.offset.x = x; @@ -710,6 +737,11 @@ void VulkanBaseContext::SetStencilReferenceValue(uint32_t stencilReferenceValue) m_stencilReferenceValue = stencilReferenceValue; } +void VulkanBaseContext::SetCullingEnabled(bool enabled) +{ + m_pipelineKey.m_cullingEnabled = enabled; +} + void VulkanBaseContext::SetPrimitiveTopology(VkPrimitiveTopology topology) { m_pipelineKey.m_primitiveTopology = topology; @@ -813,8 +845,12 @@ void VulkanBaseContext::RecreateSwapchain() swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCI.pNext = nullptr; swapchainCI.surface = *m_surface; - swapchainCI.minImageCount = std::min(m_surfaceCapabilities.minImageCount + 1, - m_surfaceCapabilities.maxImageCount); + // maxImageCount may be 0, that means there is no limit. + // https://registry.khronos.org/vulkan/specs/latest/man/html/VkSurfaceCapabilitiesKHR.html + uint32_t minImagesCount = m_surfaceCapabilities.minImageCount + 1; + if (m_surfaceCapabilities.maxImageCount != 0) + minImagesCount = std::min(minImagesCount, m_surfaceCapabilities.maxImageCount); + swapchainCI.minImageCount = minImagesCount; swapchainCI.imageFormat = m_surfaceFormat->format; swapchainCI.imageColorSpace = m_surfaceFormat->colorSpace; swapchainCI.imageExtent = m_surfaceCapabilities.currentExtent; diff --git a/drape/vulkan/vulkan_base_context.hpp b/drape/vulkan/vulkan_base_context.hpp index ec81da114a..c29fa5331d 100644 --- a/drape/vulkan/vulkan_base_context.hpp +++ b/drape/vulkan/vulkan_base_context.hpp @@ -60,6 +60,7 @@ public: void Clear(uint32_t clearBits, uint32_t storeBits) override; void Flush() override {} void SetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; + void SetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; void SetDepthTestEnabled(bool enabled) override; void SetDepthTestFunction(TestFunction depthFunction) override; void SetStencilTestEnabled(bool enabled) override; @@ -67,6 +68,7 @@ public: void SetStencilActions(StencilFace face, StencilAction stencilFailAction, StencilAction depthFailAction, StencilAction passAction) override; void SetStencilReferenceValue(uint32_t stencilReferenceValue) override; + void SetCullingEnabled(bool enabled) override; void SetPrimitiveTopology(VkPrimitiveTopology topology); void SetBindingInfo(BindingInfoArray const & bindingInfo, uint8_t bindingInfoCount); @@ -82,6 +84,7 @@ public: VkPhysicalDevice GetPhysicalDevice() const { return m_gpu; } VkDevice GetDevice() const { return m_device; } + VkQueue GetQueue() const { return m_queue; } VkPhysicalDeviceProperties const & GetGpuProperties() const { return m_gpuProperties; } uint32_t GetRenderingQueueFamilyIndex() { return m_renderingQueueFamilyIndex; } diff --git a/drape/vulkan/vulkan_layers.cpp b/drape/vulkan/vulkan_layers.cpp index 2767003358..a4126b0ef6 100755 --- a/drape/vulkan/vulkan_layers.cpp +++ b/drape/vulkan/vulkan_layers.cpp @@ -21,11 +21,25 @@ char const * const kInstanceExtensions[] = { "VK_KHR_android_surface", kDebugReportExtension, kValidationFeaturesExtension, +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_LINUX) + "VK_EXT_debug_utils", +#endif +#if defined(OMIM_OS_MAC) + "VK_KHR_portability_enumeration", + "VK_MVK_macos_surface", + "VK_KHR_get_physical_device_properties2", +#endif +#if defined(OMIM_OS_LINUX) + "VK_KHR_xlib_surface", +#endif }; char const * const kDeviceExtensions[] = { - "VK_KHR_swapchain" + "VK_KHR_swapchain", +#if defined(OMIM_OS_MAC) + "VK_KHR_portability_subset", +#endif }; char const * const kValidationLayers[] = diff --git a/drape/vulkan/vulkan_mesh_object_impl.cpp b/drape/vulkan/vulkan_mesh_object_impl.cpp index 1d5c852bb9..e2f998c16d 100644 --- a/drape/vulkan/vulkan_mesh_object_impl.cpp +++ b/drape/vulkan/vulkan_mesh_object_impl.cpp @@ -6,8 +6,10 @@ #include "drape/vulkan/vulkan_utils.hpp" #include "base/assert.hpp" +#include "base/buffer_vector.hpp" #include +#include #include namespace dp @@ -44,28 +46,43 @@ public: CHECK_LESS_OR_EQUAL(m_bindingInfoCount, kMaxBindingInfo, ()); for (size_t i = 0; i < m_mesh->m_buffers.size(); i++) { - if (m_mesh->m_buffers[i].m_data.empty()) + auto const sizeInBytes = m_mesh->m_buffers[i]->GetSizeInBytes(); + if (sizeInBytes == 0) continue; - auto const sizeInBytes = static_cast(m_mesh->m_buffers[i].m_data.size() * - sizeof(m_mesh->m_buffers[i].m_data[0])); m_geometryBuffers[i] = m_objectManager->CreateBuffer(VulkanMemoryManager::ResourceType::Geometry, sizeInBytes, 0 /* batcherHash */); - m_objectManager->Fill(m_geometryBuffers[i], m_mesh->m_buffers[i].m_data.data(), sizeInBytes); + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_BUFFER, m_geometryBuffers[i].m_buffer, + ("VB: Mesh (" + m_mesh->m_debugName + ") " + std::to_string(i)).c_str()); - m_bindingInfo[i] = dp::BindingInfo(static_cast(m_mesh->m_buffers[i].m_attributes.size()), + m_objectManager->Fill(m_geometryBuffers[i], m_mesh->m_buffers[i]->GetData(), sizeInBytes); + + m_bindingInfo[i] = dp::BindingInfo(static_cast(m_mesh->m_buffers[i]->m_attributes.size()), static_cast(i)); - for (size_t j = 0; j < m_mesh->m_buffers[i].m_attributes.size(); ++j) + for (size_t j = 0; j < m_mesh->m_buffers[i]->m_attributes.size(); ++j) { - auto const & attr = m_mesh->m_buffers[i].m_attributes[j]; + auto const & attr = m_mesh->m_buffers[i]->m_attributes[j]; auto & binding = m_bindingInfo[i].GetBindingDecl(static_cast(j)); binding.m_attributeName = attr.m_attributeName; binding.m_componentCount = static_cast(attr.m_componentsCount); binding.m_componentType = gl_const::GLFloatType; binding.m_offset = static_cast(attr.m_offset); - binding.m_stride = static_cast(m_mesh->m_buffers[i].m_stride); + CHECK_LESS_OR_EQUAL(m_mesh->m_buffers[i]->GetStrideInBytes(), + static_cast(std::numeric_limits::max()), ()); + binding.m_stride = static_cast(m_mesh->m_buffers[i]->GetStrideInBytes()); } } + + if (!m_mesh->m_indices.empty()) + { + auto const sizeInBytes = static_cast(m_mesh->m_indices.size() * sizeof(uint16_t)); + m_indexBuffer = m_objectManager->CreateBuffer(VulkanMemoryManager::ResourceType::Geometry, + sizeInBytes, 0 /* batcherHash */); + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_BUFFER, m_indexBuffer.m_buffer, + ("IB: Mesh (" + m_mesh->m_debugName + ")").c_str()); + + m_objectManager->Fill(m_indexBuffer, m_mesh->m_indices.data(), sizeInBytes); + } } void Reset() override @@ -74,84 +91,69 @@ public: for (auto const & b : m_geometryBuffers) m_objectManager->DestroyObject(b); m_geometryBuffers.clear(); + + if (m_indexBuffer.m_buffer != VK_NULL_HANDLE) + m_objectManager->DestroyObject(m_indexBuffer); } void UpdateBuffer(ref_ptr context, uint32_t bufferInd) override { CHECK_LESS(bufferInd, static_cast(m_geometryBuffers.size()), ()); - - ref_ptr vulkanContext = context; - VkCommandBuffer commandBuffer = vulkanContext->GetCurrentMemoryCommandBuffer(); - CHECK(commandBuffer != nullptr, ()); - auto & buffer = m_mesh->m_buffers[bufferInd]; - CHECK(!buffer.m_data.empty(), ()); + auto const sizeInBytes = buffer->GetSizeInBytes(); + CHECK(sizeInBytes != 0, ()); - auto const sizeInBytes = static_cast(buffer.m_data.size() * sizeof(buffer.m_data[0])); - - // Set up a barrier to prevent data collisions (write-after-write, write-after-read). - VkBufferMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier.pNext = nullptr; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.buffer = m_geometryBuffers[bufferInd].m_buffer; - barrier.offset = 0; - barrier.size = sizeInBytes; - vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, - 1, &barrier, 0, nullptr); - - // Copy to default or temporary staging buffer. - auto stagingBuffer = vulkanContext->GetDefaultStagingBuffer(); - if (stagingBuffer->HasEnoughSpace(sizeInBytes)) - { - auto staging = stagingBuffer->Reserve(sizeInBytes); - memcpy(staging.m_pointer, buffer.m_data.data(), sizeInBytes); - - // Schedule command to copy from the staging buffer to our geometry buffer. - VkBufferCopy copyRegion = {}; - copyRegion.dstOffset = 0; - copyRegion.srcOffset = staging.m_offset; - copyRegion.size = sizeInBytes; - vkCmdCopyBuffer(commandBuffer, staging.m_stagingBuffer, m_geometryBuffers[bufferInd].m_buffer, - 1, ©Region); - } - else - { - // Here we use temporary staging object, which will be destroyed after the nearest - // command queue submitting. - VulkanStagingBuffer tempStagingBuffer(m_objectManager, sizeInBytes); - CHECK(tempStagingBuffer.HasEnoughSpace(sizeInBytes), ()); - auto staging = tempStagingBuffer.Reserve(sizeInBytes); - memcpy(staging.m_pointer, buffer.m_data.data(), sizeInBytes); - tempStagingBuffer.Flush(); - - // Schedule command to copy from the staging buffer to our geometry buffer. - VkBufferCopy copyRegion = {}; - copyRegion.dstOffset = 0; - copyRegion.srcOffset = staging.m_offset; - copyRegion.size = sizeInBytes; - vkCmdCopyBuffer(commandBuffer, staging.m_stagingBuffer, m_geometryBuffers[bufferInd].m_buffer, - 1, ©Region); - } - - // Set up a barrier to prevent data collisions (read-after-write). - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, - 1, &barrier, 0, nullptr); + UpdateBufferInternal(context, m_geometryBuffers[bufferInd].m_buffer, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + buffer->GetData(), sizeInBytes); } - void DrawPrimitives(ref_ptr context, uint32_t verticesCount) override + void UpdateIndexBuffer(ref_ptr context) override + { + CHECK(!m_mesh->m_indices.empty(), ()); + auto const sizeInBytes = m_mesh->m_indices.size() * sizeof(uint16_t); + CHECK(m_indexBuffer.m_buffer != VK_NULL_HANDLE, ()); + + UpdateBufferInternal(context, m_indexBuffer.m_buffer, + VK_ACCESS_INDEX_READ_BIT, + m_mesh->m_indices.data(), sizeInBytes); + } + + void DrawPrimitives(ref_ptr context, uint32_t vertexCount, + uint32_t startVertex) override { ref_ptr vulkanContext = context; VkCommandBuffer commandBuffer = vulkanContext->GetCurrentRenderingCommandBuffer(); CHECK(commandBuffer != nullptr, ()); + BindVertexBuffers(context, commandBuffer); + + vkCmdDraw(commandBuffer, vertexCount, 1, startVertex, 0); + } + + void DrawPrimitivesIndexed(ref_ptr context, uint32_t indexCount, + uint32_t startIndex) override + { + ref_ptr vulkanContext = context; + VkCommandBuffer commandBuffer = vulkanContext->GetCurrentRenderingCommandBuffer(); + CHECK(commandBuffer != nullptr, ()); + + BindVertexBuffers(context, commandBuffer); + + CHECK(m_indexBuffer.m_buffer != VK_NULL_HANDLE, ()); + vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer.m_buffer, 0, VK_INDEX_TYPE_UINT16); + + vkCmdDrawIndexed(commandBuffer, indexCount, 1, startIndex, 0, 0); + } + + void Bind(ref_ptr program) override {} + void Unbind() override {} + +private: + void BindVertexBuffers(ref_ptr context, VkCommandBuffer commandBuffer) + { + ref_ptr vulkanContext = context; + vulkanContext->SetPrimitiveTopology(GetPrimitiveType(m_mesh->m_drawPrimitive)); vulkanContext->SetBindingInfo(m_bindingInfo, m_bindingInfoCount); @@ -166,20 +168,84 @@ public: vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkanContext->GetCurrentPipeline()); - VkDeviceSize offsets[1] = {0}; + buffer_vector buffers; + buffer_vector offsets; for (uint32_t i = 0; i < static_cast(m_geometryBuffers.size()); ++i) - vkCmdBindVertexBuffers(commandBuffer, i, 1, &m_geometryBuffers[i].m_buffer, offsets); - - vkCmdDraw(commandBuffer, verticesCount, 1, 0, 0); + { + buffers.emplace_back(m_geometryBuffers[i].m_buffer); + offsets.emplace_back(0); + } + vkCmdBindVertexBuffers(commandBuffer, 0, m_geometryBuffers.size(), buffers.data(), + offsets.data()); } - void Bind(ref_ptr program) override {} - void Unbind() override {} + void UpdateBufferInternal(ref_ptr context, VkBuffer buffer, + VkAccessFlagBits bufferAccessMask, + void const * data, uint32_t sizeInBytes) + { + ref_ptr vulkanContext = context; + VkCommandBuffer commandBuffer = vulkanContext->GetCurrentMemoryCommandBuffer(); + CHECK(commandBuffer != nullptr, ()); + + // Set up a barrier to prevent data collisions (write-after-write, write-after-read). + VkBufferMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier.pNext = nullptr; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | bufferAccessMask; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.buffer = buffer; + barrier.offset = 0; + barrier.size = sizeInBytes; + vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, + 1, &barrier, 0, nullptr); + + // Copy to default or temporary staging buffer. + auto stagingBuffer = vulkanContext->GetDefaultStagingBuffer(); + if (stagingBuffer->HasEnoughSpace(sizeInBytes)) + { + auto staging = stagingBuffer->Reserve(sizeInBytes); + memcpy(staging.m_pointer, data, sizeInBytes); + + // Schedule command to copy from the staging buffer to our geometry buffer. + VkBufferCopy copyRegion = {}; + copyRegion.dstOffset = 0; + copyRegion.srcOffset = staging.m_offset; + copyRegion.size = sizeInBytes; + vkCmdCopyBuffer(commandBuffer, staging.m_stagingBuffer, buffer, 1, ©Region); + } + else + { + // Here we use temporary staging object, which will be destroyed after the nearest + // command queue submitting. + VulkanStagingBuffer tempStagingBuffer(m_objectManager, sizeInBytes); + CHECK(tempStagingBuffer.HasEnoughSpace(sizeInBytes), ()); + auto staging = tempStagingBuffer.Reserve(sizeInBytes); + memcpy(staging.m_pointer, data, sizeInBytes); + tempStagingBuffer.Flush(); + + // Schedule command to copy from the staging buffer to our geometry buffer. + VkBufferCopy copyRegion = {}; + copyRegion.dstOffset = 0; + copyRegion.srcOffset = staging.m_offset; + copyRegion.size = sizeInBytes; + vkCmdCopyBuffer(commandBuffer, staging.m_stagingBuffer, buffer, 1, ©Region); + } + + // Set up a barrier to prevent data collisions (read-after-write). + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = bufferAccessMask; + vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, + 1, &barrier, 0, nullptr); + } -private: ref_ptr m_mesh; ref_ptr m_objectManager; std::vector m_geometryBuffers; + VulkanObject m_indexBuffer; BindingInfoArray m_bindingInfo; uint8_t m_bindingInfoCount = 0; ParamDescriptorUpdater m_descriptorUpdater; diff --git a/drape/vulkan/vulkan_object_manager.cpp b/drape/vulkan/vulkan_object_manager.cpp index c6e262d16e..53b2136163 100644 --- a/drape/vulkan/vulkan_object_manager.cpp +++ b/drape/vulkan/vulkan_object_manager.cpp @@ -117,6 +117,11 @@ VulkanObject VulkanObjectManager::CreateBuffer(VulkanMemoryManager::ResourceType info.queueFamilyIndexCount = 1; info.pQueueFamilyIndices = &m_queueFamilyIndex; CHECK_VK_CALL(vkCreateBuffer(m_device, &info, nullptr, &result.m_buffer)); + + SET_DEBUG_NAME_VK(VK_OBJECT_TYPE_BUFFER, result.m_buffer, + ((resourceType == VulkanMemoryManager::ResourceType::Geometry ? "B: Geometry (" : + (resourceType == VulkanMemoryManager::ResourceType::Uniform ? "B: Uniform (" : + "B: Staging (")) + std::to_string(sizeInBytes) + " bytes)").c_str()); VkMemoryRequirements memReqs = {}; vkGetBufferMemoryRequirements(m_device, result.m_buffer, &memReqs); @@ -387,7 +392,7 @@ void VulkanObjectManager::FlushUnsafe(VulkanObject object, uint32_t offset, uint if (size == 0) mappedRange.size = object.GetAlignedSize(); else - mappedRange.size = mappedRange.offset + size; + mappedRange.size = size; CHECK_VK_CALL(vkFlushMappedMemoryRanges(m_device, 1, &mappedRange)); } diff --git a/drape/vulkan/vulkan_pipeline.cpp b/drape/vulkan/vulkan_pipeline.cpp index 85300bf506..f345ea9290 100644 --- a/drape/vulkan/vulkan_pipeline.cpp +++ b/drape/vulkan/vulkan_pipeline.cpp @@ -270,6 +270,7 @@ void VulkanPipeline::ResetCache(VkDevice device, VkRenderPass renderPass) void VulkanPipeline::Destroy(VkDevice device) { + vkDeviceWaitIdle(device); Dump(device); ResetCache(device); vkDestroyPipelineCache(device, m_vulkanPipelineCache, nullptr); @@ -292,7 +293,7 @@ VkPipeline VulkanPipeline::GetPipeline(VkDevice device, PipelineKey const & key) VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {}; rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; - rasterizationStateCreateInfo.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizationStateCreateInfo.cullMode = key.m_cullingEnabled ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE; rasterizationStateCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizationStateCreateInfo.lineWidth = 1.0f; @@ -563,7 +564,10 @@ bool VulkanPipeline::PipelineKey::operator<(PipelineKey const & rhs) const if (m_primitiveTopology != rhs.m_primitiveTopology) return m_primitiveTopology < rhs.m_primitiveTopology; - return m_blendingEnabled < rhs.m_blendingEnabled; + if (m_blendingEnabled != rhs.m_blendingEnabled) + return m_blendingEnabled < rhs.m_blendingEnabled; + + return m_cullingEnabled < rhs.m_cullingEnabled; } } // namespace vulkan } // namespace dp diff --git a/drape/vulkan/vulkan_pipeline.hpp b/drape/vulkan/vulkan_pipeline.hpp index d9e8c5fe9c..41687723cb 100644 --- a/drape/vulkan/vulkan_pipeline.hpp +++ b/drape/vulkan/vulkan_pipeline.hpp @@ -44,6 +44,7 @@ public: uint8_t m_bindingInfoCount = 0; VkPrimitiveTopology m_primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; bool m_blendingEnabled = false; + bool m_cullingEnabled = true; }; VulkanPipeline(VkDevice device, uint32_t appVersionCode); diff --git a/drape/vulkan/vulkan_texture.hpp b/drape/vulkan/vulkan_texture.hpp index edc0cbda6e..674cd72c51 100644 --- a/drape/vulkan/vulkan_texture.hpp +++ b/drape/vulkan/vulkan_texture.hpp @@ -38,6 +38,7 @@ public: VkImageView GetTextureView() const { return m_textureObject.m_imageView; } VkImage GetImage() const { return m_textureObject.m_image; } SamplerKey GetSamplerKey() const; + VkImageLayout GetCurrentLayout() const { return m_currentLayout; } void MakeImageLayoutTransition(VkCommandBuffer commandBuffer, VkImageLayout newLayout, diff --git a/drape/vulkan/vulkan_utils.cpp b/drape/vulkan/vulkan_utils.cpp index b06ec759a7..f32af92f3d 100644 --- a/drape/vulkan/vulkan_utils.cpp +++ b/drape/vulkan/vulkan_utils.cpp @@ -15,6 +15,32 @@ uint8_t constexpr kMagFilterByte = 1; uint8_t constexpr kMinFilterByte = 0; } // namespace +VkDevice DebugName::m_device = VK_NULL_HANDLE; +PFN_vkSetDebugUtilsObjectNameEXT DebugName::vkSetDebugUtilsObjectNameEXT = nullptr; + +static bool gUse32bitDepth8bitStencil = false; + +void DebugName::Init(VkInstance instance, VkDevice device) +{ + vkSetDebugUtilsObjectNameEXT = + (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); + m_device = device; +} + +void DebugName::Set(VkObjectType type, uint64_t handle, char const * name) +{ + if (vkSetDebugUtilsObjectNameEXT == nullptr) + return; + + VkDebugUtilsObjectNameInfoEXT const info = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .objectType = type, + .objectHandle = handle, + .pObjectName = name, + }; + CHECK_VK_CALL(vkSetDebugUtilsObjectNameEXT(m_device, &info)); +} + std::string GetVulkanResultString(VkResult result) { switch (result) @@ -102,8 +128,13 @@ bool VulkanFormatUnpacker::Init(VkPhysicalDevice gpu) vkGetPhysicalDeviceFormatProperties(gpu, Unpack(TextureFormat::DepthStencil), &formatProperties); if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - LOG(LWARNING, ("Vulkan error: depth-stencil format is unsupported.")); - return false; + gUse32bitDepth8bitStencil = true; + vkGetPhysicalDeviceFormatProperties(gpu, Unpack(TextureFormat::DepthStencil), &formatProperties); + if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) + { + LOG(LWARNING, ("Vulkan error: depth-stencil format is unsupported.")); + return false; + } } std::array framebufferColorFormats = {{Unpack(TextureFormat::RGBA8), @@ -129,7 +160,11 @@ VkFormat VulkanFormatUnpacker::Unpack(TextureFormat format) case TextureFormat::RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; case TextureFormat::Alpha: return VK_FORMAT_R8_UNORM; case TextureFormat::RedGreen: return VK_FORMAT_R8G8_UNORM; - case TextureFormat::DepthStencil: return VK_FORMAT_D24_UNORM_S8_UINT; +#if defined(OMIM_OS_MAC) + case TextureFormat::DepthStencil: return VK_FORMAT_D32_SFLOAT_S8_UINT; +#else + case TextureFormat::DepthStencil: return gUse32bitDepth8bitStencil ? VK_FORMAT_D32_SFLOAT_S8_UINT : VK_FORMAT_D24_UNORM_S8_UINT; +#endif case TextureFormat::Depth: return m_bestDepthFormat; case TextureFormat::Unspecified: CHECK(false, ()); diff --git a/drape/vulkan/vulkan_utils.hpp b/drape/vulkan/vulkan_utils.hpp index f54c792b01..2d6ee6928f 100644 --- a/drape/vulkan/vulkan_utils.hpp +++ b/drape/vulkan/vulkan_utils.hpp @@ -54,6 +54,18 @@ struct SamplerKey uint32_t m_sampler = 0; }; + +class DebugName +{ +public: + static void Init(VkInstance instance, VkDevice device); + static void Set(VkObjectType type, uint64_t handle, char const * name); + +private: + static VkDevice m_device; + static PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; +}; + } // namespace vulkan } // namespace dp @@ -81,3 +93,18 @@ struct SamplerKey CHECK(statusCode == VK_SUCCESS, ("Vulkan error:", #method, "finished with code", \ dp::vulkan::GetVulkanResultString(statusCode))); \ } while (false) + +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_LINUX) +#define INIT_DEBUG_NAME_VK(instance, device) \ + do { \ + DebugName::Init(instance, device); \ + } while (false) + +#define SET_DEBUG_NAME_VK(type, handle, name) \ + do { \ + DebugName::Set(type, (uint64_t)handle, name); \ + } while (false) +#else +#define INIT_DEBUG_NAME_VK(instance, device) +#define SET_DEBUG_NAME_VK(type, handle, name) +#endif diff --git a/drape_frontend/arrow3d.cpp b/drape_frontend/arrow3d.cpp index bd935eec98..48bf8f6e60 100644 --- a/drape_frontend/arrow3d.cpp +++ b/drape_frontend/arrow3d.cpp @@ -290,12 +290,12 @@ Arrow3d::PreloadedData Arrow3d::PreloadMesh(std::optional con Arrow3d::Arrow3d(ref_ptr context, ref_ptr texMng, PreloadedData && preloadedData) - : m_arrowMesh(context, dp::MeshObject::DrawPrimitive::Triangles) + : m_arrowMesh(context, dp::MeshObject::DrawPrimitive::Triangles, "Arrow3d") , m_arrowMeshTexturingEnabled(preloadedData.m_arrowMeshTexturingEnabled) , m_texCoordFlipping(std::move(preloadedData.m_texCoordFlipping)) , m_shadowMesh( preloadedData.m_shadowMeshData.has_value() - ? make_unique_dp(context, dp::MeshObject::DrawPrimitive::Triangles) + ? make_unique_dp(context, dp::MeshObject::DrawPrimitive::Triangles, "Arrow3dShadow") : nullptr) , m_state(CreateRenderState(gpu::Program::Arrow3d, DepthLayer::OverlayLayer)) , m_meshOffset(std::move(preloadedData.m_meshOffset)) diff --git a/drape_frontend/debug_rect_renderer.cpp b/drape_frontend/debug_rect_renderer.cpp index 4a8a8fdfb8..151d5b8169 100644 --- a/drape_frontend/debug_rect_renderer.cpp +++ b/drape_frontend/debug_rect_renderer.cpp @@ -17,9 +17,9 @@ void PixelPointToScreenSpace(ScreenBase const & screen, m2::PointF const & pt, s } drape_ptr CreateMesh(ref_ptr context, ref_ptr program, - std::vector && vertices) + std::vector && vertices, std::string const & debugName) { - auto mesh = make_unique_dp(context, dp::MeshObject::DrawPrimitive::LineStrip); + auto mesh = make_unique_dp(context, dp::MeshObject::DrawPrimitive::LineStrip, debugName); mesh->SetBuffer(0 /* bufferInd */, std::move(vertices), static_cast(sizeof(float) * 2)); mesh->SetAttribute("a_position", 0 /* bufferInd */, 0 /* offset */, 2 /* componentsCount */); mesh->Build(context, program); @@ -70,9 +70,9 @@ void DebugRectRenderer::SetArrow(ref_ptr context, m2::Point ASSERT_LESS_OR_EQUAL(m_currentArrowMesh, m_arrowMeshes.size(), ()); if (m_currentArrowMesh == m_arrowMeshes.size()) - m_arrowMeshes.emplace_back(CreateMesh(context, m_program, std::move(vertices))); + m_arrowMeshes.emplace_back(CreateMesh(context, m_program, std::move(vertices), "DebugArrow")); else - m_arrowMeshes[m_currentArrowMesh]->UpdateBuffer(context, 0 /* bufferInd */, std::move(vertices)); + m_arrowMeshes[m_currentArrowMesh]->UpdateBuffer(context, 0 /* bufferInd */, vertices); } void DebugRectRenderer::SetRect(ref_ptr context, m2::RectF const & rect, @@ -87,9 +87,9 @@ void DebugRectRenderer::SetRect(ref_ptr context, m2::RectF ASSERT_LESS_OR_EQUAL(m_currentRectMesh, m_rectMeshes.size(), ()); if (m_currentRectMesh == m_rectMeshes.size()) - m_rectMeshes.emplace_back(CreateMesh(context, m_program, std::move(vertices))); + m_rectMeshes.emplace_back(CreateMesh(context, m_program, std::move(vertices), "DebugRect")); else - m_rectMeshes[m_currentRectMesh]->UpdateBuffer(context, 0 /* bufferInd */, std::move(vertices)); + m_rectMeshes[m_currentRectMesh]->UpdateBuffer(context, 0 /* bufferInd */, vertices); } void DebugRectRenderer::DrawRect(ref_ptr context, ScreenBase const & screen, diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 547d79ed33..b5c57af451 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -87,7 +87,8 @@ DrapeEngine::DrapeEngine(Params && params) params.m_trafficEnabled, params.m_blockTapEvents, std::move(effects), - params.m_onGraphicsContextInitialized); + params.m_onGraphicsContextInitialized, + std::move(params.m_renderInjectionHandler)); BackendRenderer::Params brParams( params.m_apiVersion, frParams.m_commutator, frParams.m_oglContextFactory, frParams.m_texMng, @@ -198,6 +199,11 @@ void DrapeEngine::Rotate(double azimuth, bool isAnim) AddUserEvent(make_unique_dp(azimuth, isAnim, nullptr /* parallelAnimCreator */)); } +void DrapeEngine::MakeFrameActive() +{ + AddUserEvent(make_unique_dp()); +} + void DrapeEngine::ScaleAndSetCenter(m2::PointD const & centerPt, double scaleFactor, bool isAnim, bool trackVisibleViewport) { diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 56f007af11..c843003199 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -61,7 +61,8 @@ public: bool isRoutingActive, bool isAutozoomEnabled, bool simplifiedTrafficColors, std::optional arrow3dCustomDecl, OverlaysShowStatsCallback && overlaysShowStatsCallback, - OnGraphicsContextInitialized && onGraphicsContextInitialized) + OnGraphicsContextInitialized && onGraphicsContextInitialized, + dp::RenderInjectionHandler && renderInjectionHandler) : m_apiVersion(apiVersion) , m_factory(factory) , m_viewport(viewport) @@ -83,6 +84,7 @@ public: , m_arrow3dCustomDecl(std::move(arrow3dCustomDecl)) , m_overlaysShowStatsCallback(std::move(overlaysShowStatsCallback)) , m_onGraphicsContextInitialized(std::move(onGraphicsContextInitialized)) + , m_renderInjectionHandler(std::move(renderInjectionHandler)) {} dp::ApiVersion m_apiVersion; @@ -107,6 +109,7 @@ public: std::optional m_arrow3dCustomDecl; OverlaysShowStatsCallback m_overlaysShowStatsCallback; OnGraphicsContextInitialized m_onGraphicsContextInitialized; + dp::RenderInjectionHandler m_renderInjectionHandler; }; DrapeEngine(Params && params); @@ -125,6 +128,8 @@ public: void Scroll(double distanceX, double distanceY); void Rotate(double azimuth, bool isAnim); + void MakeFrameActive(); + void ScaleAndSetCenter(m2::PointD const & centerPt, double scaleFactor, bool isAnim, bool trackVisibleViewport); diff --git a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp index 2a5eb71dec..44acf3227d 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -65,8 +65,8 @@ public: void RunTest() { - bool dummy1, dummy2; - m_stream.ProcessEvents(dummy1, dummy2); + bool dummy1, dummy2, dummy3; + m_stream.ProcessEvents(dummy1, dummy2, dummy3); TEST_EQUAL(m_expectation.empty(), true, ()); } diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 5b08eb7a58..8f0861e488 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -187,6 +187,7 @@ FrontendRenderer::FrontendRenderer(Params && params) , m_scenarioManager(new ScenarioManager(this)) #endif , m_notifier(make_unique_dp(params.m_commutator)) + , m_renderInjectionHandler(std::move(params.m_renderInjectionHandler)) { #ifdef DEBUG m_isTeardowned = false; @@ -1732,7 +1733,6 @@ void FrontendRenderer::RenderEmptyFrame() m_context->Clear(dp::ClearBits::ColorBit, dp::ClearBits::ColorBit /* storeBits */); m_context->ApplyFramebuffer("Empty frame"); m_viewport.Apply(m_context); - m_context->EndRendering(); m_context->Present(); } @@ -1753,8 +1753,8 @@ void FrontendRenderer::RenderFrame() auto & scaleFpsHelper = gui::DrapeGui::Instance().GetScaleFpsHelper(); m_frameData.m_timer.Reset(); - bool modelViewChanged, viewportChanged; - ScreenBase const & modelView = ProcessEvents(modelViewChanged, viewportChanged); + bool modelViewChanged, viewportChanged, needActiveFrame; + ScreenBase const & modelView = ProcessEvents(modelViewChanged, viewportChanged, needActiveFrame); if (viewportChanged || m_needRestoreSize) OnResize(modelView); @@ -1762,7 +1762,7 @@ void FrontendRenderer::RenderFrame() return; // Check for a frame is active. - bool isActiveFrame = modelViewChanged || viewportChanged; + bool isActiveFrame = modelViewChanged || viewportChanged || needActiveFrame; if (isActiveFrame) PrepareScene(modelView); @@ -1788,6 +1788,9 @@ void FrontendRenderer::RenderFrame() RenderScene(modelView, isActiveFrameForScene); + if (m_renderInjectionHandler) + m_renderInjectionHandler(m_context, m_texMng, make_ref(m_gpuProgramManager), false); + m_context->EndRendering(); auto const hasForceUpdate = m_forceUpdateScene || m_forceUpdateUserMarks; @@ -2304,6 +2307,9 @@ void FrontendRenderer::OnContextDestroy() { LOG(LINFO, ("On context destroy.")); + if (m_renderInjectionHandler) + m_renderInjectionHandler(m_context, m_texMng, make_ref(m_gpuProgramManager), true); + // Clear all graphics. for (RenderLayer & layer : m_layers) { @@ -2557,10 +2563,12 @@ void FrontendRenderer::OnEnterBackground() m_myPositionController->OnEnterBackground(); } -ScreenBase const & FrontendRenderer::ProcessEvents(bool & modelViewChanged, bool & viewportChanged) +ScreenBase const & FrontendRenderer::ProcessEvents(bool & modelViewChanged, bool & viewportChanged, + bool & needActiveFrame) { TRACE_SECTION("[drape] ProcessEvents"); - ScreenBase const & modelView = m_userEventStream.ProcessEvents(modelViewChanged, viewportChanged); + ScreenBase const & modelView = m_userEventStream.ProcessEvents(modelViewChanged, viewportChanged, + needActiveFrame); gui::DrapeGui::Instance().SetInUserAction(m_userEventStream.IsInUserAction()); // Location- or compass-update could have changed model view on the previous frame. diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 8038ab7c4f..3108f89b0c 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -95,7 +95,8 @@ public: OverlaysShowStatsCallback && overlaysShowStatsCallback, bool allow3dBuildings, bool trafficEnabled, bool blockTapEvents, std::vector && enabledEffects, - OnGraphicsContextInitialized const & onGraphicsContextInitialized) + OnGraphicsContextInitialized const & onGraphicsContextInitialized, + dp::RenderInjectionHandler&& renderInjectionHandler) : BaseRenderer::Params(apiVersion, commutator, factory, texMng, onGraphicsContextInitialized) , m_myPositionParams(std::move(myPositionParams)) , m_viewport(viewport) @@ -108,6 +109,7 @@ public: , m_trafficEnabled(trafficEnabled) , m_blockTapEvents(blockTapEvents) , m_enabledEffects(std::move(enabledEffects)) + , m_renderInjectionHandler(std::move(renderInjectionHandler)) {} MyPositionController::Params m_myPositionParams; @@ -121,6 +123,7 @@ public: bool m_trafficEnabled; bool m_blockTapEvents; std::vector m_enabledEffects; + dp::RenderInjectionHandler m_renderInjectionHandler; }; explicit FrontendRenderer(Params && params); @@ -194,7 +197,8 @@ private: bool HasTransitRouteData() const; bool HasRouteData() const; - ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged); + ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged, + bool & needActiveFrame); void PrepareScene(ScreenBase const & modelView); void UpdateScene(ScreenBase const & modelView); void BuildOverlayTree(ScreenBase const & modelView); @@ -430,6 +434,8 @@ private: drape_ptr m_notifier; + dp::RenderInjectionHandler m_renderInjectionHandler; + struct FrameData { base::Timer m_timer; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 0c364f78e7..66c4e2315a 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -154,7 +154,8 @@ void UserEventStream::AddEvent(drape_ptr && event) m_events.emplace_back(std::move(event)); } -ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool & viewportChanged) +ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool & viewportChanged, + bool & activeFrame) { TEventsList events; { @@ -164,6 +165,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool m2::RectD const prevPixelRect = GetCurrentScreen().PixelRect(); + activeFrame = false; viewportChanged = false; m_modelViewChanged = !events.empty() || m_state == STATE_SCALE || m_state == STATE_DRAG; @@ -268,7 +270,11 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool TouchCancel(m_touches); } break; - + case UserEvent::EventType::ActiveFrame: + { + activeFrame = true; + } + break; default: ASSERT(false, ()); break; diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index b74dc2998b..47f8ebdfd8 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -42,7 +42,8 @@ public: AutoPerspective, VisibleViewport, Move, - Scroll + Scroll, + ActiveFrame }; virtual ~UserEvent() = default; @@ -400,6 +401,15 @@ private: double m_distanceY; }; +// Doesn't have any payload, allows to unfreeze rendering in frontend_renderer +class ActiveFrameEvent : public UserEvent +{ +public: + explicit ActiveFrameEvent(){} + + EventType GetType() const override { return UserEvent::EventType::ActiveFrame; } +}; + class UserEventStream { public: @@ -434,7 +444,7 @@ public: UserEventStream(); void AddEvent(drape_ptr && event); - ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged); + ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged, bool & activeFrame); ScreenBase const & GetCurrentScreen() const; m2::RectD const & GetVisibleViewport() const; diff --git a/map/framework.cpp b/map/framework.cpp index b589cd0c18..c40cc63f48 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1135,6 +1135,12 @@ void Framework::TouchEvent(df::TouchEvent const & touch) m_drapeEngine->AddTouchEvent(touch); } +void Framework::MakeFrameActive() +{ + if (m_drapeEngine != nullptr) + m_drapeEngine->MakeFrameActive(); +} + int Framework::GetDrawScale() const { if (m_drapeEngine != nullptr) @@ -1556,7 +1562,8 @@ void Framework::CreateDrapeEngine(ref_ptr contextFac params.m_isChoosePositionMode, params.m_isChoosePositionMode, GetSelectedFeatureTriangles(), m_routingManager.IsRoutingActive() && m_routingManager.IsRoutingFollowing(), isAutozoomEnabled, simplifiedTrafficColors, std::nullopt /* arrow3dCustomDecl */, - std::move(overlaysShowStatsFn), std::move(onGraphicsContextInitialized)); + std::move(overlaysShowStatsFn), std::move(onGraphicsContextInitialized), + std::move(params.m_renderInjectionHandler)); m_drapeEngine = make_unique_dp(std::move(p)); m_drapeEngine->SetModelViewListener([this](ScreenBase const & screen) diff --git a/map/framework.hpp b/map/framework.hpp index 9fb29750aa..63fde1c9e9 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -403,6 +403,7 @@ public: bool m_isChoosePositionMode = false; df::Hints m_hints; + dp::RenderInjectionHandler m_renderInjectionHandler; }; void CreateDrapeEngine(ref_ptr contextFactory, DrapeCreationParams && params); @@ -560,6 +561,8 @@ public: void TouchEvent(df::TouchEvent const & touch); + void MakeFrameActive(); + int GetDrawScale() const; void RunFirstLaunchAnimation(); diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 22fd0ef9b5..f37d6af0bf 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -129,10 +129,9 @@ target_sources(${PROJECT_NAME} vulkan_program_pool.hpp ) -if (PLATFORM_IPHONE) +if (PLATFORM_IPHONE OR PLATFORM_MAC) target_sources(${PROJECT_NAME} PRIVATE - Metal/debug_rect.metal metal_program_params.hpp metal_program_params.mm metal_program_pool.hpp @@ -146,4 +145,8 @@ target_include_directories(${PROJECT_NAME} PUBLIC "${OMIM_ROOT}/3party/glm") target_link_libraries(${PROJECT_NAME} drape) +if (PLATFORM_MAC) + set_target_properties(${PROJECT_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) +endif() + omim_add_test_subdirectory(shaders_tests)