implemented PartialRenderPolicy for single threaded GUI-responsive rendering.

This commit is contained in:
rachytski 2011-11-03 17:58:15 +04:00 committed by Alex Zolotarev
parent fb96e2b77f
commit 097c92bfad
30 changed files with 994 additions and 288 deletions

View file

@ -13,6 +13,7 @@
#include "../../../../../indexer/drawing_rules.hpp"
#include "../../../../../map/render_policy_st.hpp"
#include "../../../../../map/partial_render_policy.hpp"
#include "../../../../../map/tiling_render_policy_st.hpp"
#include "../../../../../map/framework.hpp"
@ -87,6 +88,7 @@ namespace android
p.m_glyphCacheID = m_rm->guiThreadGlyphCacheID();
p.m_frameBuffer = make_shared_ptr(new yg::gl::FrameBuffer(true));
p.m_skinName = pl.SkinName();
p.m_useTinyStorage = true;
m_drawer = make_shared_ptr(new DrawerYG(p));
}
@ -115,7 +117,9 @@ namespace android
2 * 1024 * 1024,
1,
yg::Rt8Bpp,
false));
true));
m_rm->initTinyStorage(300 * sizeof(yg::gl::Vertex), 600 * sizeof(unsigned short), 30);
Platform::FilesList fonts;
pl.GetFontNames(fonts);
@ -129,7 +133,7 @@ namespace android
drule::rules().ForEachRule(make_all_invalid(GetPlatform().CpuCores() + 1));
// temporary workaround
m_work.SetRenderPolicy(shared_ptr<RenderPolicy>(new RenderPolicyST(m_handle, bind(&::Framework<model::FeaturesFetcher>::DrawModel, &m_work, _1, _2, _3, _4, _5, false))));
m_work.SetRenderPolicy(shared_ptr<RenderPolicy>(new PartialRenderPolicy(m_handle, bind(&::Framework<model::FeaturesFetcher>::DrawModel, &m_work, _1, _2, _3, _4, _5, false))));
m_rc = make_shared_ptr(new android::RenderContext());

View file

@ -104,7 +104,11 @@ public:
ResourcePool(TPoolTraits const & traits)
: m_traits(traits)
{}
{
/// quick trick to perform lazy initialization
/// on the same thread the pool was created.
Free(Reserve());
}
TElem const Reserve()
{

View file

@ -135,7 +135,7 @@
p.m_skinName = pl.SkinName();
p.m_visualScale = pl.VisualScale();
p.m_isSynchronized = false;
p.m_useTinyStorage = false; //< use tiny buffers to minimize CPU->GPU data transfer overhead.
p.m_useTinyStorage = true; //< use tiny buffers to minimize CPU->GPU data transfer overhead.
drawer = shared_ptr<DrawerYG>(new DrawerYG(p));

View file

@ -31,6 +31,14 @@
#include "../std/fstream.hpp"
#include "../std/target_os.hpp"
#include "render_policy_st.hpp"
#include "render_policy_mt.hpp"
#include "tiling_render_policy_st.hpp"
#include "tiling_render_policy_mt.hpp"
#include "partial_render_policy.hpp"
using namespace feature;
template <typename TModel>
@ -107,11 +115,11 @@ Framework<TModel>::Framework(shared_ptr<WindowHandle> windowHandle,
{
// on Android policy is created in AndroidFramework
#ifndef OMIM_OS_ANDROID
// SetRenderPolicy(make_shared_ptr(new RenderPolicyST(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5, false))));
// SetRenderPolicy(make_shared_ptr(new TilingRenderPolicyMT(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5, true))));
SetRenderPolicy(make_shared_ptr(new RenderPolicyMT(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5, false))));
m_navigator.SetSupportRotation(m_renderPolicy->DoSupportRotation());
// SetRenderPolicy(make_shared_ptr(new PartialRenderPolicy(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5, false))));
#endif
@ -672,6 +680,7 @@ template <typename TModel>
void Framework<TModel>::SetRenderPolicy(shared_ptr<RenderPolicy> const & renderPolicy)
{
m_renderPolicy = renderPolicy;
m_navigator.SetSupportRotation(m_renderPolicy->DoSupportRotation());
}
template <typename TModel>

View file

@ -40,6 +40,7 @@ HEADERS += \
benchmark_render_policy_mt.hpp \
ruler.hpp \
measurement_utils.hpp \
partial_render_policy.hpp
SOURCES += \
feature_vec_model.cpp \
@ -69,7 +70,8 @@ SOURCES += \
benchmark_render_policy_mt.cpp \
ruler.cpp \
measurement_utils.cpp \
window_handle.cpp
window_handle.cpp \
partial_render_policy.cpp
!iphone*:!bada*:!android* {
HEADERS += qgl_render_context.hpp
@ -80,3 +82,5 @@ SOURCES += \

View file

@ -0,0 +1,88 @@
#include "partial_render_policy.hpp"
#include "events.hpp"
#include "window_handle.hpp"
#include "drawer_yg.hpp"
#include "../yg/internal/opengl.hpp"
#include "../std/bind.hpp"
PartialRenderPolicy::PartialRenderPolicy(shared_ptr<WindowHandle> const & wh,
RenderPolicy::TRenderFn const & renderFn)
: RenderPolicyMT(wh, renderFn)
{
SetNeedSynchronize(true);
}
void PartialRenderPolicy::Initialize(shared_ptr<yg::gl::RenderContext> const & rc,
shared_ptr<yg::ResourceManager> const & rm)
{
m_renderQueue.SetGLQueue(&m_glQueue);
RenderPolicyMT::Initialize(rc, rm);
}
void PartialRenderPolicy::ProcessRenderQueue(list<yg::gl::Renderer::Packet> & renderQueue)
{
if (renderQueue.empty())
m_hasPacket = false;
else
{
m_hasPacket = true;
m_currentPacket = renderQueue.front();
renderQueue.pop_front();
}
}
void PartialRenderPolicy::DrawFrame(shared_ptr<PaintEvent> const & paintEvent,
ScreenBase const & screenBase)
{
/// blitting from the current surface onto screen
// RenderPolicyMT::DrawFrame(paintEvent, screenBase);
yg::gl::Screen * screen = paintEvent->drawer()->screen().get();
if (!m_state)
m_state = screen->createState();
screen->getState(m_state.get());
shared_ptr<yg::gl::Renderer::BaseState> curState = m_state;
unsigned cmdProcessed = 0;
unsigned const maxCmdPerFrame = 1000;
while (true)
{
m_glQueue.ProcessList(bind(&PartialRenderPolicy::ProcessRenderQueue, this, _1));
if ((m_hasPacket) && (cmdProcessed < maxCmdPerFrame))
{
cmdProcessed++;
m_currentPacket.m_state->apply(curState.get());
curState = m_currentPacket.m_state;
m_currentPacket.m_command->perform();
}
else
break;
}
/// should we continue drawing commands on the next frame
if ((cmdProcessed == maxCmdPerFrame) && m_hasPacket)
{
LOG(LINFO, ("will continue on the next frame"));
windowHandle()->invalidate();
}
else
LOG(LINFO, ("finished sequence of commands"));
// OGLCHECK(glFinish());
m_state->apply(curState.get());
// LOG(LINFO, (cmdProcessed, " commands processed"));
// OGLCHECK(glFinish());
/// blitting from the current surface onto screen
RenderPolicyMT::DrawFrame(paintEvent, screenBase);
// OGLCHECK(glFinish());
}

View file

@ -0,0 +1,32 @@
#pragma once
#include "render_policy_mt.hpp"
#include "../yg/screen.hpp"
#include "../base/threaded_list.hpp"
class WindowHandle;
class PartialRenderPolicy : public RenderPolicyMT
{
private:
ThreadedList<yg::gl::Renderer::Packet> m_glQueue;
yg::gl::Renderer::Packet m_currentPacket;
bool m_hasPacket;
shared_ptr<yg::gl::Renderer::BaseState> m_state;
void ProcessRenderQueue(list<yg::gl::Renderer::Packet> & renderQueue);
public:
PartialRenderPolicy(shared_ptr<WindowHandle> const & wh,
RenderPolicy::TRenderFn const & renderFn);
void Initialize(shared_ptr<yg::gl::RenderContext> const & rc,
shared_ptr<yg::ResourceManager> const & rm);
void DrawFrame(shared_ptr<PaintEvent> const & paintEvent,
ScreenBase const & screenBase);
};

View file

@ -22,11 +22,17 @@ RenderPolicyMT::RenderPolicyMT(shared_ptr<WindowHandle> const & wh,
GetPlatform().ScaleEtalonSize(),
GetPlatform().VisualScale(),
bgColor()),
m_DoAddCommand(true)
m_DoAddCommand(true),
m_DoSynchronize(true)
{
m_renderQueue.AddWindowHandle(wh);
}
void RenderPolicyMT::SetNeedSynchronize(bool flag)
{
m_DoSynchronize = flag;
}
void RenderPolicyMT::Initialize(shared_ptr<yg::gl::RenderContext> const & rc,
shared_ptr<yg::ResourceManager> const & rm)
{
@ -51,7 +57,8 @@ void RenderPolicyMT::BeginFrame(shared_ptr<PaintEvent> const & e,
void RenderPolicyMT::EndFrame(shared_ptr<PaintEvent> const & e,
ScreenBase const & s)
{
m_renderQueue.renderState().m_mutex->Unlock();
if (m_DoSynchronize)
m_renderQueue.renderState().m_mutex->Unlock();
}
void RenderPolicyMT::DrawFrame(shared_ptr<PaintEvent> const & e,
@ -64,7 +71,8 @@ void RenderPolicyMT::DrawFrame(shared_ptr<PaintEvent> const & e,
e->drawer()->screen()->clear(bgColor());
m_renderQueue.renderState().m_mutex->Lock();
if (m_DoSynchronize)
m_renderQueue.renderState().m_mutex->Lock();
if (m_renderQueue.renderState().m_actualTarget.get() != 0)
{

View file

@ -8,10 +8,11 @@ class WindowHandle;
class RenderPolicyMT : public RenderPolicy
{
private:
protected:
RenderQueue m_renderQueue;
bool m_DoAddCommand;
bool m_DoSynchronize;
public:
RenderPolicyMT(shared_ptr<WindowHandle> const & wh,
@ -38,5 +39,6 @@ public:
void StopScale();
RenderQueue & GetRenderQueue();
void SetNeedSynchronize(bool flag);
};

View file

@ -15,7 +15,8 @@ RenderQueue::RenderQueue(
double visualScale,
yg::Color const & bgColor
)
: m_renderState(new yg::gl::RenderState())
: m_renderState(new yg::gl::RenderState()),
m_hasPendingResize(false)
{
m_renderState->m_surfaceWidth = 100;
m_renderState->m_surfaceHeight = 100;
@ -41,7 +42,14 @@ void RenderQueue::initializeGL(shared_ptr<yg::gl::RenderContext> const & primary
m_resourceManager = resourceManager;
m_routine->initializeGL(primaryContext->createShared(),
m_resourceManager);
if (m_hasPendingResize)
{
m_routine->onSize(m_savedWidth, m_savedHeight);
m_hasPendingResize = false;
}
m_renderQueueThread.Create(m_routine);
}
RenderQueue::~RenderQueue()
@ -67,6 +75,14 @@ void RenderQueue::AddWindowHandle(shared_ptr<WindowHandle> const & windowHandle)
void RenderQueue::OnSize(size_t w, size_t h)
{
m_renderState->onSize(w, h);
if (!m_resourceManager)
{
m_hasPendingResize = true;
m_savedWidth = w;
m_savedHeight = h;
}
else
m_routine->onSize(w, h);
}
yg::gl::RenderState const RenderQueue::CopyState() const
@ -106,3 +122,8 @@ void RenderQueue::WaitForEmptyAndFinished()
m_routine->waitForEmptyAndFinished();
}
void RenderQueue::SetGLQueue(ThreadedList<yg::gl::Renderer::Packet> * glQueue)
{
m_routine->SetGLQueue(glQueue);
}

View file

@ -1,6 +1,8 @@
#pragma once
#include "../base/thread.hpp"
#include "../base/threaded_list.hpp"
#include "../yg/renderer.hpp"
#include "../geometry/screenbase.hpp"
#include "../std/shared_ptr.hpp"
#include "render_queue_routine.hpp"
@ -28,6 +30,9 @@ private:
shared_ptr<yg::gl::RenderState> m_renderState;
shared_ptr<yg::ResourceManager> m_resourceManager;
RenderQueueRoutine * m_routine;
bool m_hasPendingResize;
int m_savedWidth;
int m_savedHeight;
public:
/// constructor.
@ -71,4 +76,6 @@ public:
void enterForeground();
void WaitForEmptyAndFinished();
void SetGLQueue(ThreadedList<yg::gl::Renderer::Packet> * glQueue);
};

View file

@ -48,6 +48,7 @@ RenderQueueRoutine::RenderQueueRoutine(shared_ptr<yg::gl::RenderState> const & r
m_isBenchmarking = isBenchmarking;
m_scaleEtalonSize = scaleEtalonSize;
m_bgColor = bgColor;
m_glQueue = 0;
}
void RenderQueueRoutine::Cancel()
@ -60,6 +61,21 @@ void RenderQueueRoutine::Cancel()
m_currentRenderCommand->m_paintEvent->Cancel();
}
void RenderQueueRoutine::onSize(int w, int h)
{
size_t texW = m_renderState->m_textureWidth;
size_t texH = m_renderState->m_textureHeight;
m_newDepthBuffer.reset(new yg::gl::RenderBuffer(texW, texH, true));
m_newActualTarget = m_resourceManager->createRenderTarget(texW, texH);
m_newBackBufferLayers.clear();
m_newBackBufferLayers.resize(m_renderState->m_backBufferLayers.size());
for (unsigned i = 0; i < m_renderState->m_backBufferLayers.size(); ++i)
m_newBackBufferLayers[i] = m_resourceManager->createRenderTarget(texW, texH);
}
void RenderQueueRoutine::processResize(ScreenBase const & frameScreen)
{
if (m_renderState->m_isResized)
@ -67,21 +83,17 @@ void RenderQueueRoutine::processResize(ScreenBase const & frameScreen)
size_t texW = m_renderState->m_textureWidth;
size_t texH = m_renderState->m_textureHeight;
m_renderState->m_depthBuffer.reset();
if (!m_isMultiSampled)
{
m_renderState->m_depthBuffer = make_shared_ptr(new yg::gl::RenderBuffer(texW, texH, true));
m_threadDrawer->screen()->frameBuffer()->setDepthBuffer(m_renderState->m_depthBuffer);
}
m_threadDrawer->onSize(texW, texH);
m_threadDrawer->screen()->frameBuffer()->onSize(texW, texH);
m_renderState->m_depthBuffer = m_newDepthBuffer;
m_threadDrawer->screen()->setDepthBuffer(m_renderState->m_depthBuffer);
m_newDepthBuffer.reset();
shared_ptr<yg::gl::BaseTexture> oldActualTarget = m_renderState->m_actualTarget;
m_renderState->m_actualTarget.reset();
m_renderState->m_actualTarget = m_resourceManager->createRenderTarget(texW, texH);
m_renderState->m_actualTarget = m_newActualTarget;
m_newActualTarget.reset();
m_auxScreen->onSize(texW, texH);
m_auxScreen->setRenderTarget(m_renderState->m_actualTarget);
@ -101,7 +113,8 @@ void RenderQueueRoutine::processResize(ScreenBase const & frameScreen)
{
shared_ptr<yg::gl::BaseTexture> oldBackBuffer = m_renderState->m_backBufferLayers[i];
m_renderState->m_backBufferLayers[i].reset();
m_renderState->m_backBufferLayers[i] = m_resourceManager->createRenderTarget(texW, texH);
m_renderState->m_backBufferLayers[i] = m_newBackBufferLayers[i];
m_newBackBufferLayers[i].reset();
m_auxScreen->setRenderTarget(m_renderState->m_backBufferLayers[i]);
m_auxScreen->beginFrame();
m_auxScreen->clear(m_bgColor);
@ -229,8 +242,6 @@ void RenderQueueRoutine::Do()
{
m_renderContext->makeCurrent();
m_frameBuffer = make_shared_ptr(new yg::gl::FrameBuffer());
DrawerYG::params_t params;
params.m_resourceManager = m_resourceManager;
@ -242,6 +253,7 @@ void RenderQueueRoutine::Do()
params.m_visualScale = m_visualScale;
params.m_threadID = 0;
params.m_glyphCacheID = m_resourceManager->renderThreadGlyphCacheID(0);
params.m_renderQueue = m_glQueue;
/* params.m_isDebugging = true;
params.m_drawPathes = false;
params.m_drawAreas = false;
@ -250,8 +262,9 @@ void RenderQueueRoutine::Do()
m_threadDrawer = make_shared_ptr(new DrawerYG(params));
yg::gl::Screen::Params auxParams;
auxParams.m_frameBuffer = make_shared_ptr(new yg::gl::FrameBuffer());
auxParams.m_frameBuffer = m_auxFrameBuffer;
auxParams.m_resourceManager = m_resourceManager;
auxParams.m_renderQueue = m_glQueue;
m_auxScreen = make_shared_ptr(new yg::gl::Screen(auxParams));
@ -493,6 +506,8 @@ void RenderQueueRoutine::addCommand(render_fn_t const & fn, ScreenBase const & f
void RenderQueueRoutine::initializeGL(shared_ptr<yg::gl::RenderContext> const & renderContext,
shared_ptr<yg::ResourceManager> const & resourceManager)
{
m_frameBuffer.reset(new yg::gl::FrameBuffer());
m_auxFrameBuffer.reset(new yg::gl::FrameBuffer());
m_renderContext = renderContext;
m_resourceManager = resourceManager;
}
@ -520,3 +535,8 @@ void RenderQueueRoutine::waitForEmptyAndFinished()
if (!m_renderCommands.empty() || (m_currentRenderCommand != 0))
guard.Wait();
}
void RenderQueueRoutine::SetGLQueue(ThreadedList<yg::gl::Renderer::Packet> * glQueue)
{
m_glQueue = glQueue;
}

View file

@ -54,6 +54,10 @@ private:
shared_ptr<yg::gl::RenderContext> m_renderContext;
shared_ptr<yg::gl::FrameBuffer> m_frameBuffer;
shared_ptr<yg::gl::FrameBuffer> m_auxFrameBuffer;
shared_ptr<yg::gl::RenderBuffer> m_newDepthBuffer;
shared_ptr<yg::gl::BaseTexture> m_newActualTarget;
vector<shared_ptr<yg::gl::BaseTexture> > m_newBackBufferLayers;
shared_ptr<DrawerYG> m_threadDrawer;
shared_ptr<yg::gl::Screen> m_auxScreen;
@ -78,6 +82,7 @@ private:
bool m_isBenchmarking;
unsigned m_scaleEtalonSize;
yg::Color m_bgColor;
ThreadedList<yg::gl::Renderer::Packet> * m_glQueue;
void waitForRenderCommand(list<shared_ptr<RenderModelCommand> > & cmdList,
threads::ConditionGuard & guard);
@ -98,6 +103,9 @@ public:
shared_ptr<yg::ResourceManager> const & resourceManager);
/// This function should always be called from the main thread.
void Cancel();
void onSize(int w, int h);
/// Check, whether the resize command is queued, and resize accordingly.
void processResize(ScreenBase const & frameScreen);
/// Get update areas for the current render state
@ -122,4 +130,6 @@ public:
void enterForeground();
/// wait for all commands are processed.
void waitForEmptyAndFinished();
void SetGLQueue(ThreadedList<yg::gl::Renderer::Packet> * glQueue);
};

View file

@ -70,7 +70,7 @@ namespace yg
#ifndef OMIM_OS_ANDROID
if (current() != m_id)
#endif
OGLCHECK(glBindTexture(GL_TEXTURE_2D, m_id));
OGLCHECK(glBindTexture(GL_TEXTURE_2D, m_id));
}
unsigned BaseTexture::id() const

View file

@ -18,6 +18,40 @@ namespace yg
{
namespace gl
{
Blitter::IMMDrawTexturedRect::IMMDrawTexturedRect(
m2::RectF const & rect,
m2::RectF const & texRect,
shared_ptr<BaseTexture> const & texture,
shared_ptr<ResourceManager> const & rm)
{
m2::PointF rectPoints[4] =
{
m2::PointF(rect.minX(), rect.minY()),
m2::PointF(rect.maxX(), rect.minY()),
m2::PointF(rect.maxX(), rect.maxY()),
m2::PointF(rect.minX(), rect.maxY())
};
m2::PointF texRectPoints[4] =
{
m2::PointF(texRect.minX(), texRect.minY()),
m2::PointF(texRect.maxX(), texRect.minY()),
m2::PointF(texRect.maxX(), texRect.maxY()),
m2::PointF(texRect.minX(), texRect.maxY()),
};
m_pts.resize(4);
m_texPts.resize(4);
copy(rectPoints, rectPoints + 4, &m_pts[0]);
copy(texRectPoints, texRectPoints + 4, &m_texPts[0]);
m_ptsCount = 4;
m_texture = texture;
m_hasTexture = true;
m_hasColor = false;
m_resourceManager = rm;
}
Blitter::Blitter(base_t::Params const & params) : base_t(params)
{
}
@ -222,26 +256,35 @@ namespace yg
}
void Blitter::immDrawTexturedRect(m2::RectF const & rect,
m2::RectF const & texRect,
shared_ptr<BaseTexture> const & texture)
m2::RectF const & texRect,
shared_ptr<BaseTexture> const & texture)
{
m2::PointF rectPoints[4] =
{
m2::PointF(rect.minX(), rect.minY()),
m2::PointF(rect.maxX(), rect.minY()),
m2::PointF(rect.maxX(), rect.maxY()),
m2::PointF(rect.minX(), rect.maxY())
};
shared_ptr<IMMDrawTexturedRect> command(new IMMDrawTexturedRect(rect, texRect, texture, resourceManager()));
processCommand(command);
}
m2::PointF texRectPoints[4] =
{
m2::PointF(texRect.minX(), texRect.minY()),
m2::PointF(texRect.maxX(), texRect.minY()),
m2::PointF(texRect.maxX(), texRect.maxY()),
m2::PointF(texRect.minX(), texRect.maxY()),
};
void Blitter::immDrawTexturedPrimitives(m2::PointF const * pts,
m2::PointF const * texPts,
size_t size,
shared_ptr<BaseTexture> const & texture,
bool hasTexture,
yg::Color const & color,
bool hasColor)
{
shared_ptr<IMMDrawTexturedPrimitives> command(new IMMDrawTexturedPrimitives());
immDrawTexturedPrimitives(rectPoints, texRectPoints, 4, texture, true, yg::Color(), false);
command->m_ptsCount = size;
command->m_pts.resize(size);
command->m_texPts.resize(size);
copy(pts, pts + size, command->m_pts.begin());
copy(texPts, texPts + size, command->m_texPts.begin());
command->m_texture = texture;
command->m_hasTexture = hasTexture;
command->m_color = color;
command->m_hasColor = hasColor;
command->m_resourceManager = resourceManager();
processCommand(command);
}
void Blitter::setupAuxVertexLayout(bool hasColor, bool hasTexture, void * glPtr)
@ -269,51 +312,46 @@ namespace yg
}
}
void Blitter::immDrawTexturedPrimitives(m2::PointF const * pts,
m2::PointF const * texPts,
size_t size,
shared_ptr<BaseTexture> const & texture,
bool hasTexture,
yg::Color const & color,
bool hasColor)
void Blitter::IMMDrawTexturedPrimitives::perform()
{
m_blitStorage = resourceManager()->blitStorages()->Reserve();
if (m_isDebugging)
LOG(LINFO, ("performing IMMDrawTexturedPrimitives command"));
yg::gl::Storage blitStorage = m_resourceManager->blitStorages()->Reserve();
AuxVertex * pointsData = (AuxVertex*)m_blitStorage.m_vertices->lock();
AuxVertex * pointsData = (AuxVertex*)blitStorage.m_vertices->lock();
for (size_t i = 0; i < size; ++i)
for (size_t i = 0; i < m_ptsCount; ++i)
{
pointsData[i].pt.x = pts[i].x;
pointsData[i].pt.y = pts[i].y;
pointsData[i].texPt.x = texPts[i].x;
pointsData[i].texPt.y = texPts[i].y;
pointsData[i].color = color;
pointsData[i].pt.x = m_pts[i].x;
pointsData[i].pt.y = m_pts[i].y;
pointsData[i].texPt.x = m_texPts[i].x;
pointsData[i].texPt.y = m_texPts[i].y;
pointsData[i].color = m_color;
}
m_blitStorage.m_vertices->unlock();
m_blitStorage.m_vertices->makeCurrent();
blitStorage.m_vertices->unlock();
blitStorage.m_vertices->makeCurrent();
setupAuxVertexLayout(hasColor, hasTexture, m_blitStorage.m_vertices->glPtr());
Blitter::setupAuxVertexLayout(m_hasColor, m_hasTexture, blitStorage.m_vertices->glPtr());
if (texture)
texture->makeCurrent();
if (m_texture)
m_texture->makeCurrent();
unsigned short idxData[4] = {0, 1, 2, 3};
memcpy(m_blitStorage.m_indices->lock(), idxData, sizeof(idxData));
m_blitStorage.m_indices->unlock();
m_blitStorage.m_indices->makeCurrent();
memcpy(blitStorage.m_indices->lock(), idxData, sizeof(idxData));
blitStorage.m_indices->unlock();
blitStorage.m_indices->makeCurrent();
OGLCHECK(glDisable(GL_BLEND));
OGLCHECK(glDisable(GL_DEPTH_TEST));
OGLCHECK(glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, m_blitStorage.m_indices->glPtr()));
OGLCHECK(glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, blitStorage.m_indices->glPtr()));
OGLCHECK(glEnable(GL_DEPTH_TEST));
OGLCHECK(glEnable(GL_TEXTURE_2D));
OGLCHECK(glEnable(GL_BLEND));
// /// This call is necessary to avoid parasite blitting in updateActualTarget() on IPhone.
// OGLCHECK(glFinish());
resourceManager()->blitStorages()->Free(m_blitStorage);
m_blitStorage = yg::gl::Storage();
m_resourceManager->blitStorages()->Free(blitStorage);
}
}
}

View file

@ -2,10 +2,14 @@
#include "clipper.hpp"
#include "storage.hpp"
#include "../std/shared_ptr.hpp"
#include "../geometry/point2d.hpp"
#include "../geometry/rect2d.hpp"
#include "../base/buffer_vector.hpp"
#include "../std/shared_ptr.hpp"
class ScreenBase;
namespace yg
@ -32,12 +36,12 @@ namespace yg
yg::gl::Storage m_blitStorage;
static void setupAuxVertexLayout(bool hasColor, bool hasTexture, void * glPtr);
protected:
typedef Clipper base_t;
void setupAuxVertexLayout(bool hasColor, bool hasTexture, void * glPtr);
void calcPoints(m2::RectI const & srcRect,
m2::RectU const & texRect,
shared_ptr<BaseTexture> const & texture,
@ -46,6 +50,29 @@ namespace yg
m2::PointF * geomPts,
m2::PointF * texPts);
struct IMMDrawTexturedPrimitives : Command
{
buffer_vector<m2::PointF, 8> m_pts;
buffer_vector<m2::PointF, 8> m_texPts;
unsigned m_ptsCount;
shared_ptr<BaseTexture> m_texture;
bool m_hasTexture;
yg::Color m_color;
bool m_hasColor;
shared_ptr<ResourceManager> m_resourceManager;
void perform();
};
struct IMMDrawTexturedRect : IMMDrawTexturedPrimitives
{
IMMDrawTexturedRect(m2::RectF const & rect,
m2::RectF const & texRect,
shared_ptr<BaseTexture> const & texture,
shared_ptr<ResourceManager> const & rm);
};
public:
Blitter(base_t::Params const & params);

View file

@ -1,6 +1,8 @@
#include "../base/SRC_FIRST.hpp"
#include "clipper.hpp"
#include "internal/opengl.hpp"
#include "../std/bind.hpp"
#include "../base/logging.hpp"
namespace yg
{
@ -11,6 +13,33 @@ namespace yg
m_isClippingEnabled(false)
{}
void Clipper::State::apply(BaseState const * prev)
{
base_t::State::apply(prev);
State const * state = static_cast<State const *>(prev);
if (state->m_isClippingEnabled != m_isClippingEnabled)
{
if (m_isClippingEnabled)
{
// LOG(LINFO, ("enabling scissors"));
OGLCHECK(glEnable(GL_SCISSOR_TEST));
}
else
{
// LOG(LINFO, ("disabling scissors"));
OGLCHECK(glDisable(GL_SCISSOR_TEST));
}
}
if (state->m_clipRect != m_clipRect)
{
// LOG(LINFO, ("scissorRect(", m_clipRect.minX(), m_clipRect.minY(), m_clipRect.maxX(), m_clipRect.maxY(), ")"));
OGLCHECK(glScissor(m_clipRect.minX(), m_clipRect.minY(), m_clipRect.SizeX(), m_clipRect.SizeY()));
}
}
void Clipper::beginFrame()
{
base_t::beginFrame();
@ -28,6 +57,10 @@ namespace yg
void Clipper::enableClipRect(bool flag)
{
m_isClippingEnabled = flag;
if (renderQueue())
return;
if (m_isClippingEnabled)
OGLCHECK(glEnable(GL_SCISSOR_TEST));
else
@ -45,6 +78,9 @@ namespace yg
if (!m_clipRect.Intersect(m2::RectI(0, 0, width(), height())))
m_clipRect = m2::RectI(0, 0, 0, 0);
if (renderQueue())
return;
OGLCHECK(glScissor(m_clipRect.minX(), m_clipRect.minY(), m_clipRect.SizeX(), m_clipRect.SizeY()));
}
@ -52,5 +88,19 @@ namespace yg
{
return m_clipRect;
}
shared_ptr<Clipper::BaseState> const Clipper::createState() const
{
return shared_ptr<BaseState>(new State());
}
void Clipper::getState(BaseState * s)
{
State * state = static_cast<State *>(s);
base_t::getState(s);
state->m_clipRect = m_clipRect;
state->m_isClippingEnabled = m_isClippingEnabled;
}
}
}

View file

@ -16,10 +16,24 @@ namespace yg
bool m_isClippingEnabled;
m2::RectI m_clipRect;
void enableClipRectImpl(bool flag);
void setClipRectImpl(m2::RectI const & rect);
public:
struct State : public base_t::State
{
bool m_isClippingEnabled;
m2::RectI m_clipRect;
void apply(BaseState const * prev);
};
Clipper(base_t::Params const & params);
shared_ptr<BaseState> const createState() const;
void getState(BaseState * state);
void beginFrame();
void endFrame();

View file

@ -34,35 +34,13 @@ namespace yg
m_useTinyStorage(params.m_useTinyStorage)
{
reset(-1);
applyStates();
base_t::applyStates(m_isAntiAliased);
/// 1 to turn antialiasing on
/// 2 to switch it off
m_aaShift = m_isAntiAliased ? 1 : 2;
}
void GeometryBatcher::applyStates()
{
OGLCHECK(glEnable(GL_TEXTURE_2D));
if (!m_isAntiAliased)
{
OGLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
OGLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
}
OGLCHECK(glEnable(GL_DEPTH_TEST));
OGLCHECK(glDepthFunc(GL_LEQUAL));
OGLCHECK(glEnable(GL_ALPHA_TEST));
OGLCHECK(glAlphaFunc(GL_GREATER, 0.0));
OGLCHECK(glEnable(GL_BLEND));
OGLCHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
OGLCHECK(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
}
GeometryBatcher::~GeometryBatcher()
{}
@ -78,15 +56,15 @@ namespace yg
}
}
void GeometryBatcher::GeometryPipeline::checkStorage(shared_ptr<ResourceManager> const & resourceManager, SkinPage::EUsage usage) const
void GeometryBatcher::GeometryPipeline::checkStorage(shared_ptr<ResourceManager> const & resourceManager) const
{
if (!m_hasStorage)
{
if (m_useTinyStorage)
m_storage = resourceManager->tinyStorages()->Reserve();
else
m_storage = usage != SkinPage::EStaticUsage ? resourceManager->storages()->Reserve()
: resourceManager->smallStorages()->Reserve();
m_storage = m_usage != SkinPage::EStaticUsage ? resourceManager->storages()->Reserve()
: resourceManager->smallStorages()->Reserve();
m_maxVertices = m_storage.m_vertices->size() / sizeof(Vertex);
m_maxIndices = m_storage.m_indices->size() / sizeof(unsigned short);
@ -97,6 +75,38 @@ namespace yg
}
}
void GeometryBatcher::FreeStorage::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing FreeStorage command"));
m_storagePool->Free(m_storage);
}
void GeometryBatcher::freeStorage(int pipelineID)
{
GeometryPipeline & pipeline = m_pipelines[pipelineID];
shared_ptr<FreeStorage> freeStorage(new FreeStorage());
freeStorage->m_storage = pipeline.m_storage;
if (pipeline.m_hasStorage)
{
if (pipeline.m_useTinyStorage)
freeStorage->m_storagePool = resourceManager()->tinyStorages();
else
if (pipeline.m_usage != SkinPage::EStaticUsage)
freeStorage->m_storagePool = resourceManager()->storages();
else
freeStorage->m_storagePool = resourceManager()->smallStorages();
pipeline.m_hasStorage = false;
pipeline.m_storage = Storage();
}
processCommand(freeStorage);
}
void GeometryBatcher::setAdditionalSkinPage(shared_ptr<SkinPage> const & p)
{
if (m_skin != 0)
@ -105,11 +115,11 @@ namespace yg
int pagesCount = m_skin->getPagesCount();
m_pipelines.resize(pagesCount + 1);
/// additional page are fixed
/// additional page are fixed-content page, and shouldn't be modified by this screen.
/*m_skin->addOverflowFn(bind(&GeometryBatcher::flush, this, _1), 100);
m_skin->addClearPageFn(bind(&GeometryBatcher::flush, this, _1), 100);
m_skin->addClearPageFn(bind(&GeometryBatcher::switchTextures, this, _1), 99);*/
m_skin->addClearPageFn(bind(&GeometryBatcher::freeTexture, this, _1), 99);*/
for (size_t i = 0; i < 1; ++i)
{
@ -118,6 +128,7 @@ namespace yg
m_pipelines[i + pagesCount].m_currentIndex = 0;
m_pipelines[i + pagesCount].m_hasStorage = false;
m_pipelines[i + pagesCount].m_usage = p->usage();
m_pipelines[i + pagesCount].m_maxVertices = 0;
m_pipelines[i + pagesCount].m_maxIndices = 0;
@ -138,18 +149,7 @@ namespace yg
m_skin->clearAdditionalPage();
for (unsigned i = pagesCount; i < pagesCount + additionalPagesCount; ++i)
{
if (m_pipelines[i].m_hasStorage)
{
if (m_useTinyStorage)
resourceManager()->tinyStorages()->Free(m_pipelines[i].m_storage);
else
if (m_skin->getPage(i)->usage() != SkinPage::EStaticUsage)
resourceManager()->storages()->Free(m_pipelines[i].m_storage);
else
resourceManager()->smallStorages()->Free(m_pipelines[i].m_storage);
}
}
freeStorage(i);
m_pipelines.resize(m_skin->getPagesCount());
}
@ -165,7 +165,7 @@ namespace yg
m_skin->addOverflowFn(bind(&GeometryBatcher::flush, this, _1), 100);
m_skin->addClearPageFn(bind(&GeometryBatcher::flush, this, _1), 100);
m_skin->addClearPageFn(bind(&GeometryBatcher::switchTextures, this, _1), 99);
m_skin->addClearPageFn(bind(&GeometryBatcher::freeTexture, this, _1), 99);
for (size_t i = 0; i < m_pipelines.size(); ++i)
{
@ -174,6 +174,7 @@ namespace yg
m_pipelines[i].m_currentIndex = 0;
m_pipelines[i].m_hasStorage = false;
m_pipelines[i].m_usage = skin->getPage(i)->usage();
m_pipelines[i].m_maxVertices = 0;
m_pipelines[i].m_maxIndices = 0;
@ -219,7 +220,7 @@ namespace yg
enableClipRect(false);
if (m_isSynchronized)
OGLCHECK(glFinish());
processCommand(shared_ptr<Command>(new FinishCommand()));
if (isDebugging())
{
@ -237,7 +238,7 @@ namespace yg
{
GeometryPipeline const & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
return ((pipeline.m_currentVertex + verticesCount <= pipeline.m_maxVertices)
&& (pipeline.m_currentIndex + indicesCount <= pipeline.m_maxIndices));
@ -247,7 +248,7 @@ namespace yg
{
GeometryPipeline const & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
return pipeline.m_maxVertices - pipeline.m_currentVertex;
}
@ -255,71 +256,99 @@ namespace yg
size_t GeometryBatcher::indicesLeft(int pipelineID) const
{
GeometryPipeline const & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
return pipeline.m_maxIndices - pipeline.m_currentIndex;
}
void GeometryBatcher::flush(int pipelineID)
{
bool renderedData = false;
if (m_skin)
{
for (size_t i = m_pipelines.size(); i > 0; --i)
{
if ((pipelineID == -1) || ((i - 1) == (size_t)pipelineID))
{
shared_ptr<SkinPage> skinPage = m_skin->getPage(i - 1);
GeometryPipeline & pipeline = m_pipelines[i - 1];
skinPage->uploadData();
if (pipeline.m_currentIndex)
{
pipeline.m_storage.m_vertices->unlock();
pipeline.m_storage.m_indices->unlock();
drawGeometry(skinPage->texture(),
pipeline.m_storage.m_vertices,
pipeline.m_storage.m_indices,
pipeline.m_currentIndex);
if (isDebugging())
{
pipeline.m_verticesDrawn += pipeline.m_currentVertex;
pipeline.m_indicesDrawn += pipeline.m_currentIndex;
// LOG(LINFO, ("Pipeline #", i - 1, "draws ", pipeline.m_currentIndex / 3, "/", pipeline.m_maxIndices / 3," triangles"));
}
renderedData = true;
if (m_useTinyStorage)
resourceManager()->tinyStorages()->Free(pipeline.m_storage);
else
if (skinPage->usage() != SkinPage::EStaticUsage)
resourceManager()->storages()->Free(pipeline.m_storage);
else
resourceManager()->smallStorages()->Free(pipeline.m_storage);
pipeline.m_hasStorage = false;
pipeline.m_storage = Storage();
pipeline.m_maxIndices = 0;
pipeline.m_maxVertices = 0;
pipeline.m_vertices = 0;
pipeline.m_indices = 0;
}
flushPipeline(m_skin->getPage(i - 1), i - 1);
reset(i - 1);
}
}
}
}
void GeometryBatcher::switchTextures(int pipelineID)
void GeometryBatcher::FreeTexture::perform()
{
m_skin->getPage(pipelineID)->freeTexture();
if (m_isDebugging)
LOG(LINFO, ("performing FreeTexture command"));
m_texturePool->Free(m_texture);
}
void GeometryBatcher::freeTexture(int pipelineID)
{
shared_ptr<FreeTexture> freeTexCmd(new FreeTexture());
freeTexCmd->m_texture = m_skin->getPage(pipelineID)->texture();
switch (m_skin->getPage(pipelineID)->usage())
{
case SkinPage::EDynamicUsage:
freeTexCmd->m_texturePool = resourceManager()->dynamicTextures();
break;
case SkinPage::EFontsUsage:
freeTexCmd->m_texturePool = resourceManager()->fontTextures();
break;
}
if (freeTexCmd->m_texture)
processCommand(freeTexCmd);
/*
m_skin->getPage(pipelineID)->freeTexture();*/
}
void GeometryBatcher::uploadData(shared_ptr<SkinPage> const & skinPage)
{
if (skinPage->hasData())
{
base_t::uploadData(skinPage->uploadQueue(), skinPage->texture());
skinPage->clearUploadQueue();
}
}
void GeometryBatcher::flushPipeline(shared_ptr<SkinPage> const & skinPage,
int pipelineID)
{
GeometryPipeline & pipeline = m_pipelines[pipelineID];
if (pipeline.m_currentIndex)
{
uploadData(skinPage);
pipeline.m_storage.m_vertices->unlock();
pipeline.m_storage.m_indices->unlock();
// base_t::applyStates(m_isAntiAliased);
drawGeometry(skinPage->texture(),
pipeline.m_storage.m_vertices,
pipeline.m_storage.m_indices,
pipeline.m_currentIndex);
if (isDebugging())
{
pipeline.m_verticesDrawn += pipeline.m_currentVertex;
pipeline.m_indicesDrawn += pipeline.m_currentIndex;
// LOG(LINFO, ("Pipeline #", i - 1, "draws ", pipeline.m_currentIndex / 3, "/", pipeline.m_maxIndices / 3," triangles"));
}
freeStorage(pipelineID);
pipeline.m_maxIndices = 0;
pipeline.m_maxVertices = 0;
pipeline.m_vertices = 0;
pipeline.m_indices = 0;
}
}
void GeometryBatcher::drawTexturedPolygon(
@ -333,7 +362,7 @@ namespace yg
if (!hasRoom(4, 6, pipelineID))
flush(pipelineID);
m_pipelines[pipelineID].checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
m_pipelines[pipelineID].checkStorage(resourceManager());
float texMinX = tx0;
float texMaxX = tx1;
@ -386,7 +415,7 @@ namespace yg
GeometryPipeline & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
ASSERT(size > 2, ());
@ -437,7 +466,7 @@ namespace yg
GeometryPipeline & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
ASSERT(size > 2, ());
@ -485,7 +514,7 @@ namespace yg
GeometryPipeline & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
ASSERT(size > 2, ());
@ -524,7 +553,7 @@ namespace yg
GeometryPipeline & pipeline = m_pipelines[pipelineID];
pipeline.checkStorage(resourceManager(), skin()->getPage(pipelineID)->usage());
pipeline.checkStorage(resourceManager());
ASSERT(size > 2, ());

View file

@ -8,6 +8,7 @@
#include "render_state_updater.hpp"
#include "storage.hpp"
#include "skin_page.hpp"
#include "resource_manager.hpp"
#include "../std/vector.hpp"
#include "../std/string.hpp"
@ -62,21 +63,20 @@ namespace yg
/// @}
bool m_useTinyStorage;
yg::SkinPage::EUsage m_usage;
size_t verticesLeft();
size_t indicesLeft();
void checkStorage(shared_ptr<ResourceManager> const & resourceManager, yg::SkinPage::EUsage usage) const;
void checkStorage(shared_ptr<ResourceManager> const & resourceManager) const;
};
vector<GeometryPipeline> m_pipelines;
void reset(int pipelineID);
void switchTextures(int pipelineID);
/// Apply all states needed for rendering a batch of geometry.
void applyStates();
void freeStorage(int pipelineID);
void freeTexture(int pipelineID);
bool m_isAntiAliased;
bool m_isSynchronized;
@ -84,6 +84,21 @@ namespace yg
int m_aaShift;
struct FreeStorage : public Command
{
ResourceManager::TStoragePool * m_storagePool;
Storage m_storage;
void perform();
};
struct FreeTexture : public Command
{
ResourceManager::TTexturePool * m_texturePool;
shared_ptr<BaseTexture> m_texture;
void perform();
};
public:
@ -109,6 +124,10 @@ namespace yg
void beginFrame();
void endFrame();
void uploadData(shared_ptr<SkinPage> const & skinPage);
void flushPipeline(shared_ptr<SkinPage> const & skinPage, int pipelineID);
public:
/// This functions hide the base_t functions with the same name and signature
@ -118,7 +137,6 @@ namespace yg
void setClipRect(m2::RectI const & rect);
void clear(yg::Color const & c = yg::Color(187, 187, 187, 255), bool clearRT = true, float depth = 1.0, bool clearDepth = true);
/// @}
void setRenderTarget(shared_ptr<RenderTarget> const & rt);

View file

@ -1,39 +1,120 @@
#include "../base/SRC_FIRST.hpp"
#include "geometry_renderer.hpp"
#include "resource_style.hpp"
#include "base_texture.hpp"
#include "texture.hpp"
#include "vertexbuffer.hpp"
#include "indexbuffer.hpp"
#include "managed_texture.hpp"
#include "vertex.hpp"
#include "internal/opengl.hpp"
#include "../std/bind.hpp"
#include "../base/logging.hpp"
namespace yg
{
namespace gl
{
GeometryRenderer::GeometryRenderer(base_t::Params const & params) : base_t(params)
typedef Texture<DATA_TRAITS, true> TDynamicTexture;
GeometryRenderer::GeometryRenderer(base_t::Params const & params)
: base_t(params)
{}
void GeometryRenderer::DrawGeometry::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing DrawGeometry command"));
m_vertices->makeCurrent();
/// it's important to setupLayout after vertices->makeCurrent
Vertex::setupLayout(m_vertices->glPtr());
m_indices->makeCurrent();
m_texture->makeCurrent();
// OGLCHECK(glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ));
OGLCHECK(glDrawElements(
GL_TRIANGLES,
m_indicesCount,
GL_UNSIGNED_SHORT,
m_indices->glPtr()));
// OGLCHECK(glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ));
}
void GeometryRenderer::drawGeometry(shared_ptr<BaseTexture> const & texture,
shared_ptr<VertexBuffer> const & vertices,
shared_ptr<IndexBuffer> const & indices,
size_t indicesCount)
{
vertices->makeCurrent();
/// it's important to setupLayout after vertices->makeCurrent
Vertex::setupLayout(vertices->glPtr());
indices->makeCurrent();
shared_ptr<DrawGeometry> command(new DrawGeometry());
command->m_texture = texture;
command->m_indices = indices;
command->m_vertices = vertices;
command->m_indicesCount = indicesCount;
command->m_isDebugging = renderQueue();
texture->makeCurrent();
processCommand(command);
}
// OGLCHECK(glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ));
void GeometryRenderer::UploadData::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing UploadData command"));
OGLCHECK(glDrawElements(
GL_TRIANGLES,
indicesCount,
GL_UNSIGNED_SHORT,
indices->glPtr()));
static_cast<gl::ManagedTexture*>(m_texture.get())->lock();
// OGLCHECK(glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ));
TDynamicTexture * dynTexture = static_cast<TDynamicTexture*>(m_texture.get());
for (size_t i = 0; i < m_styles.size(); ++i)
{
shared_ptr<ResourceStyle> const & style = m_styles[i];
TDynamicTexture::view_t v = dynTexture->view(style->m_texRect.SizeX(),
style->m_texRect.SizeY());
style->render(&v(0, 0));
dynTexture->upload(&v(0, 0), style->m_texRect);
}
static_cast<gl::ManagedTexture*>(m_texture.get())->unlock();
}
void GeometryRenderer::uploadData(vector<shared_ptr<ResourceStyle> > const & v,
shared_ptr<BaseTexture> const & texture)
{
shared_ptr<UploadData> uploadData(new UploadData());
uploadData->m_styles = v;
uploadData->m_texture = texture;
uploadData->m_isDebugging = renderQueue();
processCommand(uploadData);
}
void GeometryRenderer::applyStates(bool isAntiAliased)
{
if (renderQueue())
return;
OGLCHECK(glEnable(GL_TEXTURE_2D));
// OGLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
// OGLCHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
OGLCHECK(glEnable(GL_DEPTH_TEST));
OGLCHECK(glDepthFunc(GL_LEQUAL));
OGLCHECK(glEnable(GL_ALPHA_TEST));
OGLCHECK(glAlphaFunc(GL_GREATER, 0.0));
OGLCHECK(glEnable(GL_BLEND));
OGLCHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
OGLCHECK(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
}
}
}

View file

@ -1,11 +1,16 @@
#pragma once
#include "../std/shared_ptr.hpp"
#include "blitter.hpp"
#include "../base/threaded_list.hpp"
#include "../std/shared_ptr.hpp"
#include "../std/function.hpp"
namespace yg
{
struct ResourceStyle;
namespace gl
{
class VertexBuffer;
@ -18,8 +23,29 @@ namespace yg
typedef Blitter base_t;
struct UploadData : base_t::Command
{
vector<shared_ptr<ResourceStyle> > m_styles;
shared_ptr<BaseTexture> m_texture;
void perform();
};
struct DrawGeometry : base_t::Command
{
shared_ptr<BaseTexture> m_texture;
shared_ptr<VertexBuffer> m_vertices;
shared_ptr<IndexBuffer> m_indices;
size_t m_indicesCount;
void perform();
};
GeometryRenderer(base_t::Params const & params);
void uploadData(vector<shared_ptr<ResourceStyle> > const & v,
shared_ptr<BaseTexture> const & texture);
void applyStates(bool isAntiAliased);
void drawGeometry(shared_ptr<BaseTexture> const & texture,
shared_ptr<VertexBuffer> const & vertices,
shared_ptr<IndexBuffer> const & indices,

View file

@ -51,27 +51,7 @@ namespace yg
if (!m_infoLayer.get())
oe->draw(this, id);
else
{
m_infoLayer->processOverlayElement(oe);
/* m2::PointI keyPt((int)pt.x, (int)pt.y);
LOG(LINFO, ("symbolPos:", keyPt));
TElements::const_iterator it = m_elements.find(keyPt);
if (it != m_elements.end())
{
LOG(LINFO, ("matched : ", keyPt));
shared_ptr<OverlayElement> e = it->second;
shared_ptr<CompositeOverlayElement> coe(new CompositeOverlayElement(OverlayElement::Params()));
coe->addElement(it->second);
coe->addElement(oe);
oe = coe;
}
m_elements[keyPt] = oe;*/
}
}
void OverlayRenderer::drawCircle(m2::PointD const & pt,
@ -124,27 +104,7 @@ namespace yg
if (!m_infoLayer.get())
oe->draw(this, id);
else
{
m_infoLayer->processOverlayElement(oe);
/* m2::PointI keyPt((int)pt.x, (int)pt.y);
LOG(LINFO, ("textPos:", keyPt));
TElements::const_iterator it = m_elements.find(keyPt);
if (it != m_elements.end())
{
LOG(LINFO, ("matched :", keyPt));
shared_ptr<OverlayElement> e = it->second;
shared_ptr<CompositeOverlayElement> coe(new CompositeOverlayElement(OverlayElement::Params()));
coe->addElement(it->second);
coe->addElement(oe);
oe = coe;
}
m_elements[keyPt] = oe;*/
}
}
bool OverlayRenderer::drawPathText(

View file

@ -54,20 +54,8 @@ namespace yg
double const log2 = log(2.0);
//unsigned oldTextureWidth = m_textureWidth;
//unsigned oldTextureHeight = m_textureHeight;
m_textureWidth = static_cast<uint32_t>(pow(2, ceil(log(double(w)) / log2)));
m_textureHeight = static_cast<uint32_t>(pow(2, ceil(log(double(h)) / log2)));
//bool hasChangedTextureSize;
//if ((oldTextureWidth != m_textureWidth) || (oldTextureHeight != m_textureHeight))
// hasChangedTextureSize = true;
//else
// hasChangedTextureSize = false;
//if (hasChangedTextureSize)
// LOG(LINFO, ("TextureSize: ", m_textureWidth, m_textureHeight));
}
}

View file

@ -8,6 +8,7 @@
#include "internal/opengl.hpp"
#include "../base/logging.hpp"
#include "../std/bind.hpp"
namespace yg
{
@ -48,22 +49,19 @@ namespace yg
}
}
void RenderStateUpdater::updateActualTarget()
void RenderStateUpdater::UpdateActualTarget::perform()
{
/// Carefully synchronizing the access to the m_renderState to minimize wait time.
OGLCHECK(glFinish());
if (m_doSynchronize)
m_renderState->m_mutex->Lock();
m_renderState->m_actualScreen = m_currentScreen;
if (m_doSynchronize)
m_renderState->m_mutex->Unlock();
}
{
threads::MutexGuard guard(*m_renderState->m_mutex.get());
swap(m_renderState->m_actualTarget, m_renderState->m_backBufferLayers.front());
m_renderState->m_actualScreen = m_renderState->m_currentScreen;
}
/// blitting will be performed through
/// non-multisampled framebuffer for the sake of speed
frameBuffer()->setRenderTarget(m_renderState->m_backBufferLayers.front());
frameBuffer()->makeCurrent();
void RenderStateUpdater::UpdateBackBuffer::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing UpdateBackBuffer command"));
OGLCHECK(glFinish());
@ -72,15 +70,15 @@ namespace yg
OGLCHECK(glClearColor(192 / 255.0, 192 / 255.0, 192 / 255.0, 1.0));
OGLCHECK(glClear(GL_COLOR_BUFFER_BIT));
shared_ptr<BaseTexture> actualTarget = m_renderState->m_actualTarget;
shared_ptr<IMMDrawTexturedRect> immDrawTexturedRect(
new IMMDrawTexturedRect(m2::RectF(0, 0, m_actualTarget->width(), m_actualTarget->height()),
m2::RectF(0, 0, 1, 1),
m_actualTarget,
m_resourceManager));
immDrawTexturedRect(
m2::RectF(0, 0, actualTarget->width(), actualTarget->height()),
m2::RectF(0, 0, 1, 1),
actualTarget
);
immDrawTexturedRect->perform();
if (clipRectEnabled())
if (m_isClipRectEnabled)
OGLCHECK(glEnable(GL_SCISSOR_TEST));
OGLCHECK(glFinish());
@ -88,6 +86,38 @@ namespace yg
m_renderState->invalidate();
}
void RenderStateUpdater::updateActualTarget()
{
/// Carefully synchronizing the access to the m_renderState to minimize wait time.
processCommand(shared_ptr<Command>(new FinishCommand()));
m_renderState->m_mutex->Lock();
swap(m_renderState->m_actualTarget, m_renderState->m_backBufferLayers.front());
shared_ptr<UpdateActualTarget> command(new UpdateActualTarget());
command->m_renderState = m_renderState;
command->m_currentScreen = m_renderState->m_currentScreen;
command->m_doSynchronize = renderQueue();
processCommand(command);
shared_ptr<UpdateBackBuffer> command1(new UpdateBackBuffer());
command1->m_actualTarget = m_renderState->m_actualTarget;
command1->m_renderState = m_renderState;
command1->m_resourceManager = resourceManager();
command1->m_isClipRectEnabled = clipRectEnabled();
/// blitting will be performed through
/// non-multisampled framebuffer for the sake of speed
setRenderTarget(m_renderState->m_backBufferLayers.front());
// m_renderState->m_actualScreen = m_renderState->m_currentScreen;
m_renderState->m_mutex->Unlock();
processCommand(command1);
}
void RenderStateUpdater::beginFrame()
{
base_t::beginFrame();

View file

@ -25,6 +25,25 @@ namespace yg
double m_updateInterval;
my::Timer m_updateTimer;
struct UpdateActualTarget : base_t::Command
{
bool m_doSynchronize;
shared_ptr<RenderState> m_renderState;
ScreenBase m_currentScreen;
void perform();
};
struct UpdateBackBuffer : base_t::Command
{
shared_ptr<BaseTexture> m_actualTarget;
shared_ptr<RenderState> m_renderState;
shared_ptr<ResourceManager> m_resourceManager;
bool m_isClipRectEnabled;
void perform();
};
public:
struct Params : base_t::Params
@ -47,7 +66,7 @@ namespace yg
void beginFrame();
void endFrame();
void setClipRect(m2::RectI const & rect);
virtual void updateActualTarget();
void updateActualTarget();
};
}
}

View file

@ -11,17 +11,84 @@ namespace yg
{
namespace gl
{
Renderer::Params::Params() : m_isDebugging(false)
Renderer::BaseState::~BaseState()
{}
Renderer::Command::~Command()
{}
void Renderer::State::apply(BaseState const * prevBase)
{
State const * prevState = static_cast<State const *>(prevBase);
if (m_frameBuffer)
{
bool shouldApply = false;
if (m_frameBuffer == prevState->m_frameBuffer)
{
// LOG(LINFO, ("equal framebuffers"));
if (m_renderTarget != prevState->m_renderTarget)
{
// LOG(LINFO, ("non-equal renderbuffers, ", m_renderTarget.get(), prevState->m_renderTarget.get()));
m_frameBuffer->setRenderTarget(m_renderTarget);
shouldApply = true;
}
if (m_depthBuffer != prevState->m_depthBuffer)
{
// LOG(LINFO, ("non-equal depthbuffers, ", m_depthBuffer.get(), prevState->m_depthBuffer.get()));
m_frameBuffer->setDepthBuffer(m_depthBuffer);
shouldApply = true;
}
}
else
{
// LOG(LINFO, ("non-equal framebuffers"));
m_frameBuffer->setRenderTarget(m_renderTarget);
m_frameBuffer->setDepthBuffer(m_depthBuffer);
shouldApply = true;
}
if (shouldApply)
m_frameBuffer->makeCurrent();
}
else
CHECK(false, ());
}
Renderer::Packet::Packet()
{}
Renderer::Packet::Packet(shared_ptr<BaseState> const & state,
shared_ptr<Command> const & command)
: m_state(state), m_command(command)
{}
Renderer::Params::Params()
: m_isDebugging(false),
m_renderQueue(0)
{}
Renderer::Renderer(Params const & params)
: m_frameBuffer(params.m_frameBuffer),
m_isDebugging(params.m_isDebugging),
: m_isDebugging(params.m_isDebugging),
m_isRendering(false)
{
m_frameBuffer = params.m_frameBuffer;
m_resourceManager = params.m_resourceManager;
if (m_frameBuffer)
{
m_renderTarget = m_frameBuffer->renderTarget();
m_depthBuffer = m_frameBuffer->depthBuffer();
}
m_renderQueue = params.m_renderQueue;
}
Renderer::~Renderer()
{}
shared_ptr<ResourceManager> const & Renderer::resourceManager() const
{
return m_resourceManager;
@ -30,7 +97,11 @@ namespace yg
void Renderer::beginFrame()
{
m_isRendering = true;
if (m_frameBuffer.get() != 0)
if (m_renderQueue)
return;
if (m_frameBuffer)
m_frameBuffer->makeCurrent();
}
@ -51,36 +122,95 @@ namespace yg
shared_ptr<RenderTarget> const & Renderer::renderTarget() const
{
return m_frameBuffer->renderTarget();
return m_renderTarget;
}
void Renderer::setRenderTarget(shared_ptr<RenderTarget> const & rt)
{
m_frameBuffer->setRenderTarget(rt);
m_frameBuffer->makeCurrent(); //< to attach renderTarget
m_renderTarget = rt;
if (!m_renderQueue)
{
m_frameBuffer->setRenderTarget(rt);
m_frameBuffer->makeCurrent(); //< to attach renderTarget
}
}
void Renderer::clear(yg::Color const & c, bool clearRT, float depth, bool clearDepth)
shared_ptr<RenderTarget> const & Renderer::depthBuffer() const
{
OGLCHECK(glClearColor(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f));
return m_depthBuffer;
}
void Renderer::setDepthBuffer(shared_ptr<RenderTarget> const & rt)
{
m_depthBuffer = rt;
if (!m_renderQueue)
m_frameBuffer->setDepthBuffer(rt);
}
void Renderer::ClearCommand::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing clear command"));
OGLCHECK(glClearColor(m_color.r / 255.0f,
m_color.g / 255.0f,
m_color.b / 255.0f,
m_color.a / 255.0f));
#ifdef OMIM_GL_ES
OGLCHECK(glClearDepthf(depth));
OGLCHECK(glClearDepthf(m_depth));
#else
OGLCHECK(glClearDepth(depth));
OGLCHECK(glClearDepth(m_depth));
#endif
GLbitfield mask = 0;
if (clearRT)
if (m_clearRT)
mask |= GL_COLOR_BUFFER_BIT;
if (clearDepth)
if (m_clearDepth)
mask |= GL_DEPTH_BUFFER_BIT;
OGLCHECK(glClear(mask));
}
void Renderer::clear(yg::Color const & c, bool clearRT, float depth, bool clearDepth)
{
shared_ptr<ClearCommand> command(new ClearCommand());
command->m_color = c;
command->m_clearRT = clearRT;
command->m_depth = depth;
command->m_clearDepth = clearDepth;
command->m_isDebugging = renderQueue();
processCommand(command);
}
shared_ptr<Renderer::BaseState> const Renderer::createState() const
{
return shared_ptr<BaseState>(new State());
}
void Renderer::getState(BaseState * baseState)
{
State * state = static_cast<State *>(baseState);
state->m_frameBuffer = m_frameBuffer;
state->m_renderTarget = m_renderTarget;
state->m_depthBuffer = m_depthBuffer;
state->m_resourceManager = m_resourceManager;
}
void Renderer::FinishCommand::perform()
{
if (m_isDebugging)
LOG(LINFO, ("performing FinishCommand command"));
OGLCHECK(glFinish());
}
void Renderer::finish()
{
OGLCHECK(glFinish());
shared_ptr<Command> command(new FinishCommand());
processCommand(command);
}
void Renderer::onSize(unsigned int width, unsigned int height)
@ -109,5 +239,25 @@ namespace yg
{
return m_isDebugging;
}
void Renderer::processCommand(shared_ptr<Command> const & command)
{
command->m_isDebugging = false;
// command->m_isDebugging = renderQueue();
if (renderQueue())
{
shared_ptr<BaseState> state = createState();
getState(state.get());
m_renderQueue->PushBack(Packet(state, command));
}
else
command->perform();
}
ThreadedList<Renderer::Packet> * Renderer::renderQueue()
{
return m_renderQueue;
}
}
}

View file

@ -2,6 +2,8 @@
#include "color.hpp"
#include "../base/threaded_list.hpp"
#include "../std/function.hpp"
#include "../std/shared_ptr.hpp"
namespace yg
@ -18,23 +20,73 @@ namespace yg
class Renderer
{
public:
virtual ~Renderer() {}
struct BaseState
{
virtual ~BaseState();
virtual void apply(BaseState const * prev) = 0;
};
struct State : BaseState
{
shared_ptr<FrameBuffer> m_frameBuffer;
shared_ptr<RenderTarget> m_renderTarget;
shared_ptr<RenderTarget> m_depthBuffer;
shared_ptr<ResourceManager> m_resourceManager;
void apply(BaseState const * prev);
};
struct Command
{
bool m_isDebugging;
virtual ~Command();
virtual void perform() = 0;
};
struct Packet
{
shared_ptr<BaseState> m_state;
shared_ptr<Command> m_command;
Packet();
Packet(shared_ptr<BaseState> const & state,
shared_ptr<Command> const & command);
};
struct ClearCommand : Command
{
yg::Color m_color;
bool m_clearRT;
float m_depth;
bool m_clearDepth;
void perform();
};
struct FinishCommand : Command
{
void perform();
};
virtual ~Renderer();
struct Params
{
shared_ptr<ResourceManager> m_resourceManager;
shared_ptr<FrameBuffer> m_frameBuffer;
bool m_isDebugging;
ThreadedList<Packet> * m_renderQueue;
Params();
};
private:
shared_ptr<FrameBuffer> m_frameBuffer;
shared_ptr<RenderTarget> m_renderTarget;
shared_ptr<RenderTarget> m_depthBuffer;
shared_ptr<ResourceManager> m_resourceManager;
shared_ptr<FrameBuffer> m_frameBuffer;
shared_ptr<BaseTexture> m_renderTarget;
shared_ptr<RenderBuffer> m_depthBuffer;
ThreadedList<Packet> * m_renderQueue;
bool m_isDebugging;
@ -55,13 +107,13 @@ namespace yg
shared_ptr<ResourceManager> const & resourceManager() const;
shared_ptr<FrameBuffer> const & frameBuffer() const;
// void setFrameBuffer(shared_ptr<FrameBuffer> const & fb);
shared_ptr<FrameBuffer> const & multiSampledFrameBuffer() const;
void setRenderTarget(shared_ptr<RenderTarget> const & rt);
shared_ptr<RenderTarget> const & renderTarget() const;
void setDepthBuffer(shared_ptr<RenderTarget> const & rt);
shared_ptr<RenderTarget> const & depthBuffer() const;
/// @param clearRT - should we clear the renderTarget data (visible pixels)?
/// @param clearDepth - should we clear depthBuffer data?
/// @warning this function respects the clipping rect set and enabled(!)
@ -77,6 +129,13 @@ namespace yg
void finish();
bool isDebugging() const;
virtual shared_ptr<BaseState> const createState() const;
virtual void getState(BaseState * state);
void processCommand(shared_ptr<Command> const & command);
ThreadedList<Packet> * renderQueue();
};
}
}

View file

@ -303,6 +303,11 @@ namespace yg
return !m_uploadQueue.empty();
}
SkinPage::TUploadQueue const & SkinPage::uploadQueue() const
{
return m_uploadQueue;
}
void SkinPage::checkTexture() const
{
if ((m_usage != EStaticUsage) && (m_texture == 0))

View file

@ -47,6 +47,8 @@ namespace yg
typedef m2::Packer::overflowFn overflowFn;
typedef vector<shared_ptr<ResourceStyle> > TUploadQueue;
private:
typedef map<uint32_t, shared_ptr<ResourceStyle> > TStyles;
@ -74,9 +76,7 @@ namespace yg
mutable shared_ptr<ResourceManager> m_resourceManager;
/// @}
vector<shared_ptr<ResourceStyle> > m_uploadQueue;
void clearUploadQueue();
TUploadQueue m_uploadQueue;
typedef vector<FontInfo> TFonts;
TFonts m_fonts;
@ -104,6 +104,9 @@ namespace yg
void clear();
bool hasData();
TUploadQueue const & uploadQueue() const;
void clearUploadQueue();
void uploadData();
void checkTexture() const;