From 4d133edd2cf3b31ceef7970e2b77edbd18a7d5ab Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 16 Nov 2015 20:41:32 -1000 Subject: [PATCH] Window resizing stability fixes --- include/boo/IGraphicsContext.hpp | 3 + include/boo/IWindow.hpp | 3 + .../boo/graphicsdev/IGraphicsCommandQueue.hpp | 1 + lib/graphicsdev/GL.cpp | 57 ++++++++++++------- lib/x11/ApplicationXlib.hpp | 9 +++ lib/x11/WindowWayland.cpp | 10 ++++ lib/x11/WindowXlib.cpp | 21 +++++++ 7 files changed, 83 insertions(+), 21 deletions(-) diff --git a/include/boo/IGraphicsContext.hpp b/include/boo/IGraphicsContext.hpp index 8bc559d..4b9e416 100644 --- a/include/boo/IGraphicsContext.hpp +++ b/include/boo/IGraphicsContext.hpp @@ -53,6 +53,9 @@ public: virtual IGraphicsCommandQueue* getCommandQueue()=0; virtual IGraphicsDataFactory* getDataFactory()=0; + /* Creates a new context on current thread!! Call from main client thread */ + virtual IGraphicsDataFactory* getMainContextDataFactory()=0; + /* Creates a new context on current thread!! Call from client loading thread */ virtual IGraphicsDataFactory* getLoadContextDataFactory()=0; diff --git a/include/boo/IWindow.hpp b/include/boo/IWindow.hpp index 86ebeb1..9573fe4 100644 --- a/include/boo/IWindow.hpp +++ b/include/boo/IWindow.hpp @@ -196,6 +196,9 @@ public: virtual IGraphicsCommandQueue* getCommandQueue()=0; virtual IGraphicsDataFactory* getDataFactory()=0; + /* Creates a new context on current thread!! Call from main client thread */ + virtual IGraphicsDataFactory* getMainContextDataFactory()=0; + /* Creates a new context on current thread!! Call from client loading thread */ virtual IGraphicsDataFactory* getLoadContextDataFactory()=0; diff --git a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp index 14139a6..1a3e7d7 100644 --- a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp +++ b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp @@ -25,6 +25,7 @@ struct IGraphicsCommandQueue virtual void setViewport(const SWindowRect& rect)=0; virtual void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)=0; + virtual void flushBufferUpdates()=0; virtual void setClearColor(const float rgba[4])=0; virtual void clearTarget(bool render=true, bool depth=true)=0; diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 463a4d9..4299784 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -552,7 +552,6 @@ struct GLCommandQueue : IGraphicsCommandQueue OpSetShaderDataBinding, OpSetRenderTarget, OpSetViewport, - OpResizeRenderTexture, OpSetClearColor, OpClearTarget, OpSetDrawPrimitive, @@ -577,12 +576,6 @@ struct GLCommandQueue : IGraphicsCommandQueue size_t count; size_t instCount; }; - struct - { - ITextureR* tex; - size_t width; - size_t height; - } resize; }; Command(Op op) : m_op(op) {} }; @@ -599,7 +592,15 @@ struct GLCommandQueue : IGraphicsCommandQueue std::unique_lock m_initlk; std::thread m_thr; + struct RenderTextureResize + { + GLTextureR* tex; + size_t width; + size_t height; + }; + /* These members are locked for multithreaded access */ + std::vector m_pendingResizes; std::vector m_pendingFmtAdds; std::vector m_pendingFmtDels; std::vector m_pendingFboAdds; @@ -673,25 +674,40 @@ struct GLCommandQueue : IGraphicsCommandQueue break; self->m_drawBuf = self->m_completeBuf; + if (self->m_pendingResizes.size()) + { + for (const RenderTextureResize& resize : self->m_pendingResizes) + resize.tex->resize(resize.width, resize.height); + self->m_pendingResizes.clear(); + } + if (self->m_pendingFmtAdds.size()) + { for (GLVertexFormat* fmt : self->m_pendingFmtAdds) ConfigureVertexFormat(fmt); - self->m_pendingFmtAdds.clear(); + self->m_pendingFmtAdds.clear(); + } if (self->m_pendingFmtDels.size()) + { for (GLuint fmt : self->m_pendingFmtDels) glDeleteVertexArrays(1, &fmt); - self->m_pendingFmtDels.clear(); + self->m_pendingFmtDels.clear(); + } if (self->m_pendingFboAdds.size()) + { for (GLTextureR* tex : self->m_pendingFboAdds) ConfigureFBO(tex); - self->m_pendingFboAdds.clear(); + self->m_pendingFboAdds.clear(); + } if (self->m_pendingFboDels.size()) + { for (GLuint fbo : self->m_pendingFboDels) glDeleteFramebuffers(1, &fbo); - self->m_pendingFboDels.clear(); + self->m_pendingFboDels.clear(); + } } std::vector& cmds = self->m_cmdBufs[self->m_drawBuf]; GLenum prim = GL_TRIANGLES; @@ -715,11 +731,6 @@ struct GLCommandQueue : IGraphicsCommandQueue glViewport(cmd.rect.location[0], cmd.rect.location[1], cmd.rect.size[0], cmd.rect.size[1]); break; - case Command::OpResizeRenderTexture: - { - GLTextureR* tex = static_cast(cmd.resize.tex); - tex->resize(cmd.resize.width, cmd.resize.height); - } case Command::OpSetClearColor: glClearColor(cmd.rgba[0], cmd.rgba[1], cmd.rgba[2], cmd.rgba[3]); break; @@ -800,11 +811,14 @@ struct GLCommandQueue : IGraphicsCommandQueue void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::OpResizeRenderTexture); - cmds.back().resize.tex = tex; - cmds.back().resize.width = width; - cmds.back().resize.height = height; + std::unique_lock lk(m_mt); + GLTextureR* texgl = static_cast(tex); + m_pendingResizes.push_back({texgl, width, height}); + } + + void flushBufferUpdates() + { + glFlush(); } void setClearColor(const float rgba[4]) @@ -1022,6 +1036,7 @@ GLDataFactory::newRenderTexture(size_t width, size_t height, size_t samples) { GLCommandQueue* q = static_cast(m_parent->getCommandQueue()); GLTextureR* retval = new GLTextureR(q, width, height, samples); + q->resizeRenderTexture(retval, width, height); static_cast(m_deferredData)->m_RTexs.emplace_back(retval); return retval; } diff --git a/lib/x11/ApplicationXlib.hpp b/lib/x11/ApplicationXlib.hpp index 915ad01..be3e6b0 100644 --- a/lib/x11/ApplicationXlib.hpp +++ b/lib/x11/ApplicationXlib.hpp @@ -17,6 +17,8 @@ DBusConnection* RegisterDBus(const char* appName, bool& isFirst); #include #include +#include +#include namespace boo { @@ -239,11 +241,18 @@ public: /* Spawn client thread */ int clientReturn = INT_MIN; + std::mutex initmt; + std::condition_variable initcv; + std::unique_lock outerLk(initmt); std::thread clientThread([&]() { + std::unique_lock innerLk(initmt); + innerLk.unlock(); + initcv.notify_one(); clientReturn = m_callback.appMain(this); pthread_kill(mainThread, SIGTERM); }); + initcv.wait(outerLk); /* Begin application event loop */ while (clientReturn == INT_MIN) diff --git a/lib/x11/WindowWayland.cpp b/lib/x11/WindowWayland.cpp index c43cca1..80fbcc6 100644 --- a/lib/x11/WindowWayland.cpp +++ b/lib/x11/WindowWayland.cpp @@ -72,6 +72,11 @@ public: return nullptr; } + IGraphicsDataFactory* getMainContextDataFactory() + { + return nullptr; + } + IGraphicsDataFactory* getLoadContextDataFactory() { return nullptr; @@ -196,6 +201,11 @@ struct WindowWayland : IWindow return m_gfxCtx.getDataFactory(); } + IGraphicsDataFactory* getMainContextDataFactory() + { + return m_gfxCtx.getMainContextDataFactory(); + } + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx.getLoadContextDataFactory(); diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index 77ddb12..04e18e1 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -185,6 +185,7 @@ struct GraphicsContextGLX : IGraphicsContext IGraphicsCommandQueue* m_commandQueue = nullptr; IGraphicsDataFactory* m_dataFactory = nullptr; + GLXContext m_mainCtx = 0; GLXContext m_loadCtx = 0; std::thread m_vsyncThread; @@ -396,6 +397,21 @@ public: return m_dataFactory; } + IGraphicsDataFactory* getMainContextDataFactory() + { + XLockDisplay(m_xDisp); + if (!m_mainCtx) + { + m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribs); + if (!m_mainCtx) + Log.report(LogVisor::FatalError, "unable to make main GLX context"); + } + if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_mainCtx)) + Log.report(LogVisor::FatalError, "unable to make main GLX context current"); + XUnlockDisplay(m_xDisp); + return getDataFactory(); + } + IGraphicsDataFactory* getLoadContextDataFactory() { XLockDisplay(m_xDisp); @@ -1180,6 +1196,11 @@ public: return m_gfxCtx.getDataFactory(); } + IGraphicsDataFactory* getMainContextDataFactory() + { + return m_gfxCtx.getMainContextDataFactory(); + } + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx.getLoadContextDataFactory();