diff --git a/interface/resources/shaders/splashSkybox.frag b/interface/resources/shaders/splashSkybox.frag index 38c89b4d26..244dad3356 100644 --- a/interface/resources/shaders/splashSkybox.frag +++ b/interface/resources/shaders/splashSkybox.frag @@ -1,47 +1,32 @@ -const vec3 COLOR = vec3(0x00, 0xD8, 0x02) / vec3(0xFF); -const float CUTOFF = 0.65; -const float NOISE_MULT = 8.0; -const float NOISE_POWER = 1.0; +// Replicate the default skybox texture -float noise4D(vec4 p) { - return fract(sin(dot(p ,vec4(12.9898,78.233,126.7235, 593.2241))) * 43758.5453); -} - -float worley4D(vec4 p) { - float r = 3.0; - vec4 f = floor(p); - vec4 x = fract(p); - for(int i = -1; i<=1; i++) - { - for(int j = -1; j<=1; j++) - { - for(int k = -1; k<=1; k++) - { - for (int l = -1; l <= 1; l++) { - vec4 q = vec4(float(i),float(j),float(k), float(l)); - vec4 v = q + vec4(noise4D((q+f)*1.11), noise4D((q+f)*1.14), noise4D((q+f)*1.17), noise4D((q+f)*1.20)) - x; - float d = dot(v, v); - r = min(r, d); - } - } - } - } - return sqrt(r); -} - - -vec3 mainColor(vec3 direction) { - float n = worley4D(vec4(direction * NOISE_MULT, iGlobalTime / 3.0)); - n = 1.0 - n; - n = pow(n, NOISE_POWER); - if (n < CUTOFF) { - return vec3(0.0); - } - - n = (n - CUTOFF) / (1.0 - CUTOFF); - return COLOR * (1.0 - n); -} +const int NUM_COLORS = 5; +const vec3 WHITISH = vec3(0.471, 0.725, 0.825); +const vec3 GREENISH = vec3(0.157, 0.529, 0.588); +const vec3 COLORS[NUM_COLORS] = vec3[]( + GREENISH, + GREENISH, + WHITISH, + WHITISH, + vec3(0.6, 0.275, 0.706) // purple +); +const float PI = 3.14159265359; +const vec3 BLACK = vec3(0.0); +const vec3 SPACE_BLUE = vec3(0.0, 0.118, 0.392); +const float HORIZONTAL_OFFSET = 3.75; vec3 getSkyboxColor() { - return mainColor(normalize(_normal)); + vec2 horizontal = vec2(_normal.x, _normal.z); + horizontal = normalize(horizontal); + float theta = atan(horizontal.y, horizontal.x); + theta = 0.5 * (theta / PI + 1.0); + float index = theta * NUM_COLORS; + index = mod(index + HORIZONTAL_OFFSET, NUM_COLORS); + int index1 = int(index) % NUM_COLORS; + int index2 = (index1 + 1) % NUM_COLORS; + vec3 horizonColor = mix(COLORS[index1], COLORS[index2], index - index1); + horizonColor = mix(horizonColor, SPACE_BLUE, smoothstep(0.0, 0.08, _normal.y)); + horizonColor = mix(horizonColor, BLACK, smoothstep(0.04, 0.15, _normal.y)); + horizonColor = mix(BLACK, horizonColor, smoothstep(-0.01, 0.0, _normal.y)); + return pow(horizonColor, vec3(0.4545));; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b53e24a8e..fbad66bf55 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -150,7 +150,6 @@ #include #include #include -#include #include #include "recording/ClipCache.h" @@ -2819,8 +2818,6 @@ void Application::initializeGL() { _graphicsEngine.initializeGPU(_glWidget); } -static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" }; - void Application::initializeDisplayPlugins() { auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); Setting::Handle activeDisplayPluginSetting{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME, displayPlugins.at(0)->getName() }; @@ -2856,45 +2853,6 @@ void Application::initializeDisplayPlugins() { // Submit a default frame to render until the engine starts up updateRenderArgs(0.0f); - -#define ENABLE_SPLASH_FRAME 0 -#if ENABLE_SPLASH_FRAME - { - QMutexLocker viewLocker(&_renderArgsMutex); - - if (_appRenderArgs._isStereo) { - _gpuContext->enableStereo(true); - _gpuContext->setStereoProjections(_appRenderArgs._eyeProjections); - _gpuContext->setStereoViews(_appRenderArgs._eyeOffsets); - } - - // Frame resources - auto framebufferCache = DependencyManager::get(); - gpu::FramebufferPointer finalFramebuffer = framebufferCache->getFramebuffer(); - std::shared_ptr procedural = std::make_shared(); - procedural->parse(SPLASH_SKYBOX); - - _gpuContext->beginFrame(_appRenderArgs._view, _appRenderArgs._headPose); - gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) { - batch.resetStages(); - batch.enableStereo(false); - batch.setFramebuffer(finalFramebuffer); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, { 0, 0, 0, 1 }); - batch.enableSkybox(true); - batch.enableStereo(_appRenderArgs._isStereo); - batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() }); - procedural->render(batch, _appRenderArgs._renderArgs.getViewFrustum()); - }); - auto frame = _gpuContext->endFrame(); - frame->frameIndex = 0; - frame->framebuffer = finalFramebuffer; - frame->pose = _appRenderArgs._headPose; - frame->framebufferRecycler = [framebufferCache, procedural](const gpu::FramebufferPointer& framebuffer) { - framebufferCache->releaseFramebuffer(framebuffer); - }; - _displayPlugin->submitFrame(frame); - } -#endif } void Application::initializeRenderEngine() { diff --git a/interface/src/Application.h b/interface/src/Application.h index ead7231ffc..16a11c9a3a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -72,7 +72,6 @@ #include "workload/GameWorkload.h" #include "graphics/GraphicsEngine.h" -#include #include #include @@ -761,5 +760,6 @@ private: bool _showTrackedObjects { false }; bool _prevShowTrackedObjects { false }; + }; #endif // hifi_Application_h diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp deleted file mode 100644 index 5063f6118d..0000000000 --- a/interface/src/Application_render.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -// Application_render.cpp -// interface/src -// -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Application.h" -#include - -#include -#include -#include -#include -#include "ui/Stats.h" -#include "Util.h" - - -//void Application::paintGL() { -// // Some plugins process message events, allowing paintGL to be called reentrantly. -// -// _renderFrameCount++; -// // SG: Moved into the RenderEventHandler -// //_lastTimeRendered.start(); -// -// auto lastPaintBegin = usecTimestampNow(); -// PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount); -// PerformanceTimer perfTimer("paintGL"); -// -// if (nullptr == _displayPlugin) { -// return; -// } -// -// DisplayPluginPointer displayPlugin; -// { -// PROFILE_RANGE(render, "/getActiveDisplayPlugin"); -// displayPlugin = getActiveDisplayPlugin(); -// } -// -// { -// PROFILE_RANGE(render, "/pluginBeginFrameRender"); -// // If a display plugin loses it's underlying support, it -// // needs to be able to signal us to not use it -// if (!displayPlugin->beginFrameRender(_renderFrameCount)) { -// QMetaObject::invokeMethod(this, "updateDisplayMode"); -// return; -// } -// } -// -// RenderArgs renderArgs; -// glm::mat4 HMDSensorPose; -// glm::mat4 eyeToWorld; -// glm::mat4 sensorToWorld; -// -// bool isStereo; -// glm::mat4 stereoEyeOffsets[2]; -// glm::mat4 stereoEyeProjections[2]; -// -// { -// QMutexLocker viewLocker(&_renderArgsMutex); -// renderArgs = _appRenderArgs._renderArgs; -// -// // don't render if there is no context. -// if (!_appRenderArgs._renderArgs._context) { -// return; -// } -// -// HMDSensorPose = _appRenderArgs._headPose; -// eyeToWorld = _appRenderArgs._eyeToWorld; -// sensorToWorld = _appRenderArgs._sensorToWorld; -// isStereo = _appRenderArgs._isStereo; -// for_each_eye([&](Eye eye) { -// stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye]; -// stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye]; -// }); -// } -// -// { -// PROFILE_RANGE(render, "/gpuContextReset"); -// _graphicsEngine.getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose); -// // Reset the gpu::Context Stages -// // Back to the default framebuffer; -// gpu::doInBatch("Application_render::gpuContextReset", _graphicsEngine.getGPUContext(), [&](gpu::Batch& batch) { -// batch.resetStages(); -// }); -// } -// -// -// { -// PROFILE_RANGE(render, "/renderOverlay"); -// PerformanceTimer perfTimer("renderOverlay"); -// // NOTE: There is no batch associated with this renderArgs -// // the ApplicationOverlay class assumes it's viewport is setup to be the device size -// renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize() * getRenderResolutionScale()); -// _applicationOverlay.renderOverlay(&renderArgs); -// } -// -// { -// PROFILE_RANGE(render, "/updateCompositor"); -// getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld); -// } -// -// gpu::FramebufferPointer finalFramebuffer; -// QSize finalFramebufferSize; -// { -// PROFILE_RANGE(render, "/getOutputFramebuffer"); -// // Primary rendering pass -// auto framebufferCache = DependencyManager::get(); -// finalFramebufferSize = framebufferCache->getFrameBufferSize(); -// // Final framebuffer that will be handled to the display-plugin -// finalFramebuffer = framebufferCache->getFramebuffer(); -// } -// -// { -// if (isStereo) { -// renderArgs._context->enableStereo(true); -// renderArgs._context->setStereoProjections(stereoEyeProjections); -// renderArgs._context->setStereoViews(stereoEyeOffsets); -// } -// -// renderArgs._hudOperator = displayPlugin->getHUDOperator(); -// renderArgs._hudTexture = _applicationOverlay.getOverlayTexture(); -// renderArgs._blitFramebuffer = finalFramebuffer; -// _graphicsEngine.render_runRenderFrame(&renderArgs); -// } -// -// auto frame = _graphicsEngine.getGPUContext()->endFrame(); -// frame->frameIndex = _renderFrameCount; -// frame->framebuffer = finalFramebuffer; -// frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) { -// auto frameBufferCache = DependencyManager::get(); -// if (frameBufferCache) { -// frameBufferCache->releaseFramebuffer(framebuffer); -// } -// }; -// // deliver final scene rendering commands to the display plugin -// { -// PROFILE_RANGE(render, "/pluginOutput"); -// PerformanceTimer perfTimer("pluginOutput"); -// _renderLoopCounter.increment(); -// displayPlugin->submitFrame(frame); -// } -// -// // Reset the framebuffer and stereo state -// renderArgs._blitFramebuffer.reset(); -// renderArgs._context->enableStereo(false); -// -// { -// Stats::getInstance()->setRenderDetails(renderArgs._details); -// } -// -// uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin; -// _frameTimingsScriptingInterface.addValue(lastPaintDuration); -//} - - -// WorldBox Render Data & rendering functions -// -//class WorldBoxRenderData { -//public: -// typedef render::Payload Payload; -// typedef Payload::DataPointer Pointer; -// -// int _val = 0; -// static render::ItemID _item; // unique WorldBoxRenderData -//}; -// -//render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID }; -// -//namespace render { -// template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); } -// template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); } -// template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) { -// if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) { -// PerformanceTimer perfTimer("worldBox"); -// -// auto& batch = *args->_batch; -// DependencyManager::get()->bindSimpleProgram(batch); -// renderWorldBox(args, batch); -// } -// } -//} -// -//void Application::runRenderFrame(RenderArgs* renderArgs) { -// PROFILE_RANGE(render, __FUNCTION__); -// PerformanceTimer perfTimer("display"); -// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()"); -// -// // The pending changes collecting the changes here -// render::Transaction transaction; -// -// if (DependencyManager::get()->shouldRenderEntities()) { -// // render models... -// PerformanceTimer perfTimer("entities"); -// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), -// "Application::runRenderFrame() ... entities..."); -// -// RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; -// -// renderArgs->_debugFlags = renderDebugFlags; -// } -// -// // Make sure the WorldBox is in the scene -// // For the record, this one RenderItem is the first one we created and added to the scene. -// // We could move that code elsewhere but you know... -// if (!render::Item::isValidID(WorldBoxRenderData::_item)) { -// auto worldBoxRenderData = std::make_shared(); -// auto worldBoxRenderPayload = std::make_shared(worldBoxRenderData); -// -// WorldBoxRenderData::_item = _main3DScene->allocateID(); -// -// transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload); -// _main3DScene->enqueueTransaction(transaction); -// } -// -// { -// PerformanceTimer perfTimer("EngineRun"); -// _renderEngine->getRenderContext()->args = renderArgs; -// _renderEngine->run(); -// } -//} - diff --git a/interface/src/graphics/GraphicsEngine.cpp b/interface/src/graphics/GraphicsEngine.cpp index aecaa74d12..36bf3a1b97 100644 --- a/interface/src/graphics/GraphicsEngine.cpp +++ b/interface/src/graphics/GraphicsEngine.cpp @@ -34,6 +34,8 @@ #include "Application.h" GraphicsEngine::GraphicsEngine() { + const QString SPLASH_SKYBOX { "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" }; + _splashScreen->parse(SPLASH_SKYBOX); } GraphicsEngine::~GraphicsEngine() { @@ -54,6 +56,10 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) { glwidget->makeCurrent(); _gpuContext = std::make_shared(); + _gpuContext->pushProgramsToSync(shader::allPrograms(), [this] { + _programsCompiled.store(true); + }, 1); + DependencyManager::get()->setGPUContext(_gpuContext); } @@ -122,11 +128,7 @@ void GraphicsEngine::render_runRenderFrame(RenderArgs* renderArgs) { static const unsigned int THROTTLED_SIM_FRAMERATE = 15; static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE; - - - bool GraphicsEngine::shouldPaint() const { - auto displayPlugin = qApp->getActiveDisplayPlugin(); #ifdef DEBUG_PAINT_DELAY @@ -145,7 +147,7 @@ bool GraphicsEngine::shouldPaint() const { // Throttle if requested //if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { - if ( displayPlugin->isThrottled() && + if (displayPlugin->isThrottled() && (static_cast(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { return false; } @@ -158,8 +160,6 @@ bool GraphicsEngine::checkPendingRenderEvent() { return (_renderEventHandler && static_cast(_renderEventHandler)->_pendingRenderEvent.compare_exchange_strong(expected, true)); } - - void GraphicsEngine::render_performFrame() { // Some plugins process message events, allowing paintGL to be called reentrantly. @@ -189,6 +189,7 @@ void GraphicsEngine::render_performFrame() { glm::mat4 HMDSensorPose; glm::mat4 eyeToWorld; glm::mat4 sensorToWorld; + ViewFrustum viewFrustum; bool isStereo; glm::mat4 stereoEyeOffsets[2]; @@ -211,6 +212,7 @@ void GraphicsEngine::render_performFrame() { stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye]; stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye]; }); + viewFrustum = _appRenderArgs._renderArgs.getViewFrustum(); } { @@ -221,21 +223,12 @@ void GraphicsEngine::render_performFrame() { gpu::doInBatch("Application_render::gpuContextReset", getGPUContext(), [&](gpu::Batch& batch) { batch.resetStages(); }); - } - - { - PROFILE_RANGE(render, "/renderOverlay"); - PerformanceTimer perfTimer("renderOverlay"); - // NOTE: There is no batch associated with this renderArgs - // the ApplicationOverlay class assumes it's viewport is setup to be the device size - renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize()); - qApp->getApplicationOverlay().renderOverlay(&renderArgs); - } - - { - PROFILE_RANGE(render, "/updateCompositor"); - qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld); + if (isStereo) { + renderArgs._context->enableStereo(true); + renderArgs._context->setStereoProjections(stereoEyeProjections); + renderArgs._context->setStereoViews(stereoEyeOffsets); + } } gpu::FramebufferPointer finalFramebuffer; @@ -245,21 +238,40 @@ void GraphicsEngine::render_performFrame() { // Primary rendering pass auto framebufferCache = DependencyManager::get(); finalFramebufferSize = framebufferCache->getFrameBufferSize(); - // Final framebuffer that will be handled to the display-plugin + // Final framebuffer that will be handed to the display-plugin finalFramebuffer = framebufferCache->getFramebuffer(); } - { - if (isStereo) { - renderArgs._context->enableStereo(true); - renderArgs._context->setStereoProjections(stereoEyeProjections); - renderArgs._context->setStereoViews(stereoEyeOffsets); + if (!_programsCompiled.load()) { + gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) { + batch.setFramebuffer(finalFramebuffer); + batch.enableSkybox(true); + batch.enableStereo(isStereo); + batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() }); + _splashScreen->render(batch, viewFrustum); + }); + } else { + { + PROFILE_RANGE(render, "/renderOverlay"); + PerformanceTimer perfTimer("renderOverlay"); + // NOTE: There is no batch associated with this renderArgs + // the ApplicationOverlay class assumes it's viewport is setup to be the device size + renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize()); + qApp->getApplicationOverlay().renderOverlay(&renderArgs); } - renderArgs._hudOperator = displayPlugin->getHUDOperator(); - renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture(); - renderArgs._blitFramebuffer = finalFramebuffer; - render_runRenderFrame(&renderArgs); + { + PROFILE_RANGE(render, "/updateCompositor"); + qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld); + } + + { + PROFILE_RANGE(render, "/runRenderFrame"); + renderArgs._hudOperator = displayPlugin->getHUDOperator(); + renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture(); + renderArgs._blitFramebuffer = finalFramebuffer; + render_runRenderFrame(&renderArgs); + } } auto frame = getGPUContext()->endFrame(); @@ -283,18 +295,19 @@ void GraphicsEngine::render_performFrame() { renderArgs._blitFramebuffer.reset(); renderArgs._context->enableStereo(false); +#if !defined(DISABLE_QML) { auto stats = Stats::getInstance(); if (stats) { stats->setRenderDetails(renderArgs._details); } } +#endif uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin; _frameTimingsScriptingInterface.addValue(lastPaintDuration); } - void GraphicsEngine::editRenderArgs(RenderArgsEditor editor) { QMutexLocker renderLocker(&_renderArgsMutex); editor(_appRenderArgs); diff --git a/interface/src/graphics/GraphicsEngine.h b/interface/src/graphics/GraphicsEngine.h index 490f5312b5..83e774a64f 100644 --- a/interface/src/graphics/GraphicsEngine.h +++ b/interface/src/graphics/GraphicsEngine.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -84,6 +85,9 @@ protected: FrameTimingsScriptingInterface _frameTimingsScriptingInterface; + std::shared_ptr _splashScreen { std::make_shared() }; + std::atomic _programsCompiled { false }; + friend class Application; }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 2d19a745e1..5835316efe 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(); @@ -645,6 +648,7 @@ void OpenGLDisplayPlugin::present() { auto frameId = (uint64_t)presentCount(); PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId) uint64_t startPresent = usecTimestampNow(); + { PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId) updateFrameData(); @@ -837,7 +841,6 @@ void OpenGLDisplayPlugin::render(std::function f) { _gpuContext->executeBatch(batch); } - OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index c1ce05c18b..295b9becb8 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -859,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 37dde5b08e..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, diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLShader.cpp index 44d2bd6ca0..cf123a3f66 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLShader.cpp @@ -37,6 +37,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader: if (object) { return object; } + PROFILE_RANGE(render, "/GLShader::sync"); // need to have a gpu object? if (shader.isProgram()) { GLShader* tempObject = backend.compileBackendProgram(shader, handler); diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 96b06ea6b0..cd7c7c881e 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -760,4 +760,4 @@ void Batch::flush() { } buffer->flush(); } -} +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 711059315e..610c3d1308 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -51,6 +51,7 @@ Context::~Context() { delete batch; } _batchPool.clear(); + _syncedPrograms.clear(); } void Context::shutdown() { @@ -346,6 +347,40 @@ 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() { + if (!_programsToSyncQueue.empty()) { + Lock lock(_programsToSyncMutex); + ProgramsToSync programsToSync = _programsToSyncQueue.front(); + size_t 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 654a34fe91..0626ecd8f3 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; @@ -247,6 +249,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); @@ -258,6 +274,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 { }