diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6d13305af7..8e311e5487 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2862,6 +2862,13 @@ void Application::initializeGL() { _glWidget->makeCurrent(); _gpuContext = std::make_shared(); + static std::once_flag once; + std::call_once(once, [&] { + _gpuContext->pushProgramsToSync(shader::allPrograms(), [this] { + _programsCompiled.store(true); + }, 1); + }); + DependencyManager::get()->setGPUContext(_gpuContext); } diff --git a/interface/src/Application.h b/interface/src/Application.h index fb1c916c36..c234cd757c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -795,5 +795,7 @@ private: bool _prevShowTrackedObjects { false }; std::shared_ptr _splashScreen { std::make_shared() }; + std::atomic _programsCompiled { false }; + }; #endif // hifi_Application_h diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp index 8d9cdc980a..046cd3b617 100644 --- a/interface/src/Application_render.cpp +++ b/interface/src/Application_render.cpp @@ -115,7 +115,7 @@ void Application::paintGL() { finalFramebuffer = framebufferCache->getFramebuffer(); } - if (!displayPlugin->areAllProgramsLoaded()) { + if (!_programsCompiled.load()) { gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) { batch.setFramebuffer(finalFramebuffer); batch.enableSkybox(true); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 45e0bbc2a6..aafc1a28a5 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -525,6 +525,9 @@ void OpenGLDisplayPlugin::updateFrameData() { if (_newFrameQueue.size() > 1) { _droppedFrameRate.increment(_newFrameQueue.size() - 1); } + + _gpuContext->processProgramsToSync(); + while (!_newFrameQueue.empty()) { _currentFrame = _newFrameQueue.front(); _newFrameQueue.pop(); @@ -633,29 +636,11 @@ void OpenGLDisplayPlugin::internalPresent() { _presentRate.increment(); } -std::atomic OpenGLDisplayPlugin::_allProgramsLoaded { false }; -unsigned int OpenGLDisplayPlugin::_currentLoadingProgramIndex { 0 }; - -bool OpenGLDisplayPlugin::areAllProgramsLoaded() const { - return OpenGLDisplayPlugin::_allProgramsLoaded.load(); -} - void OpenGLDisplayPlugin::present() { auto frameId = (uint64_t)presentCount(); PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId) uint64_t startPresent = usecTimestampNow(); - if (!OpenGLDisplayPlugin::_allProgramsLoaded.load()) { - const auto& programIDs = shader::allPrograms(); - if (OpenGLDisplayPlugin::_currentLoadingProgramIndex < programIDs.size()) { - gpu::doInBatch("createAndSyncProgram", _gpuContext, [&programIDs](gpu::Batch& batch) { - batch.createAndSyncProgram(programIDs.at(OpenGLDisplayPlugin::_currentLoadingProgramIndex++)); - }); - } else { - OpenGLDisplayPlugin::_allProgramsLoaded.store(true); - } - } - { PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId) updateFrameData(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index acb12aa69a..1cc060161b 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -83,8 +83,6 @@ public: void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override; - bool areAllProgramsLoaded() const override; - protected: friend class PresentThread; @@ -182,8 +180,5 @@ protected: // be serialized through this mutex mutable Mutex _presentMutex; float _hudAlpha{ 1.0f }; - - static std::atomic _allProgramsLoaded; - static unsigned int _currentLoadingProgramIndex; }; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 415c5135d9..295b9becb8 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -102,8 +102,6 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_pushProfileRange), (&::gpu::gl::GLBackend::do_popProfileRange), - - (&::gpu::gl::GLBackend::do_createAndSyncProgram), }; #define GL_GET_INTEGER(NAME) glGetIntegerv(GL_##NAME, &const_cast(NAME)); @@ -708,11 +706,6 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) { (void)CHECK_GL_ERROR(); } -void GLBackend::do_createAndSyncProgram(const Batch& batch, size_t paramOffset) { - auto shader = gpu::Shader::createProgram(batch._params[paramOffset + 0]._uint); - gpu::gl::GLShader::sync(*this, *shader); -} - void GLBackend::releaseBuffer(GLuint id, Size size) const { Lock lock(_trashMutex); _currentFrameTrash.buffersTrash.push_back({ id, size }); @@ -866,3 +859,7 @@ void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRend _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); _pipeline._cameraCorrectionBuffer._buffer->flush(); } + +void GLBackend::syncProgram(const gpu::ShaderPointer& program) { + gpu::gl::GLShader::sync(*this, *program); +} \ No newline at end of file diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 0a2c1b92ff..07f7df9277 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -249,6 +249,8 @@ public: // Let's try to avoid to do that as much as possible! void syncCache() final override; + void syncProgram(const gpu::ShaderPointer& program) override; + // This is the ugly "download the pixels to sysmem for taking a snapshot" // Just avoid using it, it's ugly and will break performances virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, @@ -380,8 +382,6 @@ public: virtual void do_setStateBlendFactor(const Batch& batch, size_t paramOffset) final; virtual void do_setStateScissorRect(const Batch& batch, size_t paramOffset) final; - virtual void do_createAndSyncProgram(const Batch& batch, size_t paramOffset) final; - virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0; virtual GLuint getTextureID(const TexturePointer& texture) final; virtual GLuint getBufferID(const Buffer& buffer) = 0; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 43c1c69287..a9b062a285 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -759,10 +759,4 @@ void Batch::flush() { } buffer->flush(); } -} - -void Batch::createAndSyncProgram(unsigned int programID) { - ADD_COMMAND(createAndSyncProgram); - - _params.emplace_back(programID); } \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index aff6cf5ddd..96a45d3111 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -289,8 +289,6 @@ public: void _glColor4f(float red, float green, float blue, float alpha); - void createAndSyncProgram(unsigned int programID); - // Maybe useful but shoudln't be public. Please convince me otherwise // Well porting to gles i need it... void runLambda(std::function f); @@ -370,8 +368,6 @@ public: COMMAND_pushProfileRange, COMMAND_popProfileRange, - COMMAND_createAndSyncProgram, - NUM_COMMANDS, }; typedef std::vector Commands; diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index dd0d510509..be55e5ba87 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -335,6 +335,39 @@ Size Context::getTextureResourceIdealGPUMemSize() { return Backend::textureResourceIdealGPUMemSize.getValue(); } +void Context::pushProgramsToSync(const std::vector& programIDs, std::function callback, size_t rate) { + std::vector programs; + for (auto programID : programIDs) { + programs.push_back(gpu::Shader::createProgram(programID)); + } + pushProgramsToSync(programs, callback, rate); +} + +void Context::pushProgramsToSync(const std::vector& programs, std::function callback, size_t rate) { + Lock lock(_programsToSyncMutex); + _programsToSyncQueue.emplace(programs, callback, rate == 0 ? programs.size() : rate); +} + +void Context::processProgramsToSync() { + Lock lock(_programsToSyncMutex); + if (!_programsToSyncQueue.empty()) { + ProgramsToSync programsToSync = _programsToSyncQueue.front(); + int numSynced = 0; + while (_nextProgramToSyncIndex < programsToSync.programs.size() && numSynced < programsToSync.rate) { + auto nextProgram = programsToSync.programs.at(_nextProgramToSyncIndex); + _backend->syncProgram(nextProgram); + _syncedPrograms.push_back(nextProgram); + _nextProgramToSyncIndex++; + numSynced++; + } + + if (_nextProgramToSyncIndex == programsToSync.programs.size()) { + programsToSync.callback(); + _nextProgramToSyncIndex = 0; + _programsToSyncQueue.pop(); + } + } +} BatchPointer Context::acquireBatch(const char* name) { Batch* rawBatch = nullptr; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 011f980957..3fb90fd2e9 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -61,6 +62,7 @@ public: virtual void render(const Batch& batch) = 0; virtual void syncCache() = 0; + virtual void syncProgram(const gpu::ShaderPointer& program) = 0; virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; @@ -245,6 +247,20 @@ public: static Size getTextureResourcePopulatedGPUMemSize(); static Size getTextureResourceIdealGPUMemSize(); + struct ProgramsToSync { + ProgramsToSync(const std::vector& programs, std::function callback, size_t rate) : + programs(programs), callback(callback), rate(rate) {} + + std::vector programs; + std::function callback; + size_t rate; + }; + + void pushProgramsToSync(const std::vector& programIDs, std::function callback, size_t rate = 0); + void pushProgramsToSync(const std::vector& programs, std::function callback, size_t rate = 0); + + void processProgramsToSync(); + protected: Context(const Context& context); @@ -256,6 +272,11 @@ protected: RangeTimerPointer _frameRangeTimer; StereoState _stereo; + std::mutex _programsToSyncMutex; + std::queue _programsToSyncQueue; + gpu::Shaders _syncedPrograms; + size_t _nextProgramToSyncIndex { 0 }; + // Sampled at the end of every frame, the stats of all the counters mutable ContextStats _frameStats; diff --git a/libraries/gpu/src/gpu/null/NullBackend.h b/libraries/gpu/src/gpu/null/NullBackend.h index e227b631c7..f934bcf619 100644 --- a/libraries/gpu/src/gpu/null/NullBackend.h +++ b/libraries/gpu/src/gpu/null/NullBackend.h @@ -43,6 +43,8 @@ public: // Let's try to avoid to do that as much as possible! void syncCache() final { } + void syncProgram(const gpu::ShaderPointer& program) final {} + // This is the ugly "download the pixels to sysmem for taking a snapshot" // Just avoid using it, it's ugly and will break performances virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final { } diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index e9fbd71689..ad49ceafe6 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -217,8 +217,6 @@ public: static const QString& MENU_PATH(); - virtual bool areAllProgramsLoaded() const { return true; } - signals: void recommendedFramebufferSizeChanged(const QSize& size); void resetSensorsRequested();