forked from organicmaps/organicmaps
Merge pull request #10525 from rokuz/rendering-fixes
Rendering fixes and some optimizations
This commit is contained in:
commit
4d30a72b4a
23 changed files with 348 additions and 174 deletions
|
@ -362,7 +362,8 @@ bool Framework::AttachSurface(JNIEnv * env, jobject jSurface)
|
|||
if (m_isSurfaceDestroyed)
|
||||
{
|
||||
LOG(LINFO, ("Recover surface, viewport size:", w, h));
|
||||
m_work.OnRecoverSurface(w, h);
|
||||
bool const recreateContextDependentResources = (m_vulkanContextFactory == nullptr);
|
||||
m_work.OnRecoverSurface(w, h, recreateContextDependentResources);
|
||||
m_isSurfaceDestroyed = false;
|
||||
|
||||
m_work.EnterForeground();
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -19,8 +19,6 @@ namespace dp
|
|||
// OpenGL data), use FR/BR threads for that.
|
||||
class DrapeRoutine
|
||||
{
|
||||
friend class Promise;
|
||||
|
||||
public:
|
||||
class Result
|
||||
{
|
||||
|
@ -64,7 +62,7 @@ public:
|
|||
static ResultPtr Run(Task && t)
|
||||
{
|
||||
ResultPtr result(new Result(Instance().GetNextId()));
|
||||
bool const success = Instance().m_workerThread.Push([result, t]() mutable
|
||||
bool const success = Instance().m_workerThread.Push([result, t = std::move(t)]() mutable
|
||||
{
|
||||
t();
|
||||
Instance().Notify(result->Finish());
|
||||
|
@ -80,7 +78,24 @@ public:
|
|||
static ResultPtr RunDelayed(base::thread_pool::delayed::ThreadPool::Duration const & duration, Task && t)
|
||||
{
|
||||
ResultPtr result(new Result(Instance().GetNextId()));
|
||||
bool const success = Instance().m_workerThread.PushDelayed(duration, [result, t]() mutable
|
||||
bool const success = Instance().m_workerThread.PushDelayed(duration, [result, t = std::move(t)]() mutable
|
||||
{
|
||||
t();
|
||||
Instance().Notify(result->Finish());
|
||||
});
|
||||
|
||||
if (!success)
|
||||
return {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Asynchronous execution for tasks when execution order matters.
|
||||
template <typename Task>
|
||||
static ResultPtr RunSequential(Task && t)
|
||||
{
|
||||
ResultPtr result(new Result(Instance().GetNextId()));
|
||||
bool const success = Instance().m_sequentialWorkerThread.Push([result, t = std::move(t)]() mutable
|
||||
{
|
||||
t();
|
||||
Instance().Notify(result->Finish());
|
||||
|
@ -129,6 +144,7 @@ private:
|
|||
void FinishAll()
|
||||
{
|
||||
m_workerThread.ShutdownAndJoin();
|
||||
m_sequentialWorkerThread.ShutdownAndJoin();
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_finished = true;
|
||||
|
@ -141,6 +157,7 @@ private:
|
|||
std::condition_variable m_condition;
|
||||
std::mutex m_mutex;
|
||||
base::thread_pool::delayed::ThreadPool m_workerThread;
|
||||
base::thread_pool::delayed::ThreadPool m_sequentialWorkerThread;
|
||||
};
|
||||
|
||||
// This is a helper class, which aggregates logic of waiting for active
|
||||
|
@ -179,10 +196,9 @@ public:
|
|||
void Remove(std::shared_ptr<TaskType> const & task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_tasks.erase(
|
||||
std::remove_if(m_tasks.begin(), m_tasks.end(),
|
||||
[task](ActiveTask const & t) { return t.m_task == task; }),
|
||||
m_tasks.end());
|
||||
m_tasks.erase(std::remove_if(m_tasks.begin(), m_tasks.end(),
|
||||
[task](ActiveTask const & t) { return t.m_task == task; }),
|
||||
m_tasks.end());
|
||||
}
|
||||
|
||||
void FinishAll()
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
void RenderRange(ref_ptr<GraphicsContext> context, bool drawAsLine,
|
||||
IndicesRange const & range) override
|
||||
{
|
||||
CHECK(m_vertexArrayBuffer->HasBuffers(), ());
|
||||
|
||||
ref_ptr<dp::metal::MetalBaseContext> metalContext = context;
|
||||
if (!metalContext->HasAppliedPipelineState())
|
||||
return;
|
||||
|
|
|
@ -180,7 +180,7 @@ void VertexArrayBuffer::Render(ref_ptr<GraphicsContext> context, bool drawAsLine
|
|||
void VertexArrayBuffer::RenderRange(ref_ptr<GraphicsContext> context,
|
||||
bool drawAsLine, IndicesRange const & range)
|
||||
{
|
||||
if (!(m_staticBuffers.empty() && m_dynamicBuffers.empty()) && GetIndexCount() > 0)
|
||||
if (HasBuffers() && GetIndexCount() > 0)
|
||||
{
|
||||
// If OES_vertex_array_object is supported than all bindings have already saved in VAO
|
||||
// and we need only bind VAO.
|
||||
|
@ -202,6 +202,9 @@ void VertexArrayBuffer::Build(ref_ptr<GraphicsContext> context, ref_ptr<GpuProgr
|
|||
if (m_moveToGpuOnBuild && !m_isPreflushed)
|
||||
PreflushImpl(context);
|
||||
|
||||
if (!HasBuffers())
|
||||
return;
|
||||
|
||||
if (!m_impl)
|
||||
{
|
||||
auto const apiVersion = context->GetApiVersion();
|
||||
|
@ -226,9 +229,7 @@ void VertexArrayBuffer::Build(ref_ptr<GraphicsContext> context, ref_ptr<GpuProgr
|
|||
}
|
||||
}
|
||||
|
||||
if (m_staticBuffers.empty())
|
||||
return;
|
||||
|
||||
CHECK(m_impl != nullptr, ());
|
||||
if (!m_impl->Build(program))
|
||||
return;
|
||||
|
||||
|
@ -408,13 +409,17 @@ void VertexArrayBuffer::ApplyMutation(ref_ptr<GraphicsContext> context,
|
|||
|
||||
bool VertexArrayBuffer::Bind() const
|
||||
{
|
||||
CHECK(m_impl != nullptr, ());
|
||||
if (m_impl == nullptr)
|
||||
return false;
|
||||
|
||||
return m_impl->Bind();
|
||||
}
|
||||
|
||||
void VertexArrayBuffer::Unbind() const
|
||||
{
|
||||
CHECK(m_impl != nullptr, ());
|
||||
if (m_impl == nullptr)
|
||||
return;
|
||||
|
||||
m_impl->Unbind();
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
|
||||
void ResetChangingTracking() { m_isChanged = false; }
|
||||
bool IsChanged() const { return m_isChanged; }
|
||||
bool HasBuffers() const { return !m_staticBuffers.empty() || !m_dynamicBuffers.empty(); }
|
||||
|
||||
private:
|
||||
ref_ptr<DataBuffer> GetOrCreateStaticBuffer(BindingInfo const & bindingInfo);
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
void RenderRange(ref_ptr<GraphicsContext> context, bool drawAsLine,
|
||||
IndicesRange const & range) override
|
||||
{
|
||||
CHECK(m_vertexArrayBuffer->HasBuffers(), ());
|
||||
|
||||
ref_ptr<dp::vulkan::VulkanBaseContext> vulkanContext = context;
|
||||
VkCommandBuffer commandBuffer = vulkanContext->GetCurrentRenderingCommandBuffer();
|
||||
CHECK(commandBuffer != nullptr, ());
|
||||
|
|
|
@ -134,7 +134,7 @@ DrapeEngine::~DrapeEngine()
|
|||
m_glyphGenerator.reset();
|
||||
}
|
||||
|
||||
void DrapeEngine::Update(int w, int h)
|
||||
void DrapeEngine::RecoverSurface(int w, int h, bool recreateContextDependentResources)
|
||||
{
|
||||
if (m_choosePositionMode)
|
||||
{
|
||||
|
@ -142,13 +142,15 @@ void DrapeEngine::Update(int w, int h)
|
|||
make_unique_dp<ShowChoosePositionMarkMessage>(),
|
||||
MessagePriority::Normal);
|
||||
}
|
||||
RecacheGui(false);
|
||||
|
||||
RecacheMapShapes();
|
||||
|
||||
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread,
|
||||
make_unique_dp<RecoverGLResourcesMessage>(),
|
||||
MessagePriority::Normal);
|
||||
if (recreateContextDependentResources)
|
||||
{
|
||||
RecacheGui(false);
|
||||
RecacheMapShapes();
|
||||
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread,
|
||||
make_unique_dp<RecoverContextDependentResourcesMessage>(),
|
||||
MessagePriority::Normal);
|
||||
}
|
||||
|
||||
ResizeImpl(w, h);
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
DrapeEngine(Params && params);
|
||||
~DrapeEngine();
|
||||
|
||||
void Update(int w, int h);
|
||||
void RecoverSurface(int w, int h, bool recreateContextDependentResources);
|
||||
|
||||
void Resize(int w, int h);
|
||||
void Invalidate();
|
||||
|
|
|
@ -474,8 +474,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
{
|
||||
m_routeRenderer->UpdateDistanceFromBegin(info.GetDistanceFromBegin());
|
||||
// Here we have to recache route arrows.
|
||||
m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(),
|
||||
std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2));
|
||||
m_routeRenderer->PrepareRouteArrows(m_userEventStream.GetCurrentScreen(),
|
||||
std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2));
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -514,8 +514,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
m_routeRenderer->AddSubrouteData(m_context, std::move(subrouteData), make_ref(m_gpuProgramManager));
|
||||
|
||||
// Here we have to recache route arrows.
|
||||
m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(),
|
||||
std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2));
|
||||
m_routeRenderer->PrepareRouteArrows(m_userEventStream.GetCurrentScreen(),
|
||||
std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2));
|
||||
|
||||
if (m_pendingFollowRoute != nullptr)
|
||||
{
|
||||
|
@ -642,9 +642,18 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
break;
|
||||
}
|
||||
|
||||
case Message::Type::RecoverGLResources:
|
||||
case Message::Type::PrepareSubrouteArrows:
|
||||
{
|
||||
UpdateGLResources();
|
||||
ref_ptr<PrepareSubrouteArrowsMessage> msg = message;
|
||||
m_routeRenderer->CacheRouteArrows(m_userEventStream.GetCurrentScreen(),
|
||||
msg->GetSubrouteId(), msg->AcceptBorders(),
|
||||
std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2));
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::Type::RecoverContextDependentResources:
|
||||
{
|
||||
UpdateContextDependentResources();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -683,7 +692,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
blocker.Wait();
|
||||
}
|
||||
|
||||
UpdateGLResources();
|
||||
UpdateContextDependentResources();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -996,7 +1005,7 @@ unique_ptr<threads::IRoutine> FrontendRenderer::CreateRoutine()
|
|||
return make_unique<Routine>(*this);
|
||||
}
|
||||
|
||||
void FrontendRenderer::UpdateGLResources()
|
||||
void FrontendRenderer::UpdateContextDependentResources()
|
||||
{
|
||||
++m_lastRecacheRouteId;
|
||||
|
||||
|
@ -1011,7 +1020,7 @@ void FrontendRenderer::UpdateGLResources()
|
|||
|
||||
m_trafficRenderer->ClearContextDependentResources();
|
||||
|
||||
// In some cases UpdateGLResources can be called before the rendering of
|
||||
// In some cases UpdateContextDependentResources can be called before the rendering of
|
||||
// the first frame. m_currentZoomLevel will be equal to -1, so ResolveTileKeys
|
||||
// could not be called.
|
||||
if (m_currentZoomLevel > 0)
|
||||
|
@ -2406,7 +2415,7 @@ void FrontendRenderer::PrepareScene(ScreenBase const & modelView)
|
|||
RefreshPivotTransform(modelView);
|
||||
|
||||
m_myPositionController->OnUpdateScreen(modelView);
|
||||
m_routeRenderer->UpdateRoute(modelView, std::bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2));
|
||||
m_routeRenderer->PrepareRouteArrows(modelView, std::bind(&FrontendRenderer::OnPrepareRouteArrows, this, _1, _2));
|
||||
}
|
||||
|
||||
void FrontendRenderer::UpdateScene(ScreenBase const & modelView)
|
||||
|
@ -2448,10 +2457,17 @@ void FrontendRenderer::EmitModelViewChanged(ScreenBase const & modelView) const
|
|||
m_modelViewChangedFn(modelView);
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnCacheRouteArrows(int routeIndex, std::vector<ArrowBorders> const & borders)
|
||||
void FrontendRenderer::OnPrepareRouteArrows(dp::DrapeID subrouteIndex, std::vector<ArrowBorders> && borders)
|
||||
{
|
||||
m_commutator->PostMessage(ThreadsCommutator::RenderThread,
|
||||
make_unique_dp<PrepareSubrouteArrowsMessage>(subrouteIndex, std::move(borders)),
|
||||
MessagePriority::Normal);
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnCacheRouteArrows(dp::DrapeID subrouteIndex, std::vector<ArrowBorders> const & borders)
|
||||
{
|
||||
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
|
||||
make_unique_dp<CacheSubrouteArrowsMessage>(routeIndex, borders, m_lastRecacheRouteId),
|
||||
make_unique_dp<CacheSubrouteArrowsMessage>(subrouteIndex, borders, m_lastRecacheRouteId),
|
||||
MessagePriority::Normal);
|
||||
}
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ private:
|
|||
};
|
||||
|
||||
void ReleaseResources();
|
||||
void UpdateGLResources();
|
||||
void UpdateContextDependentResources();
|
||||
|
||||
void BeginUpdateOverlayTree(ScreenBase const & modelView);
|
||||
void UpdateOverlayTree(ScreenBase const & modelView, drape_ptr<RenderGroup> & renderGroup);
|
||||
|
@ -255,7 +255,8 @@ private:
|
|||
|
||||
void ProcessSelection(ref_ptr<SelectObjectMessage> msg);
|
||||
|
||||
void OnCacheRouteArrows(int routeIndex, std::vector<ArrowBorders> const & borders);
|
||||
void OnPrepareRouteArrows(dp::DrapeID subrouteIndex, std::vector<ArrowBorders> && borders);
|
||||
void OnCacheRouteArrows(dp::DrapeID subrouteIndex, std::vector<ArrowBorders> const & borders);
|
||||
|
||||
void CollectShowOverlaysEvents();
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ std::string DebugPrint(Message::Type msgType)
|
|||
case Message::Type::SelectObject: return "SelectObject";
|
||||
case Message::Type::AddSubroute: return "AddSubroute";
|
||||
case Message::Type::RemoveSubroute: return "RemoveSubroute";
|
||||
case Message::Type::PrepareSubrouteArrows: return "PrepareSubrouteArrows";
|
||||
case Message::Type::CacheSubrouteArrows: return "CacheSubrouteArrows";
|
||||
case Message::Type::FlushSubroute: return "FlushSubroute";
|
||||
case Message::Type::FlushSubrouteArrows: return "FlushSubrouteArrows";
|
||||
|
@ -64,7 +65,7 @@ std::string DebugPrint(Message::Type msgType)
|
|||
case Message::Type::SetDisplacementMode: return "SetDisplacementMode";
|
||||
case Message::Type::AllowAutoZoom: return "AllowAutoZoom";
|
||||
case Message::Type::RequestSymbolsSize: return "RequestSymbolsSize";
|
||||
case Message::Type::RecoverGLResources: return "RecoverGLResources";
|
||||
case Message::Type::RecoverContextDependentResources: return "RecoverContextDependentResources";
|
||||
case Message::Type::SetVisibleViewport: return "SetVisibleViewport";
|
||||
case Message::Type::EnableTraffic: return "EnableTraffic";
|
||||
case Message::Type::FlushTrafficGeometry: return "FlushTrafficGeometry";
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
SelectObject,
|
||||
AddSubroute,
|
||||
RemoveSubroute,
|
||||
PrepareSubrouteArrows,
|
||||
CacheSubrouteArrows,
|
||||
FlushSubroute,
|
||||
FlushSubrouteArrows,
|
||||
|
@ -65,7 +66,7 @@ public:
|
|||
SetDisplacementMode,
|
||||
AllowAutoZoom,
|
||||
RequestSymbolsSize,
|
||||
RecoverGLResources,
|
||||
RecoverContextDependentResources,
|
||||
SetVisibleViewport,
|
||||
EnableTraffic,
|
||||
FlushTrafficGeometry,
|
||||
|
|
|
@ -561,6 +561,24 @@ private:
|
|||
int const m_recacheId;
|
||||
};
|
||||
|
||||
class PrepareSubrouteArrowsMessage : public Message
|
||||
{
|
||||
public:
|
||||
PrepareSubrouteArrowsMessage(dp::DrapeID subrouteId,
|
||||
std::vector<ArrowBorders> && borders)
|
||||
: m_subrouteId(subrouteId)
|
||||
, m_borders(std::move(borders))
|
||||
{}
|
||||
|
||||
Type GetType() const override { return Type::PrepareSubrouteArrows; }
|
||||
dp::DrapeID GetSubrouteId() const { return m_subrouteId; }
|
||||
std::vector<ArrowBorders> && AcceptBorders() { return std::move(m_borders); }
|
||||
|
||||
private:
|
||||
dp::DrapeID m_subrouteId;
|
||||
std::vector<ArrowBorders> m_borders;
|
||||
};
|
||||
|
||||
class CacheSubrouteArrowsMessage : public Message
|
||||
{
|
||||
public:
|
||||
|
@ -711,10 +729,10 @@ public:
|
|||
Type GetType() const override { return Type::Invalidate; }
|
||||
};
|
||||
|
||||
class RecoverGLResourcesMessage : public Message
|
||||
class RecoverContextDependentResourcesMessage : public Message
|
||||
{
|
||||
public:
|
||||
Type GetType() const override { return Type::RecoverGLResources; }
|
||||
Type GetType() const override { return Type::RecoverContextDependentResources; }
|
||||
bool IsGraphicsContextDependent() const override { return true; }
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "shaders/programs.hpp"
|
||||
|
||||
#include "drape/drape_routine.hpp"
|
||||
#include "drape/glsl_func.hpp"
|
||||
#include "drape/utils/projection.hpp"
|
||||
#include "drape/vertex_array_buffer.hpp"
|
||||
|
@ -145,17 +146,17 @@ bool AreEqualArrowBorders(std::vector<ArrowBorders> const & borders1,
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<ArrowBorders> CalculateArrowBorders(ScreenBase const & screen, float currentHalfWidth,
|
||||
RouteRenderer::SubrouteInfo const & subrouteInfo,
|
||||
double distanceFromBegin)
|
||||
std::vector<ArrowBorders> CalculateArrowBorders(m2::RectD screenRect, double screenScale,
|
||||
float currentHalfWidth, SubrouteConstPtr const & subroute,
|
||||
double subrouteLength, double distanceFromBegin)
|
||||
{
|
||||
auto const & turns = subrouteInfo.m_subroute->m_turns;
|
||||
auto const & turns = subroute->m_turns;
|
||||
if (turns.empty())
|
||||
return {};
|
||||
|
||||
// Calculate arrow mercator length.
|
||||
double glbHalfLen = 0.5 * kArrowSize;
|
||||
double const glbHalfTextureWidth = currentHalfWidth * kArrowHeightFactor * screen.GetScale();
|
||||
double const glbHalfTextureWidth = currentHalfWidth * kArrowHeightFactor * screenScale;
|
||||
double const glbHalfTextureLen = glbHalfTextureWidth * kArrowAspect;
|
||||
if (glbHalfLen < glbHalfTextureLen)
|
||||
glbHalfLen = glbHalfTextureLen;
|
||||
|
@ -164,20 +165,20 @@ std::vector<ArrowBorders> CalculateArrowBorders(ScreenBase const & screen, float
|
|||
double const glbArrowTail = 2.0 * kArrowTailSize * glbHalfTextureLen;
|
||||
double const glbMinArrowSize = glbArrowHead + glbArrowTail;
|
||||
|
||||
double const kExtendCoef = 1.1;
|
||||
m2::RectD screenRect = screen.ClipRect();
|
||||
screenRect.Scale(kExtendCoef);
|
||||
double constexpr kExtentCoef = 1.1;
|
||||
screenRect.Scale(kExtentCoef);
|
||||
|
||||
// Calculate arrow borders.
|
||||
size_t constexpr kAverageArrowsCount = 10;
|
||||
std::vector<ArrowBorders> newArrowBorders;
|
||||
newArrowBorders.reserve(turns.size());
|
||||
auto const & polyline = subrouteInfo.m_subroute->m_polyline;
|
||||
newArrowBorders.reserve(kAverageArrowsCount);
|
||||
auto const & polyline = subroute->m_polyline;
|
||||
for (size_t i = 0; i < turns.size(); i++)
|
||||
{
|
||||
ArrowBorders arrowBorders;
|
||||
arrowBorders.m_groupIndex = static_cast<int>(i);
|
||||
arrowBorders.m_startDistance = std::max(0.0, turns[i] - glbHalfLen * 0.8);
|
||||
arrowBorders.m_endDistance = std::min(subrouteInfo.m_length, turns[i] + glbHalfLen * 1.2);
|
||||
arrowBorders.m_endDistance = std::min(subrouteLength, turns[i] + glbHalfLen * 1.2);
|
||||
|
||||
if ((arrowBorders.m_endDistance - arrowBorders.m_startDistance) < glbMinArrowSize ||
|
||||
arrowBorders.m_startDistance < distanceFromBegin)
|
||||
|
@ -248,9 +249,9 @@ RouteRenderer::RouteRenderer(PreviewPointsRequestCallback && previewPointsReques
|
|||
ASSERT(m_previewPointsRequest != nullptr, ());
|
||||
}
|
||||
|
||||
void RouteRenderer::UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback)
|
||||
void RouteRenderer::PrepareRouteArrows(ScreenBase const & screen,
|
||||
PrepareRouteArrowsCallback const & prepareCallback)
|
||||
{
|
||||
ASSERT(callback != nullptr, ());
|
||||
for (auto & subrouteInfo : m_subroutes)
|
||||
{
|
||||
// Interpolate values by zoom level.
|
||||
|
@ -270,18 +271,49 @@ void RouteRenderer::UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallb
|
|||
double dist = kInvalidDistance;
|
||||
if (m_followingEnabled)
|
||||
dist = m_distanceFromBegin - subrouteInfo.m_subroute->m_baseDistance;
|
||||
auto newArrowBorders = CalculateArrowBorders(screen, halfWidth, subrouteInfo, dist);
|
||||
if (newArrowBorders.empty())
|
||||
|
||||
// We run asynchronous task to calculate new positions of route arrows.
|
||||
auto const subrouteId = subrouteInfo.m_subrouteId;
|
||||
auto const screenRect = screen.ClipRect();
|
||||
auto const screenScale = screen.GetScale();
|
||||
auto const subrouteLength = subrouteInfo.m_length;
|
||||
auto subroute = subrouteInfo.m_subroute;
|
||||
dp::DrapeRoutine::RunSequential([subrouteId, screenRect, screenScale, halfWidth,
|
||||
subroute = std::move(subroute), subrouteLength,
|
||||
dist, prepareCallback]()
|
||||
{
|
||||
// Clear arrows.
|
||||
subrouteInfo.m_arrowsData.reset();
|
||||
subrouteInfo.m_arrowBorders.clear();
|
||||
}
|
||||
else if (!AreEqualArrowBorders(newArrowBorders, subrouteInfo.m_arrowBorders))
|
||||
{
|
||||
subrouteInfo.m_arrowBorders = std::move(newArrowBorders);
|
||||
callback(subrouteInfo.m_subrouteId, subrouteInfo.m_arrowBorders);
|
||||
}
|
||||
ASSERT(prepareCallback != nullptr, ());
|
||||
prepareCallback(subrouteId, CalculateArrowBorders(screenRect, screenScale, halfWidth,
|
||||
subroute, subrouteLength, dist));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RouteRenderer::CacheRouteArrows(ScreenBase const & screen, dp::DrapeID subrouteId,
|
||||
std::vector<ArrowBorders> && arrowBorders,
|
||||
CacheRouteArrowsCallback const & cacheCallback)
|
||||
{
|
||||
ASSERT(cacheCallback != nullptr, ());
|
||||
auto const it = FindSubroute(m_subroutes, subrouteId);
|
||||
if (it == m_subroutes.end())
|
||||
return;
|
||||
|
||||
auto & subrouteInfo = *it;
|
||||
|
||||
double zoom = 0.0;
|
||||
float halfWidth = 0.0;
|
||||
InterpolateByZoom(subrouteInfo.m_subroute, screen, halfWidth, zoom);
|
||||
|
||||
if (arrowBorders.empty() || zoom < kArrowAppearingZoomLevel)
|
||||
{
|
||||
// Clear arrows.
|
||||
subrouteInfo.m_arrowsData.reset();
|
||||
subrouteInfo.m_arrowBorders.clear();
|
||||
}
|
||||
else if (!AreEqualArrowBorders(arrowBorders, subrouteInfo.m_arrowBorders))
|
||||
{
|
||||
subrouteInfo.m_arrowBorders = std::move(arrowBorders);
|
||||
cacheCallback(subrouteInfo.m_subrouteId, subrouteInfo.m_arrowBorders);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,8 +467,14 @@ void RouteRenderer::RenderSubroute(ref_ptr<dp::GraphicsContext> context, ref_ptr
|
|||
mng->GetParamsSetter()->Apply(context, prg, params);
|
||||
|
||||
// Render buckets.
|
||||
for (auto const & bucket : subrouteData->m_renderProperty.m_buckets)
|
||||
bucket->Render(context, state.GetDrawAsLine());
|
||||
auto const & clipRect = screen.ClipRect();
|
||||
CHECK_EQUAL(subrouteData->m_renderProperty.m_buckets.size(),
|
||||
subrouteData->m_renderProperty.m_boundingBoxes.size(), ());
|
||||
for (size_t i = 0; i < subrouteData->m_renderProperty.m_buckets.size(); ++i)
|
||||
{
|
||||
if (subrouteData->m_renderProperty.m_boundingBoxes[i].IsIntersect(clipRect))
|
||||
subrouteData->m_renderProperty.m_buckets[i]->Render(context, state.GetDrawAsLine());
|
||||
}
|
||||
}
|
||||
|
||||
void RouteRenderer::RenderSubrouteArrows(ref_ptr<dp::GraphicsContext> context, ref_ptr<gpu::ProgramManager> mng,
|
||||
|
@ -470,8 +508,15 @@ void RouteRenderer::RenderSubrouteArrows(ref_ptr<dp::GraphicsContext> context, r
|
|||
prg->Bind();
|
||||
dp::ApplyState(context, prg, state);
|
||||
mng->GetParamsSetter()->Apply(context, prg, params);
|
||||
for (auto const & bucket : subrouteInfo.m_arrowsData->m_renderProperty.m_buckets)
|
||||
bucket->Render(context, state.GetDrawAsLine());
|
||||
|
||||
auto const & clipRect = screen.ClipRect();
|
||||
CHECK_EQUAL(subrouteInfo.m_arrowsData->m_renderProperty.m_buckets.size(),
|
||||
subrouteInfo.m_arrowsData->m_renderProperty.m_boundingBoxes.size(), ());
|
||||
for (size_t i = 0; i < subrouteInfo.m_arrowsData->m_renderProperty.m_buckets.size(); ++i)
|
||||
{
|
||||
if (subrouteInfo.m_arrowsData->m_renderProperty.m_boundingBoxes[i].IsIntersect(clipRect))
|
||||
subrouteInfo.m_arrowsData->m_renderProperty.m_buckets[i]->Render(context, state.GetDrawAsLine());
|
||||
}
|
||||
}
|
||||
|
||||
void RouteRenderer::RenderSubrouteMarkers(ref_ptr<dp::GraphicsContext> context, ref_ptr<gpu::ProgramManager> mng,
|
||||
|
|
|
@ -29,6 +29,7 @@ extern std::string const kTransitStopInnerMarkerColor;
|
|||
class RouteRenderer final
|
||||
{
|
||||
public:
|
||||
using PrepareRouteArrowsCallback = std::function<void(dp::DrapeID, std::vector<ArrowBorders> &&)>;
|
||||
using CacheRouteArrowsCallback = std::function<void(dp::DrapeID, std::vector<ArrowBorders> const &)>;
|
||||
using PreviewPointsRequestCallback = std::function<void(uint32_t)>;
|
||||
|
||||
|
@ -55,7 +56,10 @@ public:
|
|||
|
||||
explicit RouteRenderer(PreviewPointsRequestCallback && previewPointsRequest);
|
||||
|
||||
void UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback);
|
||||
void PrepareRouteArrows(ScreenBase const & screen, PrepareRouteArrowsCallback const & prepareCallback);
|
||||
void CacheRouteArrows(ScreenBase const & screen, dp::DrapeID subrouteId,
|
||||
std::vector<ArrowBorders> && arrowBorders,
|
||||
CacheRouteArrowsCallback const & cacheCallback);
|
||||
|
||||
void RenderRoute(ref_ptr<dp::GraphicsContext> context, ref_ptr<gpu::ProgramManager> mng,
|
||||
ScreenBase const & screen, bool trafficShown, FrameValues const & frameValues);
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
#include "drape/glsl_types.hpp"
|
||||
#include "drape/texture_manager.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/math.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
@ -116,7 +119,7 @@ float SideByNormal(glsl::vec2 const & normal, bool isLeft)
|
|||
|
||||
void GenerateJoinsTriangles(glsl::vec3 const & pivot, std::vector<glsl::vec2> const & normals,
|
||||
glsl::vec4 const & color, glsl::vec2 const & length, bool isLeft,
|
||||
RouteShape::TGeometryBuffer & joinsGeometry)
|
||||
RouteShape::GeometryBuffer & joinsGeometry)
|
||||
{
|
||||
size_t const trianglesCount = normals.size() / 3;
|
||||
for (size_t j = 0; j < trianglesCount; j++)
|
||||
|
@ -125,9 +128,9 @@ void GenerateJoinsTriangles(glsl::vec3 const & pivot, std::vector<glsl::vec2> co
|
|||
glsl::vec3 const len2 = glsl::vec3(length.x, length.y, SideByNormal(normals[3 * j + 1], isLeft));
|
||||
glsl::vec3 const len3 = glsl::vec3(length.x, length.y, SideByNormal(normals[3 * j + 2], isLeft));
|
||||
|
||||
joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j], len1, color));
|
||||
joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j + 1], len2, color));
|
||||
joinsGeometry.push_back(RouteShape::RV(pivot, normals[3 * j + 2], len3, color));
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j], len1, color);
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j + 1], len2, color);
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j + 2], len3, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,17 +147,17 @@ glsl::vec2 GetUV(m2::RectF const & texRect, glsl::vec2 const & uv)
|
|||
|
||||
void GenerateArrowsTriangles(glsl::vec4 const & pivot, std::vector<glsl::vec2> const & normals,
|
||||
m2::RectF const & texRect, std::vector<glsl::vec2> const & uv,
|
||||
bool normalizedUV, RouteShape::TArrowGeometryBuffer & joinsGeometry)
|
||||
bool normalizedUV, RouteShape::ArrowGeometryBuffer & joinsGeometry)
|
||||
{
|
||||
size_t const trianglesCount = normals.size() / 3;
|
||||
for (size_t j = 0; j < trianglesCount; j++)
|
||||
{
|
||||
joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j]) : uv[3 * j]));
|
||||
joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j + 1],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j + 1]) : uv[3 * j + 1]));
|
||||
joinsGeometry.push_back(RouteShape::AV(pivot, normals[3 * j + 2],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j + 2]) : uv[3 * j + 2]));
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j]) : uv[3 * j]);
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j + 1],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j + 1]) : uv[3 * j + 1]);
|
||||
joinsGeometry.emplace_back(pivot, normals[3 * j + 2],
|
||||
normalizedUV ? GetUV(texRect, uv[3 * j + 2]) : uv[3 * j + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +181,7 @@ void Subroute::AddStyle(SubrouteStyle const & style)
|
|||
|
||||
void RouteShape::PrepareGeometry(std::vector<m2::PointD> const & path, m2::PointD const & pivot,
|
||||
std::vector<glsl::vec4> const & segmentsColors, float baseDepth,
|
||||
TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry)
|
||||
std::vector<GeometryBufferData<GeometryBuffer>> & geometryBufferData)
|
||||
{
|
||||
ASSERT(path.size() > 1, ());
|
||||
|
||||
|
@ -195,13 +198,24 @@ void RouteShape::PrepareGeometry(std::vector<m2::PointD> const & path, m2::Point
|
|||
for (auto const & segment : segments)
|
||||
length += glsl::length(segment.m_points[EndPoint] - segment.m_points[StartPoint]);
|
||||
|
||||
geometryBufferData.emplace_back(GeometryBufferData<GeometryBuffer>());
|
||||
|
||||
uint32_t constexpr kMinVertices = 5000;
|
||||
double constexpr kMinExtent = MercatorBounds::kRangeX / (1 << 10);
|
||||
|
||||
float depth = baseDepth;
|
||||
float const depthStep = kRouteDepth / (1 + segments.size());
|
||||
for (auto i = static_cast<int>(segments.size() - 1); i >= 0; i--)
|
||||
{
|
||||
auto & geomBufferData = geometryBufferData.back();
|
||||
auto & geometry = geomBufferData.m_geometry;
|
||||
|
||||
UpdateNormals(&segments[i], (i > 0) ? &segments[i - 1] : nullptr,
|
||||
(i < static_cast<int>(segments.size()) - 1) ? &segments[i + 1] : nullptr);
|
||||
|
||||
geomBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[StartPoint]));
|
||||
geomBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[EndPoint]));
|
||||
|
||||
// Generate main geometry.
|
||||
m2::PointD const startPt = MapShape::ConvertToLocal(glsl::FromVec2(segments[i].m_points[StartPoint]),
|
||||
pivot, kShapeCoordScalar);
|
||||
|
@ -224,23 +238,25 @@ void RouteShape::PrepareGeometry(std::vector<m2::PointD> const & path, m2::Point
|
|||
float const projRightStart = -segments[i].m_rightWidthScalar[StartPoint].y;
|
||||
float const projRightEnd = segments[i].m_rightWidthScalar[EndPoint].y;
|
||||
|
||||
geometry.push_back(RV(startPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(startLength, 0, kCenter), segments[i].m_color));
|
||||
geometry.push_back(RV(startPivot, leftNormalStart,
|
||||
glsl::vec3(startLength, projLeftStart, kLeftSide), segments[i].m_color));
|
||||
geometry.push_back(RV(endPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(length, 0, kCenter), segments[i].m_color));
|
||||
geometry.push_back(RV(endPivot, leftNormalEnd,
|
||||
glsl::vec3(length, projLeftEnd, kLeftSide), segments[i].m_color));
|
||||
geometry.emplace_back(startPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(startLength, 0, kCenter), segments[i].m_color);
|
||||
geometry.emplace_back(startPivot, leftNormalStart,
|
||||
glsl::vec3(startLength, projLeftStart, kLeftSide), segments[i].m_color);
|
||||
geometry.emplace_back(endPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(length, 0, kCenter), segments[i].m_color);
|
||||
geometry.emplace_back(endPivot, leftNormalEnd,
|
||||
glsl::vec3(length, projLeftEnd, kLeftSide), segments[i].m_color);
|
||||
|
||||
geometry.push_back(RV(startPivot, rightNormalStart,
|
||||
glsl::vec3(startLength, projRightStart, kRightSide), segments[i].m_color));
|
||||
geometry.push_back(RV(startPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(startLength, 0, kCenter), segments[i].m_color));
|
||||
geometry.push_back(RV(endPivot, rightNormalEnd,
|
||||
glsl::vec3(length, projRightEnd, kRightSide), segments[i].m_color));
|
||||
geometry.push_back(RV(endPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(length, 0, kCenter), segments[i].m_color));
|
||||
geometry.emplace_back(startPivot, rightNormalStart,
|
||||
glsl::vec3(startLength, projRightStart, kRightSide), segments[i].m_color);
|
||||
geometry.emplace_back(startPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(startLength, 0, kCenter), segments[i].m_color);
|
||||
geometry.emplace_back(endPivot, rightNormalEnd,
|
||||
glsl::vec3(length, projRightEnd, kRightSide), segments[i].m_color);
|
||||
geometry.emplace_back(endPivot, glsl::vec2(0, 0),
|
||||
glsl::vec3(length, 0, kCenter), segments[i].m_color);
|
||||
|
||||
auto & joinsGeometry = geomBufferData.m_joinsGeometry;
|
||||
|
||||
// Generate joins.
|
||||
if (segments[i].m_generateJoin && i < static_cast<int>(segments.size()) - 1)
|
||||
|
@ -287,13 +303,18 @@ void RouteShape::PrepareGeometry(std::vector<m2::PointD> const & path, m2::Point
|
|||
true, joinsGeometry);
|
||||
}
|
||||
|
||||
auto const verticesCount = geomBufferData.m_geometry.size() + geomBufferData.m_joinsGeometry.size();
|
||||
auto const extent = std::max(geomBufferData.m_boundingBox.SizeX(), geomBufferData.m_boundingBox.SizeY());
|
||||
if (verticesCount > kMinVertices && extent > kMinExtent)
|
||||
geometryBufferData.emplace_back(GeometryBufferData<GeometryBuffer>());
|
||||
|
||||
length = startLength;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteShape::PrepareArrowGeometry(std::vector<m2::PointD> const & path, m2::PointD const & pivot,
|
||||
m2::RectF const & texRect, float depthStep, float depth,
|
||||
TArrowGeometryBuffer & geometry, TArrowGeometryBuffer & joinsGeometry)
|
||||
GeometryBufferData<ArrowGeometryBuffer> & geometryBufferData)
|
||||
{
|
||||
ASSERT(path.size() > 1, ());
|
||||
|
||||
|
@ -310,9 +331,14 @@ void RouteShape::PrepareArrowGeometry(std::vector<m2::PointD> const & path, m2::
|
|||
float const depthInc = depthStep / (segments.size() + 1);
|
||||
for (size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
auto & geometry = geometryBufferData.m_geometry;
|
||||
|
||||
UpdateNormals(&segments[i], (i > 0) ? &segments[i - 1] : nullptr,
|
||||
(i < segments.size() - 1) ? &segments[i + 1] : nullptr);
|
||||
|
||||
geometryBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[StartPoint]));
|
||||
geometryBufferData.m_boundingBox.Add(glsl::FromVec2(segments[i].m_points[EndPoint]));
|
||||
|
||||
// Generate main geometry.
|
||||
m2::PointD const startPt = MapShape::ConvertToLocal(glsl::FromVec2(segments[i].m_points[StartPoint]),
|
||||
pivot, kShapeCoordScalar);
|
||||
|
@ -332,15 +358,17 @@ void RouteShape::PrepareArrowGeometry(std::vector<m2::PointD> const & path, m2::
|
|||
glsl::vec2 const uvLeft = GetUV(tr, 0.5f, 0.0f);
|
||||
glsl::vec2 const uvRight = GetUV(tr, 0.5f, 1.0f);
|
||||
|
||||
geometry.push_back(AV(startPivot, glsl::vec2(0, 0), uvCenter));
|
||||
geometry.push_back(AV(startPivot, leftNormalStart, uvLeft));
|
||||
geometry.push_back(AV(endPivot, glsl::vec2(0, 0), uvCenter));
|
||||
geometry.push_back(AV(endPivot, leftNormalEnd, uvLeft));
|
||||
geometry.emplace_back(startPivot, glsl::vec2(0, 0), uvCenter);
|
||||
geometry.emplace_back(startPivot, leftNormalStart, uvLeft);
|
||||
geometry.emplace_back(endPivot, glsl::vec2(0, 0), uvCenter);
|
||||
geometry.emplace_back(endPivot, leftNormalEnd, uvLeft);
|
||||
|
||||
geometry.push_back(AV(startPivot, rightNormalStart, uvRight));
|
||||
geometry.push_back(AV(startPivot, glsl::vec2(0, 0), uvCenter));
|
||||
geometry.push_back(AV(endPivot, rightNormalEnd, uvRight));
|
||||
geometry.push_back(AV(endPivot, glsl::vec2(0, 0), uvCenter));
|
||||
geometry.emplace_back(startPivot, rightNormalStart, uvRight);
|
||||
geometry.emplace_back(startPivot, glsl::vec2(0, 0), uvCenter);
|
||||
geometry.emplace_back(endPivot, rightNormalEnd, uvRight);
|
||||
geometry.emplace_back(endPivot, glsl::vec2(0, 0), uvCenter);
|
||||
|
||||
auto & joinsGeometry = geometryBufferData.m_joinsGeometry;
|
||||
|
||||
// Generate joins.
|
||||
if (segments[i].m_generateJoin && i < segments.size() - 1)
|
||||
|
@ -411,7 +439,7 @@ void RouteShape::PrepareArrowGeometry(std::vector<m2::PointD> const & path, m2::
|
|||
|
||||
void RouteShape::PrepareMarkersGeometry(std::vector<SubrouteMarker> const & markers,
|
||||
m2::PointD const & pivot, float baseDepth,
|
||||
TMarkersGeometryBuffer & geometry)
|
||||
MarkersGeometryBuffer & geometry)
|
||||
{
|
||||
ASSERT(!markers.empty(), ());
|
||||
|
||||
|
@ -488,8 +516,7 @@ void RouteShape::CacheRouteArrows(ref_ptr<dp::GraphicsContext> context,
|
|||
std::vector<ArrowBorders> const & borders, double baseDepthIndex,
|
||||
SubrouteArrowsData & routeArrowsData)
|
||||
{
|
||||
TArrowGeometryBuffer geometry;
|
||||
TArrowGeometryBuffer joinsGeometry;
|
||||
GeometryBufferData<ArrowGeometryBuffer> geometryData;
|
||||
dp::TextureManager::SymbolRegion region;
|
||||
GetArrowTextureRegion(mng, region);
|
||||
auto state = CreateRenderState(gpu::Program::RouteArrow, DepthLayer::GeometryLayer);
|
||||
|
@ -504,18 +531,23 @@ void RouteShape::CacheRouteArrows(ref_ptr<dp::GraphicsContext> context,
|
|||
std::vector<m2::PointD> points = CalculatePoints(polyline, b.m_startDistance, b.m_endDistance);
|
||||
ASSERT_LESS_OR_EQUAL(points.size(), polyline.GetSize(), ());
|
||||
PrepareArrowGeometry(points, routeArrowsData.m_pivot, region.GetTexRect(), depthStep,
|
||||
depth, geometry, joinsGeometry);
|
||||
depth, geometryData);
|
||||
}
|
||||
|
||||
BatchGeometry(context, state, make_ref(geometry.data()), static_cast<uint32_t>(geometry.size()),
|
||||
make_ref(joinsGeometry.data()), static_cast<uint32_t>(joinsGeometry.size()),
|
||||
AV::GetBindingInfo(), routeArrowsData.m_renderProperty);
|
||||
double constexpr kBoundingBoxScale = 1.2;
|
||||
geometryData.m_boundingBox.Scale(kBoundingBoxScale);
|
||||
|
||||
BatchGeometry(context, state, make_ref(geometryData.m_geometry.data()),
|
||||
static_cast<uint32_t>(geometryData.m_geometry.size()),
|
||||
make_ref(geometryData.m_joinsGeometry.data()),
|
||||
static_cast<uint32_t>(geometryData.m_joinsGeometry.size()),
|
||||
geometryData.m_boundingBox, AV::GetBindingInfo(),
|
||||
routeArrowsData.m_renderProperty);
|
||||
}
|
||||
|
||||
drape_ptr<df::SubrouteData> RouteShape::CacheRoute(ref_ptr<dp::GraphicsContext> context,
|
||||
dp::DrapeID subrouteId,
|
||||
SubrouteConstPtr subroute, size_t styleIndex,
|
||||
int recacheId,
|
||||
dp::DrapeID subrouteId, SubrouteConstPtr subroute,
|
||||
size_t styleIndex, int recacheId,
|
||||
ref_ptr<dp::TextureManager> textures)
|
||||
{
|
||||
size_t startIndex;
|
||||
|
@ -565,28 +597,34 @@ drape_ptr<df::SubrouteData> RouteShape::CacheRoute(ref_ptr<dp::GraphicsContext>
|
|||
subrouteData->m_recacheId = recacheId;
|
||||
subrouteData->m_distanceOffset = subroute->m_polyline.GetLength(startIndex);
|
||||
|
||||
TGeometryBuffer geometry;
|
||||
TGeometryBuffer joinsGeometry;
|
||||
std::vector<GeometryBufferData<GeometryBuffer>> geometryBufferData;
|
||||
PrepareGeometry(points, subrouteData->m_pivot, segmentsColors,
|
||||
static_cast<float>(subroute->m_baseDepthIndex * kDepthPerSubroute),
|
||||
geometry, joinsGeometry);
|
||||
geometryBufferData);
|
||||
|
||||
auto state = CreateRenderState(subroute->m_style[styleIndex].m_pattern.m_isDashed ?
|
||||
gpu::Program::RouteDash : gpu::Program::Route, DepthLayer::GeometryLayer);
|
||||
state.SetColorTexture(textures->GetSymbolsTexture());
|
||||
|
||||
BatchGeometry(context, state, make_ref(geometry.data()), static_cast<uint32_t>(geometry.size()),
|
||||
make_ref(joinsGeometry.data()), static_cast<uint32_t>(joinsGeometry.size()),
|
||||
RV::GetBindingInfo(), subrouteData->m_renderProperty);
|
||||
double constexpr kBoundingBoxScale = 1.2;
|
||||
for (auto & data : geometryBufferData)
|
||||
{
|
||||
data.m_boundingBox.Scale(kBoundingBoxScale);
|
||||
BatchGeometry(context, state, make_ref(data.m_geometry.data()),
|
||||
static_cast<uint32_t>(data.m_geometry.size()),
|
||||
make_ref(data.m_joinsGeometry.data()),
|
||||
static_cast<uint32_t>(data.m_joinsGeometry.size()),
|
||||
data.m_boundingBox, RV::GetBindingInfo(),
|
||||
subrouteData->m_renderProperty);
|
||||
}
|
||||
|
||||
|
||||
return subrouteData;
|
||||
}
|
||||
|
||||
drape_ptr<df::SubrouteMarkersData> RouteShape::CacheMarkers(ref_ptr<dp::GraphicsContext> context,
|
||||
dp::DrapeID subrouteId,
|
||||
SubrouteConstPtr subroute,
|
||||
int recacheId,
|
||||
ref_ptr<dp::TextureManager> textures)
|
||||
dp::DrapeID subrouteId, SubrouteConstPtr subroute,
|
||||
int recacheId, ref_ptr<dp::TextureManager> textures)
|
||||
{
|
||||
if (subroute->m_markers.empty())
|
||||
return nullptr;
|
||||
|
@ -596,7 +634,7 @@ drape_ptr<df::SubrouteMarkersData> RouteShape::CacheMarkers(ref_ptr<dp::Graphics
|
|||
markersData->m_pivot = subroute->m_polyline.GetLimitRect().Center();
|
||||
markersData->m_recacheId = recacheId;
|
||||
|
||||
TMarkersGeometryBuffer geometry;
|
||||
MarkersGeometryBuffer geometry;
|
||||
auto const depth = static_cast<float>(subroute->m_baseDepthIndex * kDepthPerSubroute + kMarkersDepth);
|
||||
PrepareMarkersGeometry(subroute->m_markers, markersData->m_pivot, depth, geometry);
|
||||
if (geometry.empty())
|
||||
|
@ -628,19 +666,27 @@ drape_ptr<df::SubrouteMarkersData> RouteShape::CacheMarkers(ref_ptr<dp::Graphics
|
|||
void RouteShape::BatchGeometry(ref_ptr<dp::GraphicsContext> context, dp::RenderState const & state,
|
||||
ref_ptr<void> geometry, uint32_t geomSize,
|
||||
ref_ptr<void> joinsGeometry, uint32_t joinsGeomSize,
|
||||
dp::BindingInfo const & bindingInfo, RouteRenderProperty & property)
|
||||
m2::RectD const & boundingBox, dp::BindingInfo const & bindingInfo,
|
||||
RouteRenderProperty & property)
|
||||
{
|
||||
size_t const verticesCount = geomSize + joinsGeomSize;
|
||||
auto verticesCount = geomSize + joinsGeomSize;
|
||||
if (verticesCount == 0)
|
||||
return;
|
||||
|
||||
uint32_t const kBatchSize = 5000;
|
||||
dp::Batcher batcher(kBatchSize, kBatchSize);
|
||||
uint32_t constexpr kMinBatchSize = 100;
|
||||
uint32_t constexpr kMaxBatchSize = 65000;
|
||||
uint32_t constexpr kIndicesScalar = 2;
|
||||
|
||||
verticesCount = base::clamp(verticesCount, kMinBatchSize, kMaxBatchSize);
|
||||
auto const indicesCount = base::clamp(verticesCount * kIndicesScalar, kMinBatchSize, kMaxBatchSize);
|
||||
|
||||
dp::Batcher batcher(indicesCount, verticesCount);
|
||||
batcher.SetBatcherHash(static_cast<uint64_t>(BatcherBucket::Routing));
|
||||
dp::SessionGuard guard(context, batcher, [&property](dp::RenderState const & state,
|
||||
drape_ptr<dp::RenderBucket> && b)
|
||||
dp::SessionGuard guard(context, batcher, [&property, &boundingBox](dp::RenderState const & state,
|
||||
drape_ptr<dp::RenderBucket> && b)
|
||||
{
|
||||
property.m_buckets.push_back(std::move(b));
|
||||
property.m_boundingBoxes.push_back(boundingBox);
|
||||
property.m_state = state;
|
||||
});
|
||||
|
||||
|
|
|
@ -50,10 +50,6 @@ enum class RouteType : uint8_t
|
|||
|
||||
struct RoutePattern
|
||||
{
|
||||
bool m_isDashed = false;
|
||||
double m_dashLength = 0.0;
|
||||
double m_gapLength = 0.0;
|
||||
|
||||
RoutePattern() = default;
|
||||
|
||||
RoutePattern(double dashLength, double gapLength)
|
||||
|
@ -69,6 +65,10 @@ struct RoutePattern
|
|||
std::fabs(m_dashLength - pattern.m_dashLength) < kEps &&
|
||||
std::fabs(m_gapLength - pattern.m_gapLength) < kEps;
|
||||
}
|
||||
|
||||
bool m_isDashed = false;
|
||||
double m_dashLength = 0.0;
|
||||
double m_gapLength = 0.0;
|
||||
};
|
||||
|
||||
enum class SubrouteStyleType
|
||||
|
@ -79,14 +79,8 @@ enum class SubrouteStyleType
|
|||
|
||||
struct SubrouteStyle
|
||||
{
|
||||
df::ColorConstant m_color;
|
||||
df::ColorConstant m_outlineColor;
|
||||
df::RoutePattern m_pattern;
|
||||
size_t m_startIndex = 0;
|
||||
size_t m_endIndex = 0;
|
||||
|
||||
SubrouteStyle() = default;
|
||||
SubrouteStyle(df::ColorConstant const & color)
|
||||
explicit SubrouteStyle(df::ColorConstant const & color)
|
||||
: m_color(color)
|
||||
, m_outlineColor(color)
|
||||
{}
|
||||
|
@ -106,16 +100,19 @@ struct SubrouteStyle
|
|||
, m_pattern(pattern)
|
||||
{}
|
||||
|
||||
bool operator == (SubrouteStyle const & style) const
|
||||
bool operator==(SubrouteStyle const & style) const
|
||||
{
|
||||
return m_color == style.m_color && m_outlineColor == style.m_outlineColor &&
|
||||
m_pattern == style.m_pattern;
|
||||
}
|
||||
|
||||
bool operator != (SubrouteStyle const & style) const
|
||||
{
|
||||
return !operator == (style);
|
||||
}
|
||||
bool operator!=(SubrouteStyle const & style) const { return !operator==(style); }
|
||||
|
||||
df::ColorConstant m_color;
|
||||
df::ColorConstant m_outlineColor;
|
||||
df::RoutePattern m_pattern;
|
||||
size_t m_startIndex = 0;
|
||||
size_t m_endIndex = 0;
|
||||
};
|
||||
|
||||
// Colored circle on the subroute.
|
||||
|
@ -157,11 +154,13 @@ using SubrouteConstPtr = std::shared_ptr<Subroute const>;
|
|||
|
||||
struct RouteRenderProperty
|
||||
{
|
||||
dp::RenderState m_state;
|
||||
std::vector<drape_ptr<dp::RenderBucket>> m_buckets;
|
||||
RouteRenderProperty()
|
||||
: m_state(CreateRenderState(gpu::Program::Route, DepthLayer::GeometryLayer))
|
||||
{}
|
||||
|
||||
dp::RenderState m_state;
|
||||
std::vector<drape_ptr<dp::RenderBucket>> m_buckets;
|
||||
std::vector<m2::RectD> m_boundingBoxes;
|
||||
};
|
||||
|
||||
struct BaseSubrouteData
|
||||
|
@ -196,11 +195,11 @@ class RouteShape
|
|||
{
|
||||
public:
|
||||
using RV = gpu::RouteVertex;
|
||||
using TGeometryBuffer = buffer_vector<RV, 128>;
|
||||
using GeometryBuffer = buffer_vector<RV, 128>;
|
||||
using AV = gpu::SolidTexturingVertex;
|
||||
using TArrowGeometryBuffer = buffer_vector<AV, 128>;
|
||||
using ArrowGeometryBuffer = buffer_vector<AV, 128>;
|
||||
using MV = gpu::RouteMarkerVertex;
|
||||
using TMarkersGeometryBuffer = buffer_vector<MV, 32>;
|
||||
using MarkersGeometryBuffer = buffer_vector<MV, 32>;
|
||||
|
||||
static drape_ptr<df::SubrouteData> CacheRoute(ref_ptr<dp::GraphicsContext> context,
|
||||
dp::DrapeID subrouteId, SubrouteConstPtr subroute,
|
||||
|
@ -218,20 +217,30 @@ public:
|
|||
SubrouteArrowsData & routeArrowsData);
|
||||
|
||||
private:
|
||||
template<typename GeometryBufferType>
|
||||
struct GeometryBufferData
|
||||
{
|
||||
GeometryBufferData()
|
||||
: m_boundingBox(m2::RectD::GetEmptyRect())
|
||||
{}
|
||||
|
||||
GeometryBufferType m_geometry;
|
||||
GeometryBufferType m_joinsGeometry;
|
||||
m2::RectD m_boundingBox;
|
||||
};
|
||||
static void PrepareGeometry(std::vector<m2::PointD> const & path, m2::PointD const & pivot,
|
||||
std::vector<glsl::vec4> const & segmentsColors, float baseDepth,
|
||||
TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry);
|
||||
std::vector<GeometryBufferData<GeometryBuffer>> & geometryBufferData);
|
||||
static void PrepareArrowGeometry(std::vector<m2::PointD> const & path, m2::PointD const & pivot,
|
||||
m2::RectF const & texRect, float depthStep, float depth,
|
||||
TArrowGeometryBuffer & geometry,
|
||||
TArrowGeometryBuffer & joinsGeometry);
|
||||
GeometryBufferData<ArrowGeometryBuffer> & geometryBufferData);
|
||||
static void PrepareMarkersGeometry(std::vector<SubrouteMarker> const & markers,
|
||||
m2::PointD const & pivot, float baseDepth,
|
||||
TMarkersGeometryBuffer & geometry);
|
||||
MarkersGeometryBuffer & geometry);
|
||||
|
||||
static void BatchGeometry(ref_ptr<dp::GraphicsContext> context, dp::RenderState const & state,
|
||||
ref_ptr<void> geometry, uint32_t geomSize, ref_ptr<void> joinsGeometry,
|
||||
uint32_t joinsGeomSize, dp::BindingInfo const & bindingInfo,
|
||||
RouteRenderProperty & property);
|
||||
uint32_t joinsGeomSize, m2::RectD const & boundingBox,
|
||||
dp::BindingInfo const & bindingInfo, RouteRenderProperty & property);
|
||||
};
|
||||
} // namespace df
|
||||
|
|
|
@ -575,7 +575,7 @@ using namespace osm_auth_ios;
|
|||
if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103)
|
||||
{
|
||||
m2::PointU const size = ((EAGLView *)self.mapViewController.view).pixelSize;
|
||||
f.OnRecoverSurface(static_cast<int>(size.x), static_cast<int>(size.y));
|
||||
f.OnRecoverSurface(static_cast<int>(size.x), static_cast<int>(size.y), true /* recreateContextDependentResources */);
|
||||
}
|
||||
[MWMLocationManager applicationDidBecomeActive];
|
||||
[MWMSearch addCategoriesToSpotlight];
|
||||
|
|
|
@ -390,7 +390,8 @@ void Framework::Migrate(bool keepDownloaded)
|
|||
{
|
||||
m_drapeEngine->SetRenderingEnabled();
|
||||
OnRecoverSurface(m_currentModelView.PixelRectIn3d().SizeX(),
|
||||
m_currentModelView.PixelRectIn3d().SizeY());
|
||||
m_currentModelView.PixelRectIn3d().SizeY(),
|
||||
true /* recreateContextDependentResources */);
|
||||
}
|
||||
InvalidateRect(MercatorBounds::FullRect());
|
||||
}
|
||||
|
@ -1910,11 +1911,11 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::GraphicsContextFactory> contextFac
|
|||
benchmark::RunGraphicsBenchmark(this);
|
||||
}
|
||||
|
||||
void Framework::OnRecoverSurface(int width, int height)
|
||||
void Framework::OnRecoverSurface(int width, int height, bool recreateContextDependentResources)
|
||||
{
|
||||
if (m_drapeEngine)
|
||||
{
|
||||
m_drapeEngine->Update(width, height);
|
||||
m_drapeEngine->RecoverSurface(width, height, recreateContextDependentResources);
|
||||
|
||||
InvalidateUserMarks();
|
||||
|
||||
|
@ -2447,21 +2448,20 @@ df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & t
|
|||
}
|
||||
|
||||
FeatureID featureTapped = tapInfo.m_featureTapped;
|
||||
|
||||
if (!featureTapped.IsValid())
|
||||
featureTapped = FindBuildingAtPoint(tapInfo.m_mercator);
|
||||
|
||||
bool showMapSelection = false;
|
||||
if (featureTapped.IsValid())
|
||||
{
|
||||
FillFeatureInfo(featureTapped, outInfo);
|
||||
showMapSelection = true;
|
||||
}
|
||||
else if (tapInfo.m_isLong || tapEvent.m_source == TapEvent::Source::Search)
|
||||
if (tapInfo.m_isLong || tapEvent.m_source == TapEvent::Source::Search)
|
||||
{
|
||||
FillPointInfo(tapInfo.m_mercator, {} /* customTitle */, outInfo);
|
||||
showMapSelection = true;
|
||||
}
|
||||
else if (featureTapped.IsValid())
|
||||
{
|
||||
FillFeatureInfo(featureTapped, outInfo);
|
||||
showMapSelection = true;
|
||||
}
|
||||
|
||||
if (showMapSelection)
|
||||
{
|
||||
|
|
|
@ -510,7 +510,7 @@ public:
|
|||
void SetRenderingEnabled(ref_ptr<dp::GraphicsContextFactory> contextFactory = nullptr);
|
||||
void SetRenderingDisabled(bool destroySurface);
|
||||
|
||||
void OnRecoverSurface(int width, int height);
|
||||
void OnRecoverSurface(int width, int height, bool recreateContextDependentResources);
|
||||
void OnDestroySurface();
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,6 +19,10 @@ void main()
|
|||
pos.xyw = (pos * u_projection).xyw;
|
||||
pos.z = a_position.z * u_zScale;
|
||||
gl_Position = u_pivotTransform * pos;
|
||||
#ifdef VULKAN
|
||||
gl_Position.y = -gl_Position.y;
|
||||
gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VTF
|
||||
v_color = texture2D(u_colorTex, a_colorTexCoords);
|
||||
|
|
Loading…
Add table
Reference in a new issue